#!/usr/bin/perl -w
#######################################################################
#
# Copyright (c) 2011 Mike bofh@norgie.net
#
# License Information:
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Home Site: http://www.norgie.net/tools/check_snmp_disks/
# #####################################################################
use strict;
use Getopt::Long qw(:config no_ignore_case);
use lib "/usr/lib/nagios/plugins/";
use Net::SNMP;
use Time::HiRes qw(gettimeofday ualarm);
use utils qw(%ERRORS);
my $PROGNAME = "check_snmp_disks.pl";
my $VERSION = '$Revision: 1.1 $';
my $config = "/etc/check_snmp_disks.conf";
my $oid_disk = "1.3.6.1.4.1.2021.9.1.2";
my $oid_avail = "1.3.6.1.4.1.2021.9.1.7";
my $oid_used = "1.3.6.1.4.1.2021.9.1.8";
my $oid_percent = "1.3.6.1.4.1.2021.9.1.9";
my $measure_default = "p";
my $warn_default = 80;
my $critical_default = 90;
my $opt_c = '';
my $opt_C = '';
my $opt_h = '';
my $opt_H = '';
my $opt_p = '';
my $opt_t = '';
my $opt_v = 0;
my $opt_V = '';
my $glob_measure = '';
my $glob_warn = '';
my $glob_critical = '';
my $host_measure = '';
my $host_warn = '';
my $host_critical = '';
my %limits;
my %excludes;
local $SIG{ALRM} = sub {
print "UNKNOWN: Timeout while connecting to snmp daemon\n";
exit $ERRORS{"UNKNOWN"};
};
GetOptions
("C=s" => \$opt_C, "community=s" => \$opt_C,
"h" => \$opt_h, "help" => \$opt_h,
"H=s" => \$opt_H, "host=s" => \$opt_H,
"p=i" => \$opt_p, "port=i" => \$opt_p,
"t=i" => \$opt_t, "timeout=i" => \$opt_t,
"v+" => \$opt_v, "verbose" => \$opt_v
) or exit $ERRORS{'UNKNOWN'};
if ($opt_H eq "" || $opt_C eq "") {
&print_short_help();
}
if ($opt_t eq '') {
$opt_t = 10;
}
$opt_t = $opt_t * 1000000;
if ($opt_h eq "1") {
&print_long_help();
}
if ($opt_p eq "") {
$opt_p = 161;
}
if ($opt_v eq "") {
$opt_v = 0;
}
# Let us start by reading in the config file
debug($opt_v, 3, "Parsing config file");
open(FD, "<$config") || die("Cannot open config file");
while() {
chomp;
my @line = split(/:/, $_);
if ($line[0] eq "i" && $line[1] eq "global") {
$glob_measure = $line[3];
$glob_warn = $line[4];
$glob_critical = $line[5];
debug($opt_v, 3, "Read global threasholds: Meausre: $glob_measure Warn: $glob_warn Critical: $glob_critical");
} elsif ($line[0] eq "i" && $line[2] eq "global" && $line[1] eq $opt_H) {
$host_measure = $line[3];
$host_warn = $line[4];
$host_critical = $line[5];
debug($opt_v, 3, "Read host threasholds: Meausre: $host_measure Warn: $host_warn Critical: $host_critical");
} elsif ($line[0] eq "e" && $line[1] eq $opt_H) {
$excludes{$line[2]} = 1;
debug($opt_v, 3, "Read exlucde for $line[2]");
} elsif ($line[0] eq "e" && $line[1] eq "global") {
$excludes{$line[2]} = 1;
debug($opt_v, 3, "Read global exlucde for $line[2]");
} elsif ($line[0] eq "i" && $line[1] eq $opt_H) {
$limits{$line[2]}->[0] = $line[3];
$limits{$line[2]}->[1] = $line[4];
$limits{$line[2]}->[2] = $line[5];
debug($opt_v, 3, "Read limits fo $line[2]: Meausre: $line[3] Warn: $line[4] Critical: $line[5]");
}
}
close(FD);
debug($opt_v, 3, "Finished reading config file");
alarm($opt_t);
debug($opt_v, 3, "Connecting to SNMP server");
my ($session, $error) = Net::SNMP->session(
-hostname => $opt_H,
-port => $opt_p,
-community => $opt_C,
-version => 'snmpv2c',
-maxmsgsize=> 65535,
);
if (!defined $session) {
debug($opt_v, 3, "Failed to connect to SNMP server: $error");
print "UNKNOWN: Could not connect to SNMP server\n";
exit $ERRORS{"UNKNOWN"};
}
my $snmp_value = '';
my @disks;
my $count = 1;
# Walk the system's SNMP MIB collecting stats for each partition
until($snmp_value eq "noSuchInstance") {
my $query_disk = $oid_disk . "." . $count;
my $query_avail = $oid_avail . "." . $count;
my $query_used = $oid_used . "." . $count;
my $query_percent = $oid_percent . "." . $count;
my $result = $session->get_request(-varbindlist => [ $query_disk, $query_avail, $query_used, $query_percent ],);
if (!defined $result) {
print "UNKNOWN: Unable to query SNMP server\n";
debug($opt_v, 3, "SNMP query failed: $session->error()");
$session->close();
exit $ERRORS{"UNKNOWN"};
}
$snmp_value = $result->{$query_disk};
unless($snmp_value eq "noSuchInstance") {
$disks[$count - 1]->[0] = $result->{$query_disk};
$disks[$count - 1]->[1] = $result->{$query_avail};
$disks[$count - 1]->[2] = $result->{$query_used};
$disks[$count - 1]->[3] = $result->{$query_percent};
debug($opt_v, 3, "Read from SNMP server: Disk: $result->{$query_disk} Available: $result->{$query_avail} Used: $result->{$query_used} Percent: $result->{$query_percent}");
}
$count++;
}
$session->close();
debug($opt_v, 3, "Disconnected from SNMP server");
ualarm(0);
my $dok = 0;
my $dwarn = 0;
my $dcritical = 0;
my (@critical_disks, @warn_disks);
# Compare each of the partitons read from SNMP against parameters defined in the config file or failling back to defaults
my $perfmon = "";
foreach(@disks) {
my $disk = $_->[0];
my $avail = $_->[1];
my $used = $_->[2];
my $percent = $_->[3];
my $total = $avail + $used;
my ($measure, $warn, $critical);
unless(defined $excludes{$disk}) {
if (defined $limits{$disk}) {
$measure = $limits{$disk}->[0];
$warn = $limits{$disk}->[1];
$critical = $limits{$disk}->[2];
debug($opt_v, 2, "Using partition limit measure: $measure warn:$warn critical: $critical");
} elsif ($host_measure ne "") {
$measure = $host_measure;
$warn = $host_warn;
$critical = $host_critical;
debug($opt_v, 2, "Using host limit measure: $measure warn: $warn critical: $critical");
} elsif ($glob_measure ne "") {
$measure = $glob_measure;
$warn = $glob_warn;
$critical = $glob_critical;
debug($opt_v, 2, "Using global limit measure: $measure warn: $warn critical: $critical");
} else {
$measure = $measure_default;
$warn = $warn_default;
$critical = $critical_default;
debug($opt_v, 2, "Using default limit measure: $measure warn: $warn critical: $critical");
}
if ($measure eq "b") {
if ($avail <= $critical) {
debug($opt_v, 2, "$disk is CRITICAL, $avail block free is <= $critical critical limit");
push(@critical_disks, $disk);
$dcritical++;
} elsif ($avail <= $warn) {
debug($opt_v, 2, "$disk is WARNING, $avail blocks free is <= $warn warning limit");
push(@warn_disks, $disk);
$dwarn++;
} else {
debug($opt_v, 2, "$disk is OK, $avail block free is > $warn warning limit");
$dok++;
}
if ($perfmon eq "") {
$perfmon = $perfmon . "'$disk'=$used;$warn;$critical;0;$total";
} else {
$perfmon = $perfmon . " '$disk'=$used;$warn;$critical;0;$total";
}
} else {
if ($percent >= $critical) {
debug($opt_v, 2, "$disk is CRITICAL, $percent% is >= $critical% critical limit");
push(@critical_disks, $disk);
$dcritical++;
} elsif ($percent >= $warn) {
debug($opt_v, 2, "$disk is WARNING, $percent% is >= $warn% warning limit");
push(@warn_disks, $disk);
$dwarn++;
} else {
debug($opt_v, 2, "$disk is OK, $percent% is < $warn% warning limit");
$dok++;
}
if ($perfmon eq "") {
$perfmon = $perfmon . "'$disk'=$percent%;$warn;$critical;0;100";
} else {
$perfmon = $perfmon . " '$disk'=$percent%;$warn;$critical;0;100";
}
}
}
}
my $state;
# Set our alert state
if ($dcritical >= 1) {
$state = "CRITICAL";
} elsif ($dwarn >= 1) {
$state = "WARNING";
} else {
$state = "OK";
}
# And finally, we report our findings
if ($opt_v == 0) {
print "$state: $dcritical disks are CRITICAL, $dwarn disks are WARNING & $dok disks are OK|$perfmon\n";
} else {
my $summary = "C" . $dcritical . "W" . $dwarn . "O" . $dok;
print "$state: $summary";
foreach (@critical_disks) {
print " C$_";
}
foreach (@warn_disks) {
print " W$_";
}
print "|$perfmon\n";
}
exit $ERRORS{$state};
sub print_short_help() {
print "check_snmp_disks.pl: Usage: check_snmp_disks.pl [-hv] -H host -C community name [-p port] [-t timeout]\n";
exit $ERRORS{"OK"};
}
sub print_long_help() {
print "check_snmp_disks.pl: Usage: check_snmp_disks.pl [-hv] -H host -C community name [-p port] [-t timeout]\n";
print "Written by BOfH\n";
print "Options:\n";
print "-C --community: Specify the SNMP community name\n";
print "-h --help: Print this help message\n";
print "-H --hostname: Specify the host to query\n";
print "-p --port: Specify a port to use (default is 161)\n";
print "-t --timeout: Specify the timeout in seconds\n";
exit $ERRORS{"OK"};
}
sub debug {
my $debug_level = shift;
my $mesg_level = shift;
my $mesg = shift;
if ($mesg_level <= $debug_level) {
print "$mesg\n";
}
}