#!/usr/bin/perl # Copyright (C) 2017 Anthony Walters # # 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 3 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, see . # Author: Anthony Walters # Website: https://github.com/anthonywalters/check-upsmib-plugin use strict; use warnings; use Net::SNMP; use Getopt::Long; Getopt::Long::Configure('no_ignore_case'); # Plugin Info my $plugin_version_number = '0.1'; my $plugin_copyright_string = 'Copyright (c) 2017 Anthony Walters '; # Command line option variables my $opt_hostname; my $opt_snmp_community; my $opt_check_type; my $opt_snmp_version = 1; my $opt_snmp_port = 161; my $opt_version_flag; my $opt_help_flag; my $opt_warning_threshold; my $opt_critical_threshold; ###### Constants ############################################################## # Constants for the plugin return status use constant { OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3, }; # Human Friendly Constants for $oid_upsOutputSource use constant { OUTPUTSOURCE_OTHER => "1", OUTPUTSOURCE_NONE => "2", OUTPUTSOURCE_NORMAL => "3", OUTPUTSOURCE_BYPASS => "4", OUTPUTSOURCE_BATTERY => "5", OUTPUTSOURCE_BOOSTER => "6", OUTPUTSOURCE_REDUCER => "7" }; # Human Friendly Constants for $oid_upsBatteryStatus use constant { BATTERY_UNKNOWN => "1", BATTERY_NORMAL => "2", BATTERY_LOW => "3", BATTERY_DEPLETED => "4" }; ###### Plugin specific oids ################################################### # http://www.oidview.com/mibs/0/UPS-MIB.html # http://www.circitor.fr/Mibs/Html/UPS-MIB.php my $oid_upsIdentName = "1.3.6.1.2.1.33.1.1.5.0"; my $oid_upsAlarmsPresent = "1.3.6.1.2.1.33.1.6.1.0"; my $oid_upsBatteryStatus = "1.3.6.1.2.1.33.1.2.1.0"; my $oid_upsBatteryTemperature = "1.3.6.1.2.1.33.1.2.7.0"; my $oid_upsEstimatedChargeRemaining = "1.3.6.1.2.1.33.1.2.4.0"; my $oid_upsEstimatedMinutesRemaining = "1.3.6.1.2.1.33.1.2.3.0"; my $oid_upsSecondsOnBattery = "1.3.6.1.2.1.33.1.2.2.0"; my $oid_upsOutputSource = "1.3.6.1.2.1.33.1.4.1.0"; ###### Variables to hold the return values of the SNMP queries ################ my $upsIdentName; my $upsAlarmsPresent; my $upsBatteryStatus; my $upsBatteryTemperature; my $upsEstimatedChargeRemaining; my $upsEstimatedMinutesRemaining; my $upsSecondsOnBattery; my $upsOutputSource; ###### Variables used by the plugin code ###################################### my $plugin_return_status; my $plugin_return_string; my $plugin_perf_data_string; my $plugin_warning_threshold; my $plugin_critical_threshold; ############################################################################### ###### Program Start ########################################################## # Get the command line arguments get_arguments(); # If help inforation was asked for, print usage and exit if ($opt_help_flag) { print_usage(); exit 0; } # If version inforation was asked for, print version info and exit if ($opt_version_flag) { print_version_info(); exit 0; } # Check the command line arguments: hostname, community and check type must be defined. if (!defined $opt_hostname || !defined $opt_snmp_community || !defined $opt_check_type) { print_usage(); exit UNKNOWN; } # Set up the snmp session my ($snmp_session, $snmp_error) = Net::SNMP->session( -hostname => $opt_hostname, -community => $opt_snmp_community, -version => $opt_snmp_version, -port => $opt_snmp_port, ); # If the snmp session did not get set up, exit with a plugin status of UNKNOWN if (!defined($snmp_session)) { printf "ERROR: %s.\n", $snmp_error; exit UNKNOWN; } # Do the type of check that was requested via the command line options if (lc $opt_check_type eq 'alarmspresent') { do_check_on_AlarmsPresent(); } elsif (lc $opt_check_type eq 'batterystatus') { do_check_on_BatteryStatus(); } elsif (lc $opt_check_type eq 'batterytemperature') { do_check_on_BatteryTemperature(); } elsif (lc $opt_check_type eq 'estimatedchargeremaining') { do_check_on_EstimatedChargeRemaining(); } elsif (lc $opt_check_type eq 'estimatedminutesremaining') { do_check_on_EstimatedMinutesRemaining(); } elsif (lc $opt_check_type eq 'outputsource') { do_check_on_OutputSource(); } else { print "ERROR: Invalid CHECK_TYPE in command line arguments\n"; } # Close the snmp session $snmp_session->close(); # Now return a return status and string for use by nagios/icinga if (defined $plugin_return_status) { # Add a newline to the end of the output string $plugin_return_string .= "\n"; # Print the return string, and exit with a status code print $plugin_return_string; exit $plugin_return_status; } else { print "$0 : Failed to geterate a status value, exiting with UNKNOWN\n"; exit UNKNOWN; } ###### Program End ############################################################ ############################################################################### ###### Subroutines ############################################################ sub do_check_on_AlarmsPresent { # Check for the warning option, if not set, give a default value if (defined $opt_warning_threshold) { $plugin_warning_threshold = $opt_warning_threshold; } else { $plugin_warning_threshold = 1; } # Check for the critical option, if not set, give a default value if (defined $opt_critical_threshold) { $plugin_critical_threshold = $opt_critical_threshold; } else { $plugin_critical_threshold = 1; } # Query the ups for each oid that we are interested in $upsIdentName = get_snmp_value($oid_upsIdentName); $upsAlarmsPresent = get_snmp_value($oid_upsAlarmsPresent); # If the ups returned a value if (defined $upsAlarmsPresent) { # Check to see if the alarms present is a non-negative number, zero or greater if ($upsAlarmsPresent >= 0) { # Decide what return value this plugin will return with. if ($upsAlarmsPresent >= $plugin_critical_threshold ) { $plugin_return_status = CRITICAL; $plugin_return_string = "Status is CRITICAL: "; } elsif ($upsAlarmsPresent >= $plugin_warning_threshold ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: "; } else { $plugin_return_status = OK; $plugin_return_string = "Status is OK: "; } # The value is not a positive integer, set return status to unknown } else { $plugin_return_status = UNKNOWN; $plugin_return_string = "NOT A POSITIVE INTEGER: "; } $plugin_return_string .= $upsIdentName . " - " if (defined $upsIdentName); $plugin_return_string .= "Number of UPS alarms is " . $upsAlarmsPresent; # The ups failed to return a value, set the return status to unknown } else { $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is UNKNOWN: Could not contact snmp server"; } # Generate the perf data and add it to the return string if (defined $upsAlarmsPresent) { $plugin_perf_data_string = "upsAlarmsPresent=$upsAlarmsPresent"; $plugin_return_string .= " | " . $plugin_perf_data_string; } } sub do_check_on_BatteryStatus { # Check for the warning option, if not set, give a default value if (defined $opt_warning_threshold) { $plugin_warning_threshold = $opt_warning_threshold; } else { $plugin_warning_threshold = BATTERY_LOW; } # Check for the critical option, if not set, give a default value if (defined $opt_critical_threshold) { $plugin_critical_threshold = $opt_critical_threshold; } else { $plugin_critical_threshold = BATTERY_DEPLETED; } # Query the ups for each oid that we are interested in $upsIdentName = get_snmp_value($oid_upsIdentName); $upsBatteryStatus = get_snmp_value($oid_upsBatteryStatus); # If the ups returned a value if (defined $upsBatteryStatus) { # Decide what return value this plugin will return with. if ($upsBatteryStatus >= $plugin_critical_threshold ) { $plugin_return_status = CRITICAL; $plugin_return_string = "Status is CRITICAL: "; } elsif ($upsBatteryStatus >= $plugin_warning_threshold ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: "; } elsif ($upsBatteryStatus == BATTERY_NORMAL ) { $plugin_return_status = OK; $plugin_return_string = "Status is OK: "; } elsif ($upsBatteryStatus == BATTERY_UNKNOWN ) { $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is UNKNOWN: "; } else { $plugin_return_status = UNKNOWN; # unknown when the battery status is not valid. $plugin_return_string = "Status is NOT_VALID: "; } # Make the output more readable, translate the upsBatteryStatus code into english if ($upsBatteryStatus == BATTERY_UNKNOWN ) { $plugin_return_string .= 'Battery UNKNOWN - '; } elsif ($upsBatteryStatus == BATTERY_NORMAL ) { $plugin_return_string .= 'Battery NORMAL - '; } elsif ($upsBatteryStatus == BATTERY_LOW ) { $plugin_return_string .= 'Battery LOW - '; } elsif ($upsBatteryStatus == BATTERY_DEPLETED ) { $plugin_return_string .= 'Battery DEPLETED - '; } else { # Catchall for when the status is invalid, just print the value $plugin_return_string .= 'Battery Status ' . $upsBatteryStatus . ' - '; } # Add the name and raw value returned by the ups to the output string $plugin_return_string .= $upsIdentName . " - " if (defined $upsIdentName); $plugin_return_string .= "UPS returned a battery status of " . $upsBatteryStatus; # The ups failed to return a value } else { $plugin_return_status = UNKNOWN; #unknown if the snmp server did not answer $plugin_return_string = "Status is UNKNOWN: Could not contact snmp server"; } # Generate the perf data and add it to the return string if (defined $upsBatteryStatus) { $plugin_perf_data_string = "upsBatteryStatus=$upsBatteryStatus"; $plugin_return_string .= " | " . $plugin_perf_data_string; } } sub do_check_on_BatteryTemperature { # Check for the warning option, if not set, give a default value if (defined $opt_warning_threshold) { $plugin_warning_threshold = $opt_warning_threshold; } else { $plugin_warning_threshold = 26; } # Check for the critical option, if not set, give a default value if (defined $opt_critical_threshold) { $plugin_critical_threshold = $opt_critical_threshold; } else { $plugin_critical_threshold = 30; } # Query the ups for each oid that we are interested in $upsIdentName = get_snmp_value($oid_upsIdentName); $upsBatteryTemperature = get_snmp_value($oid_upsBatteryTemperature); # If the ups returned a value if (defined $upsBatteryTemperature) { # Check to see if the estimated minutes remaining is zero or greater if ($upsBatteryTemperature >= 0) { # Decide what return value this plugin will return with. if ($upsBatteryTemperature >= $plugin_critical_threshold ) { $plugin_return_status = CRITICAL; $plugin_return_string = "Status is CRITICAL: "; } elsif ($upsBatteryTemperature >= $plugin_warning_threshold ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: "; } elsif ($upsBatteryTemperature <= 15) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: "; } else { $plugin_return_status = OK; $plugin_return_string = "Status is OK: "; } # the value is not a positive integer, set the return status to unknown. } else { $plugin_return_status = UNKNOWN; $plugin_return_string = "Temperature returned from the UPS is NOT A POSITIVE INTEGER: "; } $plugin_return_string .= $upsIdentName . " - " if (defined $upsIdentName); $plugin_return_string .= "UPS battery temperature is " . $upsBatteryTemperature . " degrees"; # The ups failed to return a value, set the return status to unknwon } else { $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is UNKNOWN: Could not contact snmp server"; } # Generate the perf data and add it to the return string if (defined $upsBatteryTemperature) { $plugin_perf_data_string = "upsBatteryTemperature=$upsBatteryTemperature;$plugin_warning_threshold;$plugin_critical_threshold;;"; $plugin_return_string .= " | " . $plugin_perf_data_string; } } sub do_check_on_EstimatedChargeRemaining { # Check for the warning option, if not set, give a default value if (defined $opt_warning_threshold) { $plugin_warning_threshold = $opt_warning_threshold; } else { $plugin_warning_threshold = 50; } # Check for the critical option, if not set, give a default value if (defined $opt_critical_threshold) { $plugin_critical_threshold = $opt_critical_threshold; } else { $plugin_critical_threshold = 30; } # Query the ups for each oid that we are interested in $upsIdentName = get_snmp_value($oid_upsIdentName); $upsEstimatedChargeRemaining = get_snmp_value($oid_upsEstimatedChargeRemaining); $upsSecondsOnBattery = get_snmp_value($oid_upsSecondsOnBattery); # If the ups returned a value if (defined $upsEstimatedChargeRemaining) { # Check to see if the percentage value is between 0 and 100 if ($upsEstimatedChargeRemaining >= 0 && $upsEstimatedChargeRemaining <= 100) { # Decide what return value this plugin will return with. if ($upsEstimatedChargeRemaining <= $plugin_critical_threshold ) { $plugin_return_status = CRITICAL; $plugin_return_string = "Status is CRITICAL: "; } elsif ($upsEstimatedChargeRemaining <= $plugin_warning_threshold ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: "; } else { $plugin_return_status = OK; $plugin_return_string = "Status is OK: "; } } else { # the % value is not between 0 and 100, set the return status to unknown. $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is NOT A VALID PERCENTAGE: "; } $plugin_return_string .= $upsIdentName . " - " if (defined $upsIdentName); $plugin_return_string .= "UPS returned an estimated charge remaining of " . $upsEstimatedChargeRemaining . "%"; } else { # The ups failed to return a value $plugin_return_status = UNKNOWN; #return unknown if the snmp server did not answer $plugin_return_string = "Status is UNKNOWN: Could not contact snmp server"; } # Generate the perf data and add it to the return string if (defined $upsEstimatedChargeRemaining) { $plugin_perf_data_string = "upsEstimatedChargeRemaining=$upsEstimatedChargeRemaining%"; $plugin_perf_data_string .= " upsSecondsOnBattery=${upsSecondsOnBattery}s"; $plugin_return_string .= " | " . $plugin_perf_data_string; } } sub do_check_on_EstimatedMinutesRemaining { # Check for the warning option, if not set, give a default value if (defined $opt_warning_threshold) { $plugin_warning_threshold = $opt_warning_threshold; } else { $plugin_warning_threshold = 25; } # Check for the critical option, if not set, give a default value if (defined $opt_critical_threshold) { $plugin_critical_threshold = $opt_critical_threshold; } else { $plugin_critical_threshold = 15; } # Query the ups for each oid that we are interested in $upsIdentName = get_snmp_value($oid_upsIdentName); $upsEstimatedMinutesRemaining = get_snmp_value($oid_upsEstimatedMinutesRemaining); $upsSecondsOnBattery = get_snmp_value($oid_upsSecondsOnBattery); # If the ups returned a value if (defined $upsEstimatedMinutesRemaining) { # Check to see if the estimated minutes remaining is zero or greater if ($upsEstimatedMinutesRemaining >= 0) { # Decide what return value this plugin will return with. if ($upsEstimatedMinutesRemaining <= $plugin_critical_threshold ) { $plugin_return_status = CRITICAL; $plugin_return_string = "Status is CRITICAL: "; } elsif ($upsEstimatedMinutesRemaining <= $plugin_warning_threshold ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: "; } else { $plugin_return_status = OK; $plugin_return_string = "Status is OK: "; } # The value is not a positive integer, set the return status to unknown. } else { $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is NOT A POSITIVE INTEGER: "; } $plugin_return_string .= $upsIdentName . " - " if (defined $upsIdentName); $plugin_return_string .= "UPS returned estimated time remaining to depletion of " . $upsEstimatedMinutesRemaining . " minutes"; } else { # The ups failed to return a value, set the return status to unknown $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is UNKNOWN: Could not contact snmp server"; } # Generate the perf data and add it to the return string if (defined $upsEstimatedMinutesRemaining) { $plugin_perf_data_string = "upsEstimatedMinutesRemaining=$upsEstimatedMinutesRemaining;$plugin_warning_threshold;$plugin_critical_threshold;;"; $plugin_perf_data_string .= " upsSecondsOnBattery=${upsSecondsOnBattery}s"; $plugin_return_string .= " | " . $plugin_perf_data_string; } } sub do_check_on_OutputSource { # Note: warning and critical thresholds do not make sense for these checks # and so they are ignored even if they are defined. # Query the ups for each oid that we are interested in $upsIdentName = get_snmp_value($oid_upsIdentName); $upsOutputSource = get_snmp_value($oid_upsOutputSource); # If the ups returned a value if (defined $upsOutputSource) { # Decide what return value and string this plugin will return with. if ($upsOutputSource == OUTPUTSOURCE_OTHER ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: UPS Output OTHER - "; } elsif ($upsOutputSource == OUTPUTSOURCE_NONE ) { $plugin_return_status = CRITICAL; $plugin_return_string = "Status is CRITICAL: UPS Output NONE - "; } elsif ($upsOutputSource == OUTPUTSOURCE_NORMAL ) { $plugin_return_status = OK; $plugin_return_string = "Status is OK: UPS Output NORMAL - "; } elsif ($upsOutputSource == OUTPUTSOURCE_BYPASS ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: UPS Output BYPASS - "; } elsif ($upsOutputSource == OUTPUTSOURCE_BATTERY ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: UPS Output BATTERY - "; } elsif ($upsOutputSource == OUTPUTSOURCE_BOOSTER ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: UPS Output BOOSTER - "; } elsif ($upsOutputSource == OUTPUTSOURCE_REDUCER ) { $plugin_return_status = WARNING; $plugin_return_string = "Status is WARNING: UPS Output REDUCER - "; } else { $plugin_return_status = UNKNOWN; #return unknown when the status is not valid. $plugin_return_string = "Status is INVALID FROM THE UPS: "; } $plugin_return_string .= $upsIdentName . " - " if (defined $upsIdentName); $plugin_return_string .= "UPS returned an output source of " . $upsOutputSource; } else { # The ups failed to return a value, set the return status to unknown $plugin_return_status = UNKNOWN; $plugin_return_string = "Status is UNKNOWN: Could not contact snmp server"; } # Generate the perf data and add it to the return string if ($upsOutputSource) { $plugin_perf_data_string = "upsOutputSource=$upsOutputSource"; $plugin_return_string .= " | " . $plugin_perf_data_string; } } # Accepts a scalar $oid # Returns a scalar with the value of the snmp query # Returns undef when the snmp query fails sub get_snmp_value { my $oid = shift; my $hashref_result = $snmp_session->get_request( -varbindlist => [ $oid ], ); #Return undef on error, or the result of the snmp query if successful. if (!defined $hashref_result) { printf STDERR "ERROR: ", $snmp_session->error(); return undef; } else { return $hashref_result->{$oid}; } } sub print_usage { print "SUMMARY\n"; print " This plugin queries upsMIB compatible UPS over snmp v1 or v2 for monitoring purposes\n"; print "USAGE\n"; print " $0 -T CHECK_TYPE -H HOST -C COMMUNITY [OPTIONS]\n"; print "OPTIONS\n"; print " -T CHECK_TYPE, --checktype=CHECK_TYPE\n"; print " -H HOST, --hostname=HOST\n"; print " -C COMMUNITY, --community=COMMUNITY\n"; print " -p PORT, --port=PORT\n"; print " -s SNMP_VERSION, --snmpversion=SNMP_VERSION\n"; print " -w THRESHOLD, --warning=THRESHOLD\n"; print " -c THRESHOLD, --critical=THRESHOLD\n"; print " -h, --help\n"; print " -V, --version\n"; print "CHECK_TYPE Check type can be one of the following:\n"; print " AlarmsPresent\n"; print " BatteryStatus\n"; print " BatteryTemperature\n"; print " EstimatedChargeRemaining\n"; print " EstimatedMinutesRemaining\n"; print " OutputSource\n"; } sub print_version_info { print 'check_upsmib plugin Version ' . $plugin_version_number . "\n"; print $plugin_copyright_string . "\n"; } sub get_arguments { #get options docs: https://www.monitoring-plugins.org/doc/guidelines.html#PLUGOPTIONS my $status = GetOptions( "checktype|T=s" => \$opt_check_type, "hostname|H=s" => \$opt_hostname, "community|C=s" => \$opt_snmp_community, "version|V" => \$opt_version_flag, "port|p=i" => \$opt_snmp_port, "snmpversion|s=i" => \$opt_snmp_version, "warning|w=i" => \$opt_warning_threshold, "critical|c=i" => \$opt_critical_threshold, "help|h" => \$opt_help_flag, ) or die("Error in command line arguments\n"); }