#!/usr/bin/perl -w

### check_ipmi_sensors.pl
# based on check_stuff.pl

# Alexander Greiner-Baer <alexander.greiner-baer@web.der> 2007
# mainly inspired by check_ipmi: Chris Wilson <check_ipmi@qwirx.com>, 2005-06-04
# see Chris Wilson's site: http://www.qwirx.com/check_ipmi
# 
# Nagios plugin using the Nagios::Plugin module and ipmitool.  
# see: http://ipmitool.sourceforge.net/
# tested with ipmitool 1.8.8
#
# checks status of temperature sensors and fans
#
# License: GPL
#
# Changelog:
# 1.1	perform checking on command line options
#	--
# 1	initial release
# 
##############################################################################
use strict;
use warnings;

use Nagios::Plugin ;

use vars qw($VERSION $PROGNAME  $verbose $warn $critical $timeout $result);
$VERSION = 1.1;

$PROGNAME = "check_ipmi_sensors";

# ipmi privilege level
my $PRIV = "USER";

# Path to ipmitool
my $IPMITOOL = "/usr/local/nagios/libexec/myplugins/ipmitool";

# sdr command
my $SDR = "sdr list full";

# instantiate Nagios::Plugin
my $p = Nagios::Plugin->new(
	usage => "Usage: %s [ -v|--verbose ]  [-t <timeout>]
	[ -H|--Host <ipaddr> ] [ -u|--user <username> ] [ -p|--pass <password> ]",
	version => $VERSION,
	blurb => 'This plugin checks Sensors with IPMI and will output 
	OK or CRITICAL. Requires ipmitool.', 

	extra => ""
);

# add all arguments 
$p->add_arg(
	spec => 'Host|H=s',
	help =>
	qq{-H, --Host=STRING
	Specify the remote station on the command line.},
	required => 0,
);

$p->add_arg(
	spec => 'user|u=s',
	help =>
	qq{-u, --user=STRING
	Specify the IPMI user on the command line.},
	required => 0,
);

$p->add_arg(
	spec => 'pass|p=s',
	help =>
	qq{-p, --pass=STRING
	Specify the IPMI password on the command line.},
	required => 0,
);

# parse arguments
$p->getopts;

# perform checking on command line options
if ( ( (defined $p->opts->Host) || (defined $p->opts->user) || (defined $p->opts->pass) )
	&& !( (defined $p->opts->Host) && (defined $p->opts->user) && (defined $p->opts->pass) ) ) {
	$p->nagios_exit(
		return_code => UNKNOWN,
		message	=> "Specify username, password and host on the command line."
	)
}

# helper
sub trim ($) {
	my ($v) = @_;
	$v =~ s/^ +//;
	$v =~ s/ +$//;
	return $v;
}


my $result=OK;
my $message="";
my %goodresults;
my %badresults;

# open ipmitool with remote connection if host, user and password exists
if ( (defined $p->opts->Host) && (defined $p->opts->user) && (defined $p->opts->pass) ) {
	my $host = $p->opts->Host;
	my $user = $p->opts->user;
	my $pass = $p->opts->pass;
	open IPMI, "$IPMITOOL -L $PRIV -H $host -U $user -P $pass $SDR |" or 
	$p->nagios_exit( 
		return_code => UNKNOWN, 
		message => "ipmitool: $!" 
	);
}
else {
	# fall back to local execution (for use with nrpe)
	open IPMI, "$IPMITOOL -L $PRIV $SDR |" or 
	$p->nagios_exit( 
		return_code => UNKNOWN, 
		message => "ipmitool: $!" 
	);
}

# parse ipmitool output
# mainly based on Chris Wilson's code
while ( my $line = <IPMI> ) {
	chomp $line;
	print "$line\n" if ( $p->opts->verbose );
	unless ($line =~ m/^(.*) \| (.*) \| (\w+)$/)
	{
		$p->nagios_exit(
			return_code => UNKNOWN,
			message => "Bad format in ipmitool output: $line"
		);
	}
	my $name  = trim $1;
	my $value = trim $2;
	my $state = trim $3;

	# $uname is used as key, check for doublets 
	my $counter = 1;
	my $uname = "$name";
	while ($goodresults{$uname}) {
		$uname = $name . $counter++;
	}

	$counter = 1;
	$uname = "$name";
	while ($badresults{$uname}) {
		$uname = $name . $counter++;
	}

	# skip not readable entries
	next if $state eq "ns";

	# put bad entries in %badresults
	if ($state ne "ok") {
		$badresults{$uname} = $state;
	}

	# rest is good
	$goodresults{$uname} = $value;

}

close IPMI or 
$p->nagios_exit( 
	return_code => UNKNOWN, 
	message => "ipmitool: $! $?" 
);

# check results an build a readable output 
if (keys %badresults) {
	$result = CRITICAL;
	foreach my $name (sort keys %badresults) {
		if ( $message ne "" ) {
			$message = $message."; ";
		}
		$message = $message.$name.": ".$badresults{$name};
	}
}
else {
	foreach my $name (sort keys %goodresults) {
		next unless $name =~ m/(fan)|(temp)/i or $goodresults{$name} =~ m/(degrees)|(rpm)/i;
		if ( $message ne "" ) {
			$message = $message."; ";
		}
		my $value = $goodresults{$name};
		$value =~ s/degrees C//;
		$value =~ s/RPM//;
		$value = trim $value;
		$message = $message.$name.": ".$value;
	}
}

print "result $result\n " if $p->opts->verbose;

$p->nagios_exit( 
	return_code => $result, 
	message => "$message" 
);

