#!/usr/bin/perl -wT
# author: Al Tobey <albert.tobey@priority-health.com>
# what:    monitor diskspace using the host-resources mib
# license: GPL - http://www.fsf.org/licenses/gpl.txt
#
# Todo:

require 5.006;
use strict;
use lib utils.pm ;
use Plugin;
use Plugin::Parameter qw(:DEFAULT :snmp :thresholds);

use vars qw( $exit $message $opt_t $opt_command $opt_H $opt_C $opt_v $opt_w $opt_c $opt_p $opt_m $opt_s $snmp_session $PROGNAME %mounts );

use utils qw(%ERRORS &usage);
use Net::SNMP;

$w_opt->default(99);
$w_opt->description("percent of disk used to generate WARNING state");
$w_opt->optional("yes");
$c_opt->default(100);
$c_opt->description("percent of disk used to generate CRITICAL state");
$c_opt->optional("yes");
my $m_opt = new Plugin::Parameter(-name => "mountpoint", -flags => [ 'm', 'mountpoint' ],
				  -optional => "no", -valueoptional => "no", -type => "DIRECTORIES",
				  -description => "Mount point(s) for disks. A mountpoint, or a comma delimited list of mountpoints");
my $s_opt = new Plugin::Parameter(-name => "statistics", -flags => [ 's', 'statistics' ],
				  -optional => "yes", -valueoptional => "yes", -type => "NONE",
				  -description => "output statistics in Nagios format");
$p_opt->default(161);
my $plugin = new Plugin(-revision => '$Revision: 1.1 $',
			-copyright => "2002 Al Tobey <albert.tobey\@priority-health.com>, 2004 Howard Wilkinson <howard\@cohtech.com>",
			-shortcomment => "SNMP Disk Monitor plugin for Nagios",
			-parameterlists => [ [ $H_opt, $C_opt, $s_opt, $w_opt, $c_opt, $t_opt, $m_opt, $p_opt, $v_opt ], $h_opts, $V_opts ]);

$message       = undef;
$exit          = 'OK';
%mounts        = ();

sub process_options {

    $plugin->init() ;

    $opt_m = [ split(/,/, $opt_m) ];
}

sub verbose (@) {
    return if ( !defined($opt_v) );
    print @_;
}

# =========================================================================== #
# =====> MAIN
# =========================================================================== #
process_options();

$|=1;

$plugin->start_timeout($opt_t, "Don't hang about fro too long (alarm)");

my ($snmp_session, $error) = Net::SNMP->session(-hostname => $opt_H,
						-community => $opt_C,
						-port => $opt_p,
						-version => '2c',
						-timeout => $opt_t,
						-debug => ($opt_v)?$opt_v:0
					       );

if (!defined $snmp_session) {
    usage("$PROGNAME UNKNOWN: Cannot establish SNMP session - $error\n");
}

my $isoMIB = "1";
my $orgMIB = "$isoMIB.3";
my $dodMIB = "$orgMIB.6";
my $internetMIB = "$dodMIB.1";
my $mgmtMIB = "$internetMIB.2";
my $mib2MIB = "$mgmtMIB.1";
my $hostMIB = "$mib2MIB.25";
my $hrStorageMIB = "$hostMIB.2";
my $hrStorageTableMIB = "$hrStorageMIB.3";
my $hrStorageEntryMIB = "$hrStorageTableMIB.1";
my $hrStorageIndexMIB = "$hrStorageEntryMIB.1";
my $hrStorageTypeMIB = "$hrStorageEntryMIB.2";
my $hrStorageDescrMIB = "$hrStorageEntryMIB.3";
my $hrStorageAllocationUnitsMIB = "$hrStorageEntryMIB.4.";
my $hrStorageSizeMIB = "$hrStorageEntryMIB.5.";
my $hrStorageUsedMIB = "$hrStorageEntryMIB.6.";
my $hrStorageAllocationFailuresMIB = "$hrStorageEntryMIB.7";

# retrieve the data from the remote host
my %mmap = ( $hrStorageDescrMIB            => "mountpoint",
	     $hrStorageAllocationUnitsMIB  => "alloc_units",
	     $hrStorageSizeMIB             => "size",
	     $hrStorageUsedMIB             => "used"
	     );

foreach my $oid (keys %mmap) {
  my $response = $snmp_session->get_table(-baseoid => $oid );
  if (!defined $response ) {
    usage("$PROGNAME UNKNOWN: error retrieving SNMP $mmap{$oid} data: " . $snmp_session->error . "\n");
  }

  foreach my $key (keys %{$response}) {
    $key =~ m/([0-9]+)$/;
    my $index = $1;
    $mounts{$index}->{$mmap{$oid}} = $response->{$key};
  }
}

$plugin->stop_timeout();

foreach my $key (keys %mounts) {
    if (defined $mounts{$key}->{alloc_units}) {
        $mounts{$key}->{size} = $mounts{$key}->{size} * $mounts{$key}->{alloc_units}
	  if (defined $mounts{$key}->{size});
	$mounts{$key}->{used} = $mounts{$key}->{used} * $mounts{$key}->{alloc_units}
	  if (defined $mounts{$key}->{used});
    }
}

# now find the mountpoint or mountpoints that were actually requested and push onto an array for output
my @matches = ();
foreach my $mp ( @$opt_m ) {
    my $found = scalar(@matches); # count all matches
    foreach my $key ( keys(%mounts) ) {
        if ( $mounts{$key}->{mountpoint} eq $mp ) {

            # find the percentate - eval to avoid divide by zero errors
            eval { $mounts{$key}->{percent_used} = $mounts{$key}->{used} / $mounts{$key}->{size} };
            $mounts{$key}->{percent_used} =~ s/^0\.([0-9]{1,2})([0-9]?).*/$1/; # truncate
            if ( $2 >= 5 ) { $mounts{$key}->{percent_used}++ }; # round the number number

            verbose "mountpoint $mp has ", $mounts{$key}->{percent_used}, "% used, ",
                $mounts{$key}->{size}, " bytes and ",$mounts{$key}->{used}, " used\n"; 

            push( @matches, $mounts{$key} );
        }
    }
    if ( scalar(@matches) == $found ) {
        usage("$PROGNAME UNKNOWN: could not locate mountpoint $mp on host\n");
    }
}

# now run through and check the thresholds
foreach my $mp ( @matches ) {
    if ( $mp->{percent_used} >= $opt_w  ) {
        $exit = 'WARNING';
        if ( $mp->{percent_used} >= $opt_c ) { $exit = 'CRITICAL'; }
    }
    $message .= $mp->{percent_used}.'% used on '.$mp->{mountpoint}.', ';
}
$message =~ s/,\s*$//;

# append statistics if requested
if ( defined($opt_s) ) {
    my @tmp = ();
    foreach my $mp ( @matches ) {
        push( @tmp, join(',',$mp->{mountpoint},$mp->{size},$mp->{used}) );
    }
    $message .= '|'.join( ':', @tmp );
}

print "$PROGNAME $exit: $message\n";
exit $ERRORS{$exit};


