#! /usr/bin/perl
###############################################################################
#                                                                             #
#               Check an PowerWare UPS' EMP device via SNMP                   #
#                                                                             #
###############################################################################
#
# Copyright (c) 2005 Simon Butcher <simon@butcher.name>
#  
# 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
#
##############################################################################
#
#
# Performance data:
#    +-------+-----------------------------------------------+
#    | Field | Description                                   |
#    +-------+-----------------------------------------------+
#    |   1   | Remote temperature (degrees celcius)          |
#    |   2   | Remote humidity (percent)                     |
#    |   3   | Contact 1                                     |
#    |  ...  | ...                                           |
#    |   n   | Contact n                                     |
#    +-------+-----------------------------------------------+
#
##############################################################################


use Net::SNMP;
use Getopt::Std;

$script = "check_snmp_powerware_xups_emp";
$script_title =
  "Check an PowerWare UPS' EMP device via SNMP";
$script_version = "20051203";

# SNMP options
$version = "1";
$timeout = 2;

# Various SNMP OID prefixes to look at..
$oid_xups_emp_temp      = ".1.3.6.1.4.1.534.1.6.5"; # degrees celcius
$oid_xups_emp_humidity  = ".1.3.6.1.4.1.534.1.6.6"; # percent
$oid_xups_emp_contacts  = ".1.3.6.1.4.1.534.1.6.7"; # number of contacts
$oid_xups_emp_conttable = ".1.3.6.1.4.1.534.1.6.8.1.3."; # contacts

# The information we returned
$xups_emp_temp = 0;
$xups_emp_humidity = 0;
$xups_emp_contacts = 0;

# Thresholds
$critical_temp = -1;
$warning_temp = -1;
$critical_humidity_max = -1;
$warning_humidity_max = -1;
$critical_humidity_min = -1;
$warning_humidity_min = -1;

# Our return status - we start with 0 (OK) and hope for the best
$status = 0;

# Our return string with lots of interesting stuff in it
$returnstr = "";

# The SNMP hostname and community to use for the query
$hostname = "";
$community = "public";


# Grab the command line options
getopts("h:H:C:w:c:");

# If we didn't get any options, show some help and quit
if ($opt_h){
    usage();
    exit(-1); # Unknown
}

# Get the hostname, if it was given..
if (defined($opt_H)){
    $hostname = $opt_H;
} else {
    # We really need a hostname
    usage();
    exit(-1); # Unknown
}

# Get the SNMP community
if (defined($opt_C)){
    $community = $opt_C;
}

# Grab the warning thresholds
if (defined($opt_w)) {
    my @warning = split(/\,/, $opt_w);

    if (!($warning[0] eq "")) {
        $warning_temp = $warning[0];
    }
    if (!($warning[1] eq "")) {
	$warning_humidity_max = $warning[1];
    }
    if (!($warning[2] eq "")) {
	$warning_humidity_min = $warning[2];

	# If we also have the maximum humidity value, make sure it is higher
	# than the minimum
	if (($warning_humidity_max != -1) &&
	    ($warning_humidity_max < $warning_humidity_min)) {
	    print "Warning humidity maximum is lower than the minimum!\n";
	    exit(-1); # Unknown
	}
    }
}

# Grab the critical thresholds
if (defined($opt_c)) {
    my @critical = split(/\,/, $opt_c);

    if (!($critical[0] eq "")) {
        $critical_temp = $critical[0];
    }	
    if (!($critical[1] eq "")) {
	$critical_humidity_max = $critical[1];
    }
    if (!($critical[2] eq "")) {
	$critical_humidity_min = $critical[2];

	# If we also have the maximum humidity value, make sure it is higher
	# than the minimum
	if (($critical_humidity_max != -1) &&
	    ($critical_humidity_max < $critical_humidity_min)) {
	    print "Critical humidity maximum is lower than the minimum!\n";
	    exit(-1); # Unknown
	}
    }
}

# If we have both temperature thresholds, make sure the critical is higher than
# the warning
if (($warning_temp != -1) &&
    ($critical_temp != -1) &&
    ($warning_temp > $critical_temp)) {
    print "Critical temperature is lower than warning temperature!\n";
    exit(-1); # Unknown
}

# If we have both the humidity maximum thresholds, make sure the critical is
# higher than the warning
if (($warning_humidity_max != -1) &&
    ($critical_humidity_max != -1) &&
    ($warning_humidity_max > $critical_humidity_max)) {
    print "Critical humidity maximum is lower than warning maximum!\n";
    exit(-1); # Unknown
}

# If we have both the humidity minimum thresholds, make sure the critical is
# lower than the warning
if (($warning_humidity_min != -1) &&
    ($critical_humidity_min != -1) &&
    ($warning_humidity_min < $critical_humidity_min)) {
    print "Critical humidity minimum is higher than warning maximum!\n";
    exit(-1); # Unknown
}

# Initialise the SNMP session via the Net::SNMP perl module
my ($snmp_session, $snmp_error) = Net::SNMP->session(
    -community => $community,
    -hostname => $hostname,
    -version => $version,
    -timeout => $timeout,
);

# Grab interesting details
check_device();
    
# Shut down the SNMP session
$snmp_session->close();

# Return the return string and return status
print "$returnstr\n";
exit($status);


##############################################################################
##############################################################################
#
# Change the status level
#
sub status {
    my $newstatus = $_[0];

    # If the new status is greater than the old status, change the old status
    if ($newstatus > $status) {
	$status = $newstatus;
    }
}


##############################################################################
##############################################################################
#
# Grab a value from snmp
#
sub grab_snmp_value {
    my $this_oid = $_[0];
    my $this_value = "";

    # Try to grab the OID's value, if it exists
    if (defined($snmp_session->get_request($this_oid))) {
        foreach ($snmp_session->var_bind_names()) {
            $this_value = $snmp_session->var_bind_list()->{$_};
        }
    }

    # Return the value we got..
    return $this_value;
}


##############################################################################
##############################################################################
#
# Grab lots of interesting info about the device
#
sub check_device {
    # Grab some values
    $xups_emp_temp = grab_snmp_value($oid_xups_emp_temp);
    $xups_emp_humidity = grab_snmp_value($oid_xups_emp_humidity);
    $xups_emp_contacts = grab_snmp_value($oid_xups_emp_contacts);

    # If we have the remote temperature, add it to the output
    if (!($xups_emp_temp eq "")) {
	# Have we broken a threshold?
	if (($critical_temp != -1) &&
	    ($xups_emp_temp >= $critical_temp)) {
	    status(2); # Critical
	    $returnstr = "Critical: ";
	} elsif (($warning_temp != -1) &&
		 ($xups_emp_temp >= $warning_temp)) {
	    status(1); # Warning
	    $returnstr = "Warning: ";
	}

	# Add the temperature
	$returnstr = 
	    "$returnstr" .
	    "Temperature: $xups_emp_temp C"; # &#2451; or &#x2103; ?
    } else {
	status(2); # Critical
	$returnstr = "Temperature Unavailable";
    }

    if (($xups_emp_humidity ne "") &&
	($xups_emp_humidity >= 0) &&
        ($xups_emp_humidity <= 100)) {
	# Have we broken a threshold?
	if ((($critical_humidity_max != -1) &&
	     ($xups_emp_humidity > $critical_humidity_max)) ||
	    (($critical_humidity_min != -1) &&
	     ($xups_emp_humidity < $critical_humidity_min))) {
	    status(2); # Critical
	    $returnstr = "$returnstr, Critical:";
	} elsif ((($warning_humidity_max != -1) &&
		  ($xups_emp_humidity > $warning_humidity_max)) ||
		 (($warning_humidity_min != -1) &&
		  ($xups_emp_humidity < $warning_humidity_min))) {
	    status(1); # Warning
	    $returnstr = "$returnstr, Warning:";
	} else {
	    $returnstr = "$returnstr,";
	}

	$returnstr =
	    "$returnstr " .
	    "Humidity: $xups_emp_humidity\%";
    }

    # Add on some performance monitoring stuff to the return string :)
    $returnstr =
	"$returnstr" .
	"|$xups_emp_temp;$xups_emp_humidity" .
	";";

    # Iterate over the contacts and output their values
    for (my $c = 1; $c <= $xups_emp_contacts; $c++) {
	my $oid = $oid_xups_emp_conttable . $c;
	my $value = grab_snmp_value($oid);

	if (($value == 2) ||     # closed
	    ($value == 4)) {     # closed with notice
	    $boolvalue = 1;
        } else {
	    $boolvalue = 0;
        }

	$returnstr =
	    "$returnstr" .
	    "$boolvalue;";
    }    
}


##############################################################################
##############################################################################
#
# Usage information
#
sub usage {
    print << "USAGE";
$script ($script_version)
Copyright (c) 2005 Simon Butcher <simon@butcher.name>

$script_title

Usage: $script -H <hostname> [-C <community>]
            [-w <temp>,<hMax>,<hMin>] [-c <temp>,<hMax>,<hMin>]

Options:
    -H 	Hostname or IP address of the PowerWare UPS
    -C 	SNMP read community (default is $community)
    -w  Warning level for temperature max and humidity max/min
    -c  Critical level for temperature max and humidity max/min
        For example: 30 degrees, between 15% and 75% humidity = "30,75,15"

USAGE
     exit(-1); # Unknown
}
