#!/usr/bin/perl -w
#
# check_emerson_acu - nagios plugin 
#
# by Frank Bulk <frnkblk@iname.com> 
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

use strict;
use Net::SNMP;
use Getopt::Long;
use File::Basename;
&Getopt::Long::config('auto_abbrev');
use IO::Socket;

my $version = "1.0";
my $status;
my $needhelp = '';
my $TIMEOUT = 60;

my %ERRORS = (
	'OK'       => '0',
	'WARNING'  => '1',
	'CRITICAL' => '2',
	'UNKNOWN'  => '3',
);

# default return value is UNKNOWN
my $state = "UNKNOWN";

# time this script was run
my $runtime = time();

# responses from script
my $answer = "";
my $oidmsg = "";
my $alarmmsg = "";
my $error;
my $oidwarn = 0;
my $oidcrit = 0;
my @oid_array;
my $index;
my $interface_num;
my $temp;
my $minor_match;
my $major_match;
my $desired_value;
my $actual_value;
my $output_index;
my $input_status;

# external variable declarations
my $hostname;
my $community = "public";
my $port = 161;
my $maxsystemcurrent = 100;
my $i;
my $acinputlinecount = 0;
my $major;
my $minor;
my %alarmstate;
my $uptime;
my @systemStatus_array = ( '', 'unknown', 'normal', 'warning', 	'minor', 'major', 'critical', 'unmanaged', 'restricted', 'testing', 'disabled' );
$alarmstate{minor} = 0;
$alarmstate{major} = 0;

# snmp related variables
my $snmpkey;
my $snmpoid;
my %bla;
my %bla2;
my $key;

## main program

# Just in case of problems, let's not hang 
$SIG{'ALRM'} = sub {
	print ("ERROR: No (timely) SNMP response from $hostname (alarm)\n");
	exit $ERRORS{'UNKNOWN'};
};
alarm($TIMEOUT);

# we must have -some- arguments
if (scalar(@ARGV) == 0) {
	usage();
} # end if no options

Getopt::Long::Configure("no_ignore_case");
$status = GetOptions(
	"h|help"             => \$needhelp,
	"C|snmpcommunity=s"  => \$community,
	"p|port=i"           => \$port,
	"H|hostname=s"       => \$hostname,
	"msc|maxsystemcurrent=i"       => \$maxsystemcurrent,
);

if ($status == 0 || $needhelp) {
	usage();
} # end if getting options fails or the user wants help

my $systemStatus = snmp_get_request($hostname, $port, "2c", $community, "1.3.6.1.4.1.6302.2.1.2.1.0");
#print "DEBUG: $systemStatus $systemStatus_array[$systemStatus]\n";
if ($systemStatus eq 2) {
	$oidmsg = $oidmsg . "\nSystem status: $systemStatus_array[$systemStatus]";
}
elsif ($systemStatus eq 5) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nSystem status: $systemStatus_array[$systemStatus]";
}
elsif ($systemStatus eq 6) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nSystem status: $systemStatus_array[$systemStatus]";
}
elsif ($systemStatus eq 3) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nSystem status: $systemStatus_array[$systemStatus]";
}
elsif ($systemStatus eq 4) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nSystem status: $systemStatus_array[$systemStatus]";
}
else  {
	$alarmstate{unknown}++;
	$alarmmsg = $alarmmsg . "\nSystem status: $systemStatus_array[$systemStatus]";
}

my $systemVoltage = snmp_get_request($hostname, $port, "2c", $community, "1.3.6.1.4.1.6302.2.1.2.2.0") / 1000;
if ($systemVoltage <= 46) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nSystem output voltage much too low at $systemVoltage VDC";
}
elsif ($systemVoltage >= 58) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nSystem output voltage much too high at $systemVoltage VDC";
}
elsif ($systemVoltage <= 48) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nSystem output voltage too low at $systemVoltage VDC";
}
elsif ($systemVoltage >= 56) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nSystem output voltage too high at $systemVoltage VDC";
}
else {
	$oidmsg = $oidmsg . "\nSystem output voltage: $systemVoltage VDC";
}

my $systemCurrent = snmp_get_request($hostname, $port, "2c", $community, "1.3.6.1.4.1.6302.2.1.2.3.0") / 1000;
my $systemUsedCapacity = snmp_get_request($hostname, $port, "2c", $community, "1.3.6.1.4.1.6302.2.1.2.4.0");
if ($systemUsedCapacity >= 85) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nSystem output amperage too high at $systemCurrent A ($systemUsedCapacity%)";
}
elsif (($systemCurrent >= $maxsystemcurrent) || ($systemUsedCapacity >= 80)) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nSystem output amperage high at $systemCurrent A ($systemUsedCapacity%)";
}
elsif ($systemCurrent <= 1) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nSystem output amperage low at $systemCurrent A";
}
else {
	$oidmsg = $oidmsg . "\nSystem output amperage: $systemCurrent A ($systemUsedCapacity%)";
}

my $psBatteryVoltage = snmp_get_request($hostname, $port, "2c", $community, "1.3.6.1.4.1.6302.2.1.2.5.1.0") / 1000;
if ($psBatteryVoltage <= 46) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nBattery output voltage much too low at $psBatteryVoltage VDC";
}
elsif ($psBatteryVoltage >= 58) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nBattery output voltage much too high at $psBatteryVoltage VDC";
}
elsif ($psBatteryVoltage <= 48) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nBattery output voltage too low at $psBatteryVoltage VDC";
}
elsif ($psBatteryVoltage >= 56) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nBattery output voltage too high at $psBatteryVoltage VDC";
}
else {
	$oidmsg = $oidmsg . "\nBattery output voltage: $psBatteryVoltage VDC";
}

for ($i = 1; $i <= 3; $i++) {
	my $psInputLineVoltage = snmp_get_request($hostname, $port, "2c", $community, "1.3.6.1.4.1.6302.2.1.2.6.$i.0") / 1000;
	if ($psInputLineVoltage > 0) {
		$acinputlinecount++;
	}
	if ($psInputLineVoltage >= 250) {
		$alarmstate{major}++;
		$alarmmsg = $alarmmsg . "\nInput Line " . chr(64 + $i) . " voltage much too high at $psInputLineVoltage VAC";
	}
	elsif  (($psInputLineVoltage > 0) && ($psInputLineVoltage <= 230)) {
		$alarmstate{major}++;
		$alarmmsg = $alarmmsg . "\nInput Line " . chr(64 + $i) . " voltage much too low at $psInputLineVoltage VAC";
	}
	elsif ($psInputLineVoltage >= 245) {
		$alarmstate{minor}++;
		$alarmmsg = $alarmmsg . "\nInput Line " . chr(64 + $i) . " voltage too high at $psInputLineVoltage VAC";
	}
	elsif  (($psInputLineVoltage > 0) && ($psInputLineVoltage <= 235)) {
		$alarmstate{minor}++;
		$alarmmsg = $alarmmsg . "\nInput Line " . chr(64 + $i) . " voltage too low at $psInputLineVoltage VAC";
	}
	else {
		$oidmsg = $oidmsg . "\nInput Line " . chr(64 + $i) . " voltage: $psInputLineVoltage VAC";
	}	
}
if ($acinputlinecount == 1) {
	$alarmstate{minor}++;
	$alarmmsg = $alarmmsg . "\nOnly one AC Input Line functioning!";
}
elsif ($acinputlinecount = 0) {
	$alarmstate{major}++;
	$alarmmsg = $alarmmsg . "\nNo AC Input Line functioning!";
}


# figure out what state we're in
if ($alarmstate{major}) {
	$state = "CRITICAL";
} elsif ($alarmstate{minor}) {
	$state = "WARNING";
} elsif ($alarmstate{unknown}) {
	$state = "UNKNOWN";
} else {
	$state = "OK";
} # end if we have warnings or not

# setup final message
$answer = "critical: $alarmstate{major}, warning: $alarmstate{minor}$alarmmsg$oidmsg";
print ("$state: $answer");
exit $ERRORS{$state};


## subroutines ##

# the usage of this program (duh)
sub usage
{
	print <<END;
== check_emerson_acu v$version ==
Perl SNMP check Emerson ACU+ plugin for Nagios
Frank Bulk <frnkblk\@iname.com>

Usage:
  check_emerson_acu (-C|--snmpcommunity) <read_community>
                    (-H|--hostname) <hostname>
                    [-p|--port] <port> 
                    [-msc|--maxsystemcurrent] <maximum allowed current draw in amps>

END
	exit $ERRORS{"UNKNOWN"};
}

sub snmp_get_request {
        my $ip = shift;
	my $port = shift;
        my $version = shift;
	my $community = shift;
        my $sysdescr = shift;

        my $snmp_result = '';

        my ($session, $error) = Net::SNMP->session(
                -hostname => $ip,
                -version => $version,
                -community => $community,
                -port => $port);

        $snmp_result = $session->get_request(
                -varbindlist => [$sysdescr]
                );

        if (!defined($snmp_result)) {
#               print "\nERROR: Trying to obtain $sysdescr from $ip. $session->error.\n";
                sleep 5;
                $snmp_result = $session->get_request(
                        -varbindlist => [$sysdescr]
                );
                if (!defined($snmp_result)) {
                        print "\nERROR: Trying to obtain $sysdescr from $ip. $session->error.\n";
                        $session->close;
                        return 0;
                }
        }

        $session->close;

        return $snmp_result->{$sysdescr};
}

sub snmp_get_table {
        my $ip = shift;
	my $port = shift;
	my $version = shift;
	my $community = shift;
        my $snmp_oid = shift;
#print "DEBUG: snmp_oid [$snmp_oid]\n";

        my ($session, $error) = Net::SNMP->session(
                -hostname => $ip,
                -community => $community,
		-version => $version,
                -timeout => $TIMEOUT,
                -port => $port,
        );

        my $snmp_result = $session->get_table(
                -baseoid => $snmp_oid
        );

        if (!defined($snmp_result)) {
#               print "ERROR: $session->error.\n";
                $session->close;
		return;
#		exit 1;
        }

        $session->close;

        return %{$snmp_result};
}

sub get_uptime {
        my $ip = shift;
	my $port = shift;
	my $version = shift;
	my $community = shift;

	my $session;
	my $resultat=undef;
	my $result;
	my $uptime='.1.3.6.1.2.1.1.3.0';

# SNMP1 Login
	 ($session, $error) = Net::SNMP->session(
	-hostname  => $ip,
        -version => $version,
	-community => $community,
	-port      => $port,
	-translate   => [
	-timeticks => 0x0
	]
	);
#error handle for connection error	
	if (!defined($session)) {
	   printf("ERROR opening session: %s.\n", $error);
	   exit $ERRORS{"UNKNOWN"};
	}

	$resultat=$session->get_request($uptime);

#error handle for OID error
	if (!defined($resultat)) {
		printf("ERROR: Description table : %s.\n", $session->error);
		$session->close;
		exit $ERRORS{"UNKNOWN"};
	}
	$session->close;
	
#get regex on output	
	$result=$resultat->{$uptime};
	
	return $result;	
}#end Get_uptime

