分类: 网络与安全
2013-09-23 18:51:12
1 |
#!/usr/bin/perl -w |
2 |
|
3 | # Nagios plugin to check remote disk partitions via SNMP |
4 | # Author: Ulmer |
5 | # Created on: 2013-09-18 |
6 |
|
7 | use strict; |
8 | use Getopt::Std; |
9 | #use Net::SNMP qw(:snmp); |
10 | use Net::SNMP qw(oid_lex_sort oid_base_match snmp_type_ntop); |
11 |
|
12 | # Set snmp |
13 | use constant SNMP_VERSION => 2; |
14 | use constant SNMP_COMMUNITY => 'public'; |
15 | use constant OID_HR_STORAGE_TABLE => '1.3.6.1.2.1.25.2.3'; |
16 |
|
17 | # Nagios Exit Code |
18 | use constant EXIT_OK => 0; |
19 | use constant EXIT_WARNING => 1; |
20 | use constant EXIT_CRITICAL => 2; |
21 | use constant EXIT_UNKNOWN => 3; |
22 |
|
23 | # Nagios default critical and warning values |
24 | use constant DISK_CRITICAL => 95; |
25 | use constant DISK_WARNING => 85; |
26 |
|
27 | # Set key name |
28 | use constant KEY_TYPE => 'type'; |
29 | use constant KEY_DATA => 'data'; |
30 | use constant KEY_MOUNT => 'mount'; |
31 | use constant KEY_SIZE => 'size'; |
32 | use constant KEY_USED => 'used'; |
33 | use constant KEY_AVAIL => 'avail'; |
34 | use constant KEY_USESPACE => 'usespace'; |
35 |
|
36 | # Set command line input options |
37 |
# -H |
38 | # -c [Critical used space in percetage] Sets $opt_c as a side effect. |
39 | # -w [Warning used space in percetage] Sets $opt_w as a side effect. |
40 | # -d [Debugging mode] Sets $opt_d as a side effect. |
41 | getopt('Hwcd'); |
42 | our($opt_H, $opt_w, $opt_c, $opt_d); |
43 |
|
44 |
|
45 | ###################################################################### |
46 | # Subroutines # |
47 | ###################################################################### |
48 |
|
49 | sub snmp_walk { |
50 | my ($session, $walk_oid) = @_; |
51 | my @args = (-maxrepetitions => 25, -varbindlist => [$walk_oid]); |
52 |
# HoH data structure { |
53 | my $records = {}; |
54 |
|
55 | LINE: while (defined($session->get_bulk_request(@args))) { |
56 | my @oids = oid_lex_sort( keys %{$session->var_bind_list()} ); |
57 | foreach my $oid (@oids) { |
58 | if (!oid_base_match($walk_oid, $oid)) { |
59 | last LINE; |
60 | } |
61 | my $type = snmp_type_ntop($session->var_bind_types()->{$oid}); |
62 | my $data = $session->var_bind_list()->{$oid}; |
63 |
|
64 | # Store walk records |
65 | $records->{$oid}->{KEY_TYPE} = $type; |
66 | $records->{$oid}->{KEY_DATA} = $data; |
67 |
|
68 | # Make sure we have not hit the end of the MIB |
69 | if ($session->var_bind_list()->{$oid} eq 'endOfMibView') { |
70 |
last LINE; |
71 | } |
72 | } |
73 | # Get the last OBJECT IDENTIFIER in the returned list |
74 | @args = (-maxrepetitions => 25, -varbindlist => [pop(@oids)]); |
75 | } |
76 | return $records; |
77 | } |
78 |
|
79 | sub get_storage_partitions { |
80 | my ($snmp_walk_records) = @_; |
81 | my $partitions = {}; |
82 | foreach my $oid (sort keys %$snmp_walk_records) { |
83 | my $type = $snmp_walk_records->{$oid}->{KEY_TYPE}; |
84 | my $data = $snmp_walk_records->{$oid}->{KEY_DATA}; |
85 | if ($type eq 'OCTET STRING' and $data =~ /^\//) { |
86 | # We'v got partition path |
87 | my @oid_items = split /\./, $oid; |
88 | # Fetching partition's block (1024 or 4096, ...) |
89 | # the OID for disk block is oid_items[-2] = 4; |
90 | $oid_items[-2] = 4; |
91 | my $oid_disk_block = join '.', @oid_items; |
92 | my $block_multiple_factor = 1; |
93 | if (exists($snmp_walk_records->{$oid_disk_block})) { |
94 | my $block_data = $snmp_walk_records->{$oid_disk_block}->{KEY_DATA}; |
95 | if ($block_data >= 1024) { |
96 | $block_multiple_factor = $block_data / 1024; |
97 | } |
98 | } |
99 | # Fechting total size : oid_items[-2] = 5 |
100 | $oid_items[-2] = 5; |
101 | my $oid_disk_size = join '.', @oid_items; |
102 | my $size = -1; |
103 | if (exists($snmp_walk_records->{$oid_disk_size})) { |
104 | my $size_data = $snmp_walk_records->{$oid_disk_size}->{KEY_DATA}; |
105 | $size = $size_data * $block_multiple_factor; |
106 | } |
107 | # Fechting disk used : oid_items[-2] = 6 |
108 | $oid_items[-2] = 6; |
109 | my $oid_disk_used = join '.', @oid_items; |
110 | my $used = -1; |
111 | if (exists($snmp_walk_records->{$oid_disk_used})) { |
112 | my $used_data = $snmp_walk_records->{$oid_disk_used}->{KEY_DATA}; |
113 | $used = $used_data * $block_multiple_factor; |
114 | } |
115 | my $avail = $size - $used; |
116 | my $use_space = -1; |
117 | if ($size > 0 && $used > 0) { |
118 | $use_space = sprintf("%d", ($used / $size) * 100); |
119 | } |
120 | # Generate partitions records |
121 | if ($size > 0 ) { |
122 | $partitions->{$oid}->{KEY_MOUNT} = $data; |
123 | $partitions->{$oid}->{KEY_SIZE} = $size; |
124 | $partitions->{$oid}->{KEY_USED} = $used; |
125 | $partitions->{$oid}->{KEY_AVAIL} = $avail; |
126 | $partitions->{$oid}->{KEY_USESPACE} = $use_space; |
127 | } |
128 | } |
129 | } |
130 | return $partitions; |
131 | } |
132 |
|
133 | sub display_disk_partition { |
134 | my ($partitions) = @_; |
135 |
|
136 | foreach my $oid (sort keys %$partitions) { |
137 | my $mnt = $partitions->{$oid}->{KEY_MOUNT}; |
138 | my $size = $partitions->{$oid}->{KEY_SIZE}; |
139 | my $used = $partitions->{$oid}->{KEY_USED}; |
140 | my $avail = $partitions->{$oid}->{KEY_AVAIL}; |
141 | my $usespace = $partitions->{$oid}->{KEY_USESPACE}; |
142 |
|
143 | my $format = "%.2f"; |
144 | my $out = '['. $mnt. ']: size='; |
145 | if ($size > (1024*1024)) { |
146 | $out .= sprintf($format, $size/(1024*1024)).'G'; |
147 | } elsif ($size > 1024) { |
148 | $out .= sprintf($format, $size/1024).'M'; |
149 | } else { |
150 | $out .= $size.'K'; |
151 | } |
152 | $out .= ', used='; |
153 | if ($used > (1024*1024)) { |
154 | $out .= sprintf($format, $used/(1024*1024)).'G'; |
155 | } elsif ($used > 1024) { |
156 | $out .= sprintf($format, $used/1024). 'M'; |
157 | } else { |
158 | $out .= $used.'K'; |
159 | } |
160 | $out .= ', avail='; |
161 | if ($avail > (1024*1024)) { |
162 | $out .= sprintf($format, $avail/(1024*1024)).'G'; |
163 | } elsif ($avail > 1024) { |
164 | $out .= sprintf($format, $avail/1024).'M'; |
165 | } else { |
166 | $out .= $avail.'K'; |
167 | } |
168 | $out .= ', use%='.$usespace.'%'; |
169 | print "$out\n"; |
170 | } |
171 | } |
172 |
|
173 | sub check_used_space { |
174 | my ($storage_partitions, $max_allowed_space) = @_; |
175 |
|
176 | my @failures = (); |
177 | foreach my $oid (sort keys %$storage_partitions) { |
178 | my $mnt = $storage_partitions->{$oid}->{KEY_MOUNT}; |
179 | my $usespace = $storage_partitions->{$oid}->{KEY_USESPACE}; |
180 | if ($usespace >= $max_allowed_space) { |
181 | push @failures, '['. $mnt. ']: use%='. $usespace. ' >= max. allowed!'; |
182 | } |
183 | } |
184 | return @failures; |
185 | } |
186 |
|
187 | sub dump_snmpwalk { |
188 | my ($snmpwalk_records) = @_; |
189 | foreach my $oid (sort keys %$snmpwalk_records) { |
190 | print $oid. ' = '. $snmpwalk_records->{$oid}->{KEY_TYPE} . ': '. |
191 | $snmpwalk_records->{$oid}->{KEY_DATA} . "\n"; |
192 | } |
193 | } |
194 |
|
195 | sub usage { |
196 | print "Usage: $0 ARGUMENTS\n"; |
197 | print " Nagios Plugin for check remote disk via SNMP\n"; |
198 | print " Support SNMP Version: '2c', Community: 'public'\n"; |
199 | print " Required Arguments:\n"; |
200 |
print " -H |
201 | print " Optional:\n"; |
202 | print " -w [maximum used space] : ". |
203 | "Warning for used space, default is ". DISK_WARNING. "%\n"; |
204 | print " -c [maximum used space] : ". |
205 | "Crtitical for used space, default is ". DISK_CRITICAL. "%\n"; |
206 | print " -d [y|yes]: Debugging mode\n"; |
207 | } |
208 |
|
209 |
|
210 | ###################################################################### |
211 | # Main Program # |
212 | ###################################################################### |
213 | my $exit_code = EXIT_UNKNOWN; |
214 | my @stdout = ("Check Hard Disk Partitions..."); |
215 |
|
216 | if ($opt_H) { |
217 | my $host = $opt_H; |
218 | my ($session, $error) = Net::SNMP->session( |
219 | -hostname => $host, |
220 | -community => SNMP_COMMUNITY, |
221 | -port => 161, |
222 | -version => SNMP_VERSION, |
223 | ); |
224 | if (!defined($session)) { |
225 | printf("Session error: %s.\n", $error); |
226 | $session->close; |
227 | exit EXIT_UNKNOWN; |
228 | } |
229 | # check remote system response firstly |
230 | my $oidSysDescr = '1.3.6.1.2.1.1.1.0'; |
231 | my $result = $session->get_request(-varbindlist=>[$oidSysDescr]); |
232 | if (!defined($result)) { |
233 | printf("Result error: %s.\n", $session->error); |
234 | $session->close; |
235 | exit EXIT_UNKNOWN; |
236 | } |
237 |
|
238 | # Start snmpwalk to collect oids responses |
239 | my $snmpwalk_records = snmp_walk($session, OID_HR_STORAGE_TABLE); |
240 | my $disk_partitions = get_storage_partitions($snmpwalk_records); |
241 | $session->close; |
242 |
|
243 | # Check used space |
244 | my $warning_space = DISK_WARNING; |
245 | my $critical_space = DISK_CRITICAL; |
246 | if ($opt_w and $opt_w =~ /^\d{1,2}$/) { |
247 | $warning_space = $opt_w; |
248 | } |
249 | if ($opt_c and $opt_c =~ /^\d{1,2}$/) { |
250 | $critical_space = $opt_c; |
251 | } |
252 | my @warning = check_used_space($disk_partitions, $warning_space); |
253 | my @critical = check_used_space($disk_partitions, $critical_space); |
254 | if (@warning > 0 ) { |
255 | foreach my $msg (@warning) { |
256 | push @stdout, 'WARNING: '. $msg; |
257 | } |
258 | $exit_code = EXIT_WARNING; |
259 | } elsif (@critical > 0 ) { |
260 | foreach my $msg (@critical) { |
261 | push @stdout, 'CRITICAL: '. $msg; |
262 | } |
263 | $exit_code = EXIT_CRITICAL; |
264 | } else { |
265 | $exit_code = EXIT_OK; |
266 | push @stdout, 'RESULT: OK'; |
267 | foreach my $oid (sort keys %$disk_partitions) { |
268 | my $mnt = $disk_partitions->{$oid}->{KEY_MOUNT}; |
269 | my $usespace = $disk_partitions->{$oid}->{KEY_USESPACE}; |
270 | push @stdout, "[$mnt]: use%=$usespace;"; |
271 | } |
272 | } |
273 | if ($opt_d && $opt_d =~ /^y|yes$/i) { |
274 | # dump |
275 | display_disk_partition($disk_partitions); |
276 | print "Dump snmpwalk: hrStorageTable: ". OID_HR_STORAGE_TABLE. " ...\n"; |
277 | dump_snmpwalk($snmpwalk_records); |
278 | } else { |
279 | print join("\n", @stdout); |
280 | } |
281 | print "\n"; |
282 | exit $exit_code; |
283 | } else { |
284 | usage(); |
285 | exit EXIT_UNKNOWN; |
286 | } |
287 |
|
288 | __END__ |