#!/usr/bin/perl
# 
# check_ups_alarm.pl
#
# Matt Stanford
# 12/03/04 - Release 1.0
#
# Known to work with Liebert NPower UPSs
#
# Nagios Plugin designed to query SNMP on the UPS in the data center and retrun the current status
# 0 alarms is OK
# 1 and above is Critical (UPS shuts down at 5)
#
# You can use and distribute this script under terms of the GNU 
# GENERAL PUBLIC LICENSE Version 2 later.
#
use warnings;
use strict;
use Net::SNMP;
use Getopt::Long;
Getopt::Long::config('auto_abbrev');

sub nagios_exit;
sub show_help;
sub check_action;
sub get_snmp_ups;
sub get_nagios_status;

####################
# DEFINE VARIABLES #
####################

my $snmp_host;
my $snmp_community;
my $snmp_version		= 1;
my $snmp_timeout		= 5;
my $snmp_port			= 161;

my $snmp_battery_status		= "1.3.6.1.2.1.33.1.2.1.0";
my $snmp_battery_sec		= "1.3.6.1.2.1.33.1.2.2.0";
my $snmp_battery_min_remain	= "1.3.6.1.2.1.33.1.2.3.0";
my $snmp_battery_cha_remain	= "1.3.6.1.2.1.33.1.2.4.0";
my $snmp_battery_temp		= "1.3.6.1.2.1.33.1.2.7.0";

my $snmp_input_line_bads	= "1.3.6.1.2.1.33.1.3.1.0";

my $snmp_output_load_pct	= "1.3.6.1.2.1.33.1.4.4.1.5.1";

my $snmp_alarm_count		= "1.3.6.1.2.1.33.1.6.1.0";


my %NAGSTAT			= ('UNKNOWN'	=>	'-1',
				   'OK'		=>	'0',
				   'WARNING'	=>	'1',
				   'CRITICAL'	=>	'2');

my @battery_status 		= ('?','Battery State UNKNOWN','Battery State NORMAL','Battery State LOW','Battery State DEPLETED');

my %snmp_ups			= ('batteryStatus'	=>	$snmp_battery_status,
				   'batterySeconds'	=>	$snmp_battery_sec,
				   'batteryMinRemaining' =>	$snmp_battery_min_remain,
##
				   'batteryChaRemain' =>	$snmp_battery_cha_remain,
				   'batteryTemperature'	=>	$snmp_battery_temp,
				   'inputLineBads'	=>	$snmp_input_line_bads,
				   'outputLoadPercent'	=>	$snmp_output_load_pct,
				   'alarmCount'		=>	$snmp_alarm_count);

my $status;
my $warning;
my $critical;
my $action;
my $nagios_message;
my $current_status;
my $current_oid;
my $lowerwarn;
my $lowercrit;

####################
# DEFINE FUNCTIONS #
####################

sub get_snmp_ups($){

	my $OID = shift;
	my $session;
	my $error;
	my $response;

	($session,$error) = Net::SNMP->session(
		Hostname	=>	$snmp_host,
		Port		=>	$snmp_port,
		Version		=>	$snmp_version,
		Timeout		=>	$snmp_timeout,
		Community	=>	$snmp_community
		);

	# Make sure we connected
	if (!defined($session)){
		
		exit;
	}

	# Query the UPS
	if (!defined($response = $session->get_request($OID))){
		printf STDERR $session->error();
	
		$session->close();
		nagios_exit "UNKNOWN";
	}

	# Close the session
	$session->close();

	return $response->{$OID};

}


sub nagios_exit($){

	my $a = shift;
	exit $NAGSTAT{"$a"};

}

# P1 = Action
# P2 = Current numeric status
# P3 = Warning Threshold
# P4 = Critical Threshold
# P5 = Warning Lower Threshold
# P6 = Critical Lower Threshold
sub get_nagios_status($$$$;$$){

	my $act = shift;
	my $sta = shift;
	my $war = shift;
	my $cri = shift;
	my $lwt = shift;
	my $lct = shift;
	my $tmp;
	my $nagstatus = "UNKNOWN";

	if (!defined($lwt)){
		$lwt = 15;
	}
	if (!defined($lct)){
		$lct = 10;
	}
	if ($act eq 'batteryStatus'){
		if ($sta == 2){
			$nagstatus = "OK";
		} elsif (($sta == 3) || ($sta == 4)){
			$nagstatus = "CRITICAL";
		} else {
			$nagstatus = "UNKNOWN";
		}
		$nagios_message = $battery_status[$sta];
	} elsif ($act eq 'batteryMinRemaining'){
		if ($war < $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $war;
		}
		if ($sta == 65535){
			$nagstatus = "OK";
		} elsif ($sta > $war){
			$nagstatus = "OK";
		} elsif (($sta <= $war) && ($sta > $cri)){
			$nagstatus = "WARNING";
		} elsif ($sta <= $cri) {
			$nagstatus = "CRITICAL";
		} else {
			$nagstatus = "UNKNOWN";
		}
		$nagios_message = "UPS Status $nagstatus; $sta minutes remaining";
        } elsif ($act eq 'batteryChaRemain'){                
		if ($war < $cri){
                        $tmp = $war;
                        $war = $cri;
                        $cri = $war;
                }
                if ($sta == 100){
                        $nagstatus = "OK";
                } elsif ($sta > $war){
                        $nagstatus = "OK";
                } elsif (($sta <= $war) && ($sta > $cri)){
                        $nagstatus = "WARNING";
                } elsif ($sta <= $cri) {
                        $nagstatus = "CRITICAL";
                } else {
                        $nagstatus = "UNKNOWN";
                }
                $nagios_message = "UPS Status $nagstatus; $sta percent remaining";
	} elsif ($act eq 'batterySeconds'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $war;
		}
		if ($sta == 0){
			$nagstatus = "OK";
		} elsif ($sta < $war){
			$nagstatus = "OK";
		} elsif (($sta >= $war) && ($sta < $cri)){
			$nagstatus = "WARNING";
		} elsif ($sta >= $cri){
			$nagstatus = "CRITICAL";
		} else {
			$nagstatus = "UNKNOWN";
		}
		if ($sta == 0){
			$nagios_message = "UPS is on city/generator power.";
		} else {
			$nagios_message = "UPS is RUNNING.  We have been on battery power for $sta seconds";
		}
	} elsif ($act eq 'batteryTemperature'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $war;
		}
		if ($lwt < $lct){
			$tmp = $lwt;
			$lwt = $lct;
			$lct = $lwt;
		}
		$sta = ((1.8 * $sta) + 32);
		if (($sta < $war) && ($sta > $lwt)){
			$nagstatus = "OK";
		} elsif ((($sta >= $war) && ($sta < $cri)) || (($sta <= $lwt) && ($sta > $lct))){
			$nagstatus = "WARNING";
		} elsif (($sta >= $cri) || ($sta <= $lct)){
			$nagstatus = "CRITICAL";
		} else {
			$nagstatus = "UNKNOWN";
		}
		$nagios_message = "UPS Battery Temperature $nagstatus.  Current Temp is $sta degrees Farenheit";
	} elsif ($act eq 'inputLineBads'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $war;
		}
		if ($sta == 0){
			$nagstatus = "OK";
		} elsif ($sta < $war){
			$nagstatus = "OK";
		} elsif (($sta >= $war) && ($sta < $cri)){
			$nagstatus = "WARNING";
		} elsif ($sta >= $cri){
			$nagstatus = "CRITICAL";
		} else {
			$nagstatus = "UNKNOWN";
		}
		$nagios_message = "UPS Input Line Bad Count is $nagstatus.  The current count is $sta.";
	} elsif ($act eq 'outputLoadPercent'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $war;
		}
		if ($sta < $war){
			$nagstatus = "OK";
		} elsif (($sta >= $war) && ($sta < $cri)){
			$nagstatus = "WARNING";
		} elsif ($sta >= $cri){
			$nagstatus = "CRITICAL";
		} else {
			$nagstatus = "UNKNOWN";
		}
		$nagios_message = "UPS Output Load is $nagstatus.  The current Load is $sta\%.";
	} elsif ($act eq 'alarmCount'){
		if ($sta == 0){
			$nagstatus = "OK";
			$nagios_message = "UPS Alarm count is OK, Currently there are no known alarms";
		} else {
			$nagstatus = "CRITICAL";
			$nagios_message = "UPS Alarm count is CRITICAL.  Currently we have $sta alarms";
		}
	} else {
		$nagstatus = "UNKNOWN";
		$nagios_message = "UPS State UNKNOWN.  Please check the command line syntax";
	}

	printf "$nagios_message\n";
	nagios_exit "$nagstatus";

}


# Routine to check the input from the user.  We need to make sure it is in the list.
# If everything is ok then return then set global $action to this (we just return the value)
sub check_action($){

	my $a = shift;

	if ($a eq 'batteryStatus'){
		return $a;
	} elsif ($a eq 'batteryMinRemaining'){
		return $a;
        } elsif ($a eq 'batteryChaRemain'){
                return $a;
	} elsif ($a eq 'batterySeconds'){
		return $a;
	} elsif ($a eq 'batteryTemperature'){
		return $a;
	} elsif ($a eq 'inputLineBads'){
		return $a;
	} elsif ($a eq 'outputLoadPercent'){
		return $a;
	} elsif ($a eq 'alarmCount'){
		return $a;
	} else {
		return "ERROR";
	}
}
	

sub show_help(){
	
	printf "scriptname [options]\n";
	printf "       	-C\tSNMP Community\n";
	printf "       	-H\tHostname\n";
	printf "       	-P\tSNMP Port\n";
	printf "	-T\tSNMP Timeout\n";
	printf "	-w\tWarning Threshold\n";
	printf "	-c\tCritical Threshold\n";
	printf "	-X\tType of Check (see below)\n\n";
	printf "Check Types:\n";
	printf "   batteryStatus	Current Status of the Battery [UNKNOWN,NORMAL,LOW,DEPLETED]\n";
	printf "   batteryMinRemaining	Estimated minutes of battery life remaining (65535 means we aren't on battery power)\n";
	printf "   batteryChaRemain	Shows the current Battery Charge level\n";
	printf "   batterySeconds	Number of seconds we've been on battery power (0 means we aren't on battery power)\n";
	printf "   batteryTemperature	Current temperature (degrees Farenheit)\n";
	printf "        -k\tLower Warning Threshold\n";
	printf "	-r\tLower Critical Threshold\n";
	printf "   inputLineBads	Counter showing how many times the input has been out of spec\n";
	printf "   outputLoadPercent	Percentage of the current load of the Data Center compared to the capacity of the UPS\n";
	printf "   alarmCount		Current number of alarms on the UPS\n";
	printf "\nNote:\n";
	printf "     The Warning and Critical Thresholds should always be set UNLESS batteryStatus is selected\n";
	printf "     Example: ./check_vertiv.pl -C public -H 193.168.3.30 -X batteryStatus -w 3 -c 4 \n";
	nagios_exit "UNKNOWN";
}

Getopt::Long::Configure('bundling');
$status = GetOptions
        ("C=s",         \$snmp_community,
         "H=s",         \$snmp_host,
         "P=i",      	\$snmp_port,
         "T=i",   	\$snmp_timeout,
         "X=s",         \$action,
	 "w=i",		\$warning,
	 "c=i",		\$critical,
 	 "k=i",		\$lowerwarn,
 	 "r=i",		\$lowercrit);

# We need either a Status Action or we need a warning and a critical 
if ((!defined($action)) && ((!defined($critical)) || (!defined($warning)))){
	show_help;
} elsif ((!defined($snmp_host)) || (!defined($snmp_port)) || (!defined($snmp_port))){
	show_help;
}

if ((!defined($lowerwarn)) || (!defined($lowercrit))){
	$lowerwarn = 15;
	$lowercrit = 10;
}

# Verify that what was entered as an action is legal
$action = check_action "$action";

if ($action ne "ERROR"){
	$current_oid = $snmp_ups{"$action"};
	$current_status = get_snmp_ups "$current_oid";
} else {
	printf "Unknown action (-X) type!\n";
	show_help;
}

#get_nagios_status "$action", "$current_status", "$warning", "$critical", "$lowerwarn", "$lowercrit";
get_nagios_status "$action", "$current_status", "$warning", "$critical", "$lowerwarn", "$lowercrit";
