#!/usr/bin/perl -wT
# 
# check_bestlinkups_alarm.pl
#
# Don Flynn
# 5/4/11 - Toward release 1.0
# Based on script by :
# Matt Stanford
# 12/03/04 - Release 1.0
#
# Attempting to get this to work with Best Power's Bestlink SNMP adapters
#
# 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 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.4.1.2947.1.8.4.6"; #upsAlarmCheckBattery 0 good, 1 fail
my $snmp_replacebattery_status	= "1.3.6.1.4.1.2947.1.8.4.7"; #upsAlarmReplaceBattery 0 good, 1 fail

my $snmp_battery_sec		= "1.3.6.1.4.1.2947.1.2.2"; # upsBatteryTimeOnBattery (in seconds)
my $snmp_battery_min_remain	= "1.3.6.1.4.1.2947.1.2.3"; # upsBatteryRuntimeRemaining (in minutes)
my $snmp_battery_temp		= "1.3.6.1.4.1.2947.1.2.6"; # upsBatteryTemperature in 1/10 degrees C

#Formerly inputlinebads
my $snmp_on_battery		= "1.3.6.1.4.1.2947.1.8.4.1"; # upsAlarmonBattery, 0 is utility, 1 is battery

my $snmp_output_load_pct	= "1.3.6.1.4.1.2947.1.4.9"; # upsOutputPercentFullLoad %loading on UPS

#Formerly alarm_count
my $snmp_bypass_active		= "1.3.6.1.4.1.2947.1.8.4.14"; # upsAlarmBypassOn 0 is ok, 1 bypass engaged

#New Tests for registered clients
my $snmp_total_clients		= "1.3.6.1.4.1.2947.1.5.10.2"; # upsRegisteredShutdownClientsTotalNumberOf
my $snmp_registered_clients	= "1.3.6.1.4.1.2947.1.5.10.1.1.2"; # upsRegisteredShutdownClientsIPAddress

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,
				   'replacebattery'	=>	$snmp_replacebattery_status,
				   'batterySeconds'	=>	$snmp_battery_sec,
				   'batteryMinRemaining' =>	$snmp_battery_min_remain,
				   'batteryTemperature'	=>	$snmp_battery_temp,
				   'onBattery'		=>	$snmp_on_battery,
				   'outputLoadPercent'	=>	$snmp_output_load_pct,
				   'bypassActive'	=>	$snmp_bypass_active,
				   'total_clients'	=>	$snmp_total_clients,
				   'registered_clients' =>	$snmp_registered_clients);

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 == 0){
			$nagstatus = "OK";
			$nagios_message = "Battery Status is OK";
		} elsif ($sta == 1) {
			$nagstatus = "CRITICAL";
			$nagios_message = "A battery has failed a periodic test from the UPS";
 		} else {
			$nagstatus = "UNKNOWN";
			$nagios_message = "battery status UNKNOWN status is $sta";
		}
		
	printf ("$nagios_message\n");
	nagios_exit "$nagstatus";
	} 

	if ($act eq 'replacebattery') {
		if ($sta == 0){
			$nagstatus = "OK";
			$nagios_message = "UPS battery is OK";
	}
		elsif ($sta == 1){
			$nagstatus = "CRITICAL";
			$nagios_message = "UPS has determined a battery needs replacing";
		}else {
			$nagstatus = "UNKNOWN";
		}
	printf ("$nagios_message\n");
        nagios_exit "$nagstatus";
	}
	elsif ($act eq 'batteryMinRemaining'){
		if ($war < $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $tmp;
		}
		if ($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";
		printf ("$nagios_message\n");
	        nagios_exit "$nagstatus";
	} 
	elsif ($act eq 'batterySeconds'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $tmp;
		}
		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";
		}
		printf ("$nagios_message\n");
	        nagios_exit "$nagstatus";
	} 
	elsif ($act eq 'batteryTemperature'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $tmp;
		}
		if ($lwt < $lct){
			$tmp = $lwt;
			$lwt = $lct;
			$lct = $tmp;
		}
		$sta = ((1.8 * ( $sta / 10) ) + 32); # The SNMP adapter reports temp weirdly -> 1/10 C
		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";
		printf ("$nagios_message\n");
	        nagios_exit "$nagstatus";
	} 
	elsif ($act eq 'onBattery'){

		if ($sta == 0){
			$nagstatus = "OK";
		} elsif ($sta == 1){
			$nagstatus = "WARNING";
		} 
		if ($sta == 0) {
		$nagios_message = "UPS is $nagstatus, running on city/generator power.";
		}
		else {
		$nagios_message = "UPS is on battery power.";
		}
		printf ("$nagios_message\n");
	        nagios_exit "$nagstatus";
	} 
	elsif ($act eq 'outputLoadPercent'){
		if ($war > $cri){
			$tmp = $war;
			$war = $cri;
			$cri = $tmp;
		}
		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 percent";
		printf ("$nagios_message\n");
        	nagios_exit "$nagstatus";

	} 
	elsif ($act eq 'bypassActive'){
		if ($sta == 0){
			$nagstatus = "OK";
			$nagios_message = "UPS is OK";
		} else {
			$nagstatus = "WARNING";
			$nagios_message = "UPS is currently in BYPASS";
		}
	printf ("$nagios_message\n");
        nagios_exit "$nagstatus";

	} 
	elsif ($act eq 'total_clients'){
	 	if ($sta == 0){
			$nagstatus = "WARNING";
			$nagios_message = "UPS has no registered clients";
		}else {
			$nagstatus = "OK";
			$nagios_message = "UPS has $sta registered clients";
		}

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

	}
	elsif ($act eq 'registered_clients') {
		if ($sta eq '\0') {
			$nagstatus = "WARNING";
			$nagios_message = "Unable to determine address of registered UPS clients";
		} else {
			$nagstatus = "OK";
			$nagios_message = "UPS has at least one registered client listed";
		       }
	}else {
		$nagstatus = "UNKNOWN";
		$nagios_message = "UPS State UNKNOWN.  Please check the command line syntax";
	printf ("$nagios_message\n");
        nagios_exit "$nagstatus";

	} 

	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 'replacebattery'){
		return $a;
	}
	  elsif ($a eq 'batteryMinRemaining'){
		return $a;
	} elsif ($a eq 'batterySeconds'){
		return $a;
	} elsif ($a eq 'batteryTemperature'){
		return $a;
	} 
          elsif ($a eq 'onBattery'){
                return $a;
        }
	 elsif ($a eq 'outputLoadPercent'){
		return $a;
	} elsif ($a eq 'bypassActive'){
                return $a;
	} elsif ($a eq 'total_clients'){
		return $a;
	} 
          elsif ($a eq 'registered_clients'){
                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	On failure (1)  indicates a battery has failed a periodic test \n";
	printf "   replacebattery	On failure (1), UPS has determined a battery needs replacing\n";
	printf "   batteryMinRemaining	Estimated minutes of battery runtime \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 "   onBattery	Is the UPS on battery\n";
	printf "   outputLoadPercent	Percentage of the current load of the Data Center compared to the capacity of the UPS\n";
	printf "   bypassActive		Check if the UPS is in Bypass mode.\n";
	printf "   total_clients	Total clients managed by the UPS.\n";
	printf "   registered_clients	IP addresses of the registered clients of the UPS.\n";
	printf "\nNote:\n";
	printf "     The Warning and Critical Thresholds should always be set UNLESS batteryStatus is selected\n";
        printf " But it looks like there is a bug the requires even nonsense values for batteryStatus or\n";
   	printf " there will be an 'uninitialized variable error\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";


