分类: 网络与安全
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__ |