#!/usr/bin/perl

# author: Chris Russell <chris.russell@htw.com.au>
# adapted from: Eric Schultz <eric.schultz@mentaljynx.com> Bladecentre plugin (http://www.monitoringexchange.org/cgi-bin/page.cgi?g=Detailed%2F2071.html;d=1)
# what:    monitor IBM server fans using snmp on RSA
# license: GPL - http://www.fsf.org/licenses/gpl.txt
#

use strict;
require 5.6.0;
use lib qw( /opt/nagios/libexec );
use utils qw(%ERRORS $TIMEOUT &print_revision &support &usage);
   use Net::SNMP qw(:snmp);
use Getopt::Long;
use vars qw/$exit $message $opt_version $opt_timeout $opt_help $opt_command $opt_host $opt_community $opt_verbose 
$opt_warning $opt_critical $opt_port $opt_mountpoint $snmp_session $PROGNAME $TIMEOUT $test_details $test_name $test_num/;

$PROGNAME      = "check_snmp_IBM_RSA.pl";
$opt_verbose   = undef;
$opt_host      = undef;
$opt_community = 'public';
$opt_command   = undef;
$opt_warning   = undef;
$opt_critical  = undef;
$opt_port      = 161;
$message       = undef;
$exit          = 'OK';


my %dataresults;
my %warnfans;
my %critfans;
my $resultcode = 3;

# =========================================================================== #
# =====> MAIN
# =========================================================================== #
process_options();

alarm( $TIMEOUT ); # make sure we don't hang Nagios

   my ($session, $error) = Net::SNMP->session(
      -version     => 'snmpv1',
      -nonblocking => 1,
      -hostname    => $opt_host,
      -community   => $opt_community,
      -port        => $opt_port
   );

   if (!defined($session)) {
      printf("ERROR: %s.\n", $error);
      exit 1;
   }

   my $fanTable = '.1.3.6.1.4.1.2.3.51.1.2.3';

   my $result = $session->get_next_request(
      -callback       => [\&check_fans, {}],
      -varbindlist    => [$fanTable]
   );

   if (!defined($result)) {
      printf("ERROR: %s.\n", $session->error);
      $session->close;
      exit 1;
   }

   snmp_dispatcher();

   $session->close;
   
alarm( 0 ); # we're not going to hang after this.

# Parse our the thresholds. and set the result
my ($ow_low,$ow_high,$oc_low,$oc_high) = parse_thres($opt_warning,$opt_critical);
my $res = "OK: ";

print "Low Warning Threshold is $ow_low\n" if verbose();
print "High Warning Threshold is $ow_high\n" if verbose();
print "Low Critical Threshold is $oc_low\n" if verbose();
print "High Critical Threshold is $oc_high\n" if verbose();
print "\n" if verbose();

foreach my $fan (keys(%dataresults)) {
	print "Fan number: $fan => $dataresults{$fan}\n" if verbose();

	if( ($ow_low ne '' and $dataresults{$fan} < $ow_low ) or ($ow_high ne '' and $dataresults{$fan} > $ow_high) ) {
		$res = "WARNING " . "Fan number: " . $fan . " is outside of its threshold at " . $dataresults{$fan} . "% of its max";
		print "$res\n" if verbose();
		$warnfans{$fan}=$dataresults{$fan};
	}
	if( ($oc_low ne '' and $dataresults{$fan} < $oc_low ) or ($oc_high ne '' and $dataresults{$fan} > $oc_high) ) {
		$res = "CRITICAL " . "Fan number: " . $fan . " is outside of its threshold at " . $dataresults{$fan} . "% of its max";
		print "$res\n" if verbose();
		$critfans{$fan}=$dataresults{$fan};
	}
}

if ((keys(%warnfans) ne 0 ) and (keys(%critfans) eq 0)) { $res = "WARNING: "; $resultcode = 1;} 
elsif ((keys(%warnfans) eq 0 ) and (keys(%critfans) ne 0)) { $res = "CRITICAL: "; $resultcode = 2;} 
elsif (keys(%critfans) ne 0) { $res = "CRITICAL: "; $resultcode = 2;} 
elsif (keys(%warnfans) ne 0) { $res = "WARNING: "; $resultcode = 1; }
else { $res = "OK: "; $resultcode = 0; }

if ((keys(%warnfans) ne 0) or (keys(%critfans) ne 0)) {
	my $warns = "";
	foreach my $fan (keys(%warnfans)) {
	  $warns .= "$fan=>$warnfans{$fan}% ";
	}
	
	my $crits = "";
	foreach my $fan (keys(%critfans)) {
	  $crits .= "$fan=>$critfans{$fan}% ";
	}
	$res .= "There are warnings on ( $warns) and Critical alerts on ( $crits)";
}
else {
	$res .= "There are no Fan problems";
}

print "$res\n";
exit $resultcode;


# =========================================================================== #
# =====> Sub-Routines
# =========================================================================== #

sub parse_thres{
	my ($opt_warning,$opt_critical)=@_;
	my ($ow_low,$ow_high) = ('','');
	if($opt_warning){
		if(($opt_warning =~ m/^(\d*?):(\d*?)$/) or ($opt_warning =~ m/^(\d*?),(\d*?)$/)){ ($ow_low,$ow_high) = ($1,$2); }
		elsif($opt_warning =~ m/^\d+$/){ ($ow_low,$ow_high)=(-1,$opt_warning); }
		}
	my ($oc_low,$oc_high) = ('','');
	if($opt_critical){
		if(($opt_critical =~ m/^(\d*?):(\d*?)$/)or($opt_critical =~ m/^(\d*?),(\d*?)$/)){ ($oc_low,$oc_high) = ($1,$2); }
		elsif($opt_critical =~ m/^\d+$/){ ($oc_low,$oc_high)=(-1,$opt_critical); }
		}
	return($ow_low,$ow_high,$oc_low,$oc_high);
	}

sub process_options {
	Getopt::Long::Configure( 'bundling' );
	GetOptions(
			'V'     => \$opt_version,       'version'     => \$opt_version,
			'v'     => \$opt_verbose,       'verbose'     => \$opt_verbose,
			'h'     => \$opt_help,          'help'        => \$opt_help,
			'H:s'   => \$opt_host,          'hostname:s'  => \$opt_host,
			'p:i'   => \$opt_port,          'port:i'      => \$opt_port,
			'C:s'   => \$opt_community,     'community:s' => \$opt_community,
			'c:s'   => \$opt_critical,          'critical:s'  => \$opt_critical,
			'w:s'   => \$opt_warning,          'warning:s'   => \$opt_warning,
			'o:i'   => \$TIMEOUT,           'timeout:i'   => \$TIMEOUT,
		  );

	if ( defined($opt_version) ) { local_print_revision(); }
	if ( defined($opt_verbose) ) { $SNMP::debugging = 1; }
	if ( !defined($opt_host) || defined($opt_help) ) {
		
		print_help();
		$resultcode = 3;
		exit $resultcode;
		}
	}

sub local_print_revision { print_revision( $PROGNAME, '$Revision: 1.0 $ ' ); }

sub print_usage { print "Usage: $PROGNAME -H <host> -C <snmp_community> -w <low>,<high> -c <low>,<high> [-o <timeout>] \n"; }

sub print_help {
	local_print_revision();
	print "SNMP IBM RSA plugin for Nagios\n\n";
	print_usage();
print <<EOT;
	-v, --verbose
		print extra debugging information
	-h, --help
		print this help message
	-H, --hostname=HOST
		name or IP address of host to check
	-C, --community=COMMUNITY NAME
		community name for the host's SNMP agent
	-w, --warning=INTEGER
		low:high percentages for fans
	-c, --critical=INTEGER
		low:high percentages for fans

EOT

	}

sub verbose (@) {
	return if ( !defined($opt_verbose) );
	print @_;
	}
   
  
   sub check_fans
   {
      my ($session, $table) = @_;

      if (!defined($session->var_bind_list)) {

         printf("ERROR: %s\n", $session->error);   

      } else {

         # Loop through each of the OIDs in the response and assign
         # the key/value pairs to the anonymous hash that is passed
         # to the callback.  Make sure that we are still in the table
         # before assigning the key/values.

         my $next;

         foreach my $oid (oid_lex_sort(keys(%{$session->var_bind_list}))) {
            if (!oid_base_match($fanTable, $oid)) {
               $next = undef;
               last;
            }
            $next = $oid; 
            $table->{$oid} = $session->var_bind_list->{$oid};   
         }

         # If $next is defined we need to send another request 
         # to get more of the table.

         if (defined($next)) {

            $result = $session->get_next_request(
               -callback       => [\&check_fans, $table],
               -varbindlist    => [$next]
            ); 

            if (!defined($result)) {
               printf("ERROR: %s\n", $session->error);
            }

         } else {

            # We are no longer in the table, so print the results.

            foreach my $oid (oid_lex_sort(keys(%{$table}))) {
               my $fanres = $table->{$oid};
               $fanres =~ s/% of maximum//g;
	       $fanres = trim($fanres);
               my $fannum = $oid;
               $fannum =~ s/.1.3.6.1.4.1.2.3.51.1.2.3.//g;
               $fannum =~ s/\.0//g;
               $fannum = trim($fannum);
               $dataresults{$fannum} = $fanres;
            }
         }
      }
   }
   
   sub trim {
   	#trim down whitespace in a string
   	
   	my $string = shift(@_);
   	$string =~ s/^\s+//;
   	$string =~ s/\s+$//;
   	return $string;
   }
