root/lib/Core/ZpoolFree.pm

Revision f5eecec577d75ab8e558d7c5a3b34ab6053c8c92, 4.5 kB (checked in by Mark Harrison <mark@mivok.net>, 1 year ago)

Allow non-wildcard use of Core::ZpoolFree?

  • Property mode set to 100644
Line 
1 package Core::ZpoolFree;
2
3 use strict;
4 use warnings;
5
6 use base 'Resmon::Module';
7
8 use Resmon::ExtComm qw(run_command);
9
10 =pod
11
12 =head1 NAME
13
14 Core::ZpoolFree - monitor free space available on ZFS pools
15
16 =head1 SYNOPSIS
17
18  Core::ZpoolFree {
19      * : noop
20  }
21
22  Core::ZpoolFree {
23      poolname : noop
24  }
25
26  Core::ZpoolFree {
27      * : zfs_path => '/sbin/zfs'
28  }
29
30 =head1 DESCRIPTION
31
32 This module monitors the free space on ZFS pools. Free space is reported for
33 all pools on the system. Multiple checks are not required for individual
34 pools.
35
36 Implementation Note: The 'zfs list' command is used rather than 'zpool list'
37 in order to get a more accurate view of the available space in certain cases
38 where zpool list does not report the true usable free space (e.g. raidz
39 pools). See http://www.cuddletech.com/blog/pivot/entry.php?id=1013 for another
40 case where zpool list does not report the correct values for monitoring.
41
42 Zpool list is still used to get the list of pools on the system, and then zfs
43 list is run individually for each pool. This is done to improve performance in
44 the case where there are many filesystems.
45
46 =head1 CONFIGURATION
47
48 =over
49
50 =item check_name
51
52 The check name is descriptive only in this check. It is not used for anything.
53
54 =item zfs_path
55
56 Specify an alternative location for the zfs command. Default: /sbin/zfs.
57
58 =item zpool_path
59
60 Specify an alternative location for the zpool command. Default: /sbin/zpool.
61
62 =back
63
64 =head1 METRICS
65
66 A set of metrics is returned for each pool on the system.
67
68 =over
69
70 =item free_MB
71
72 The amount of free space in the pool, measured in megabytes.
73
74 =item used_MB
75
76 The amount of used space in the pool, measured in megabytes.
77
78 =item percent_full
79
80 The amount of used space in the pool, expressed as a percentage of the total
81 space.
82
83 =back
84
85 =cut
86
87 our %units = (
88     'B' => 1,
89     'K' => 1024,
90     'M' => 1048576,
91     'G' => 1073741824,
92     'T' => 1099511627776,
93     'P' => 1125899906842624,
94     'E' => 1152921504606846976,
95     'Z' => 1180591620717411303424
96 );
97
98 sub handler {
99     my $self = shift;
100     my $config = $self->{config}; # All configuration is in here
101     my $pool = $self->{check_name};
102     my $zfs_command = $config->{zfs_command} || "/sbin/zfs";
103     my $zpool_command = $config->{zpool_command} || "/sbin/zpool";
104     my $status = {};
105     # Sanity check
106     die "Invalid pool name: $pool" if $pool !~ /[a-zA-Z0-9_.-]+/;
107     my $zfs_output = run_command(
108         "$zfs_command list -H -o name,used,avail $pool");
109     my ($name, $used, $uunit, $free, $funit) = $zfs_output =~
110         /(\S+)\s+([0-9.]+)([BKMGTPEZ]?)\s+([0-9.]+)([BKMGTPEZ]?)/;
111     # Make sure we were able to match the regex
112     die "Unable to parse zfs command output: $zfs_output\n"
113         unless defined($name);
114     next if ($name =~ /\//); # We're only interested in the root of a pool
115
116     # Convert human readable units to bytes
117     $used = $used * $units{$uunit} if $uunit;
118     $free = $free * $units{$funit} if $funit;
119
120     my $percent_full = sprintf("%.2f", ($used / ($used + $free)) * 100);
121     $status->{"used_MB"} = [int($used/1048576), "i"];
122     $status->{"free_MB"} = [int($free/1048576), "i"];
123     $status->{"percent_full"} = [$percent_full, "n"];
124
125     return $status;
126 };
127
128 sub wildcard_handler {
129     my $self = shift;
130     my $config = $self->{config}; # All configuration is in here
131     my $zfs_command = $config->{zfs_command} || "/sbin/zfs";
132     my $zpool_command = $config->{zpool_command} || "/sbin/zpool";
133     my $status = {};
134     my $output = run_command("$zpool_command list -H -o name");
135     foreach my $pool (split /\n/, $output) {
136         # Sanity check in case zpool outputs something strange
137         die "Invalid pool name: $pool" if $pool !~ /[a-zA-Z0-9_.-]+/;
138         my $zfs_output = run_command(
139             "$zfs_command list -H -o name,used,avail $pool");
140         my ($name, $used, $uunit, $free, $funit) = $zfs_output =~
141             /(\S+)\s+([0-9.]+)([BKMGTPEZ]?)\s+([0-9.]+)([BKMGTPEZ]?)/;
142         # Make sure we were able to match the regex
143         die "Unable to parse zfs command output: $zfs_output\n"
144             unless defined($name);
145         next if ($name =~ /\//); # We're only interested in the root of a pool
146
147         # Convert human readable units to bytes
148         $used = $used * $units{$uunit} if $uunit;
149         $free = $free * $units{$funit} if $funit;
150
151         my $percent_full = sprintf("%.2f", ($used / ($used + $free)) * 100);
152         $status->{$name}->{"used_MB"} = [int($used/1048576), "i"];
153         $status->{$name}->{"free_MB"} = [int($free/1048576), "i"];
154         $status->{$name}->{"percent_full"} = [$percent_full, "n"];
155     }
156
157     return $status;
158 };
159
160 1;
Note: See TracBrowser for help on using the browser.