#!/bin/bash # # check_apcupsd_ng 2.0 # # Nagios plugin to monitor APC Smart-UPSes using apcupsd. # Modified from Martin Toft's check_apcupsd 1.2 by Ben Shephard # http://bshephard.com/?p=1119 # # Modified by fabricat (August 2011): # - added "all" option (unique output summarizing all check results) # # Copyright (c) 2008 Martin Toft # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # # Example configuration # # commands.cfg: # # define command { # command_name check_apcupsd # command_line $USER1$/check_apcupsd -w $ARG2$ -c $ARG3$ $ARG1$ # } # # define command { # command_name check_apcupsd_no_notify # command_line $USER1$/check_apcupsd $ARG1$ # } # # ups1.cfg: # # define service { # use generic-service # host_name ups1 # service_description CHARGE # check_command check_apcupsd!bcharge!95!50 # } # # define service { # use generic-service # host_name ups1 # service_description TEMP # check_command check_apcupsd!itemp!35!40 # } # # define service { # use generic-service # host_name ups1 # service_description LOAD # check_command check_apcupsd!loadpct!70!85 # } # # define service { # use generic-service # host_name ups1 # service_description TIMELEFT # check_command check_apcupsd_no_notify!timeleft # } # #define service { # use generic-service # host_name ups1 # service_description BATTERY VOLTAGE # check_command check_apcupsd!battv!25!24 # } # #define service { # use generic-service # host_name ups1 # service_description LINE VOLTAGE # check_command check_apcupsd!linev!245!250 # } # #define service { # use generic-service # host_name ups1 # service_description OUTPUT VOLTAGE # check_command check_apcupsd!outputv!245!250 # } # #define service { # use generic-service # host_name ups1 # service_description LINE FREQUENCY # check_command check_apcupsd!linefreq!51!52 # } # # PROGNAME=`basename $0` PROGPATH=`dirname $0` REVISION="2.0" . $PROGPATH/utils.sh APCACCESS=/sbin/apcaccess usage() { echo "" echo "usage: $PROGNAME [-h hostname] [-p port] [-v]" echo " [-w warning_value] [-c critical_value]" echo " [-x test_to_exclude] [-x test_to_exclude] ..." echo " " echo "" echo " NB1: hostname and port defaults to localhost and 3551, respectively." echo " NB2: warning_value and critical_value ignored when running \"all\" checks." echo " NB3: exclusions are valid only when selecting \"all\" checks." echo "" echo "checks:" echo " all = All the available checks." echo " bcharge = Battery charge, measured in percent." echo " itemp = Internal temperature, measured in degree Celsius." echo " loadpct = Load, measured in percent." echo " timeleft = Time left with current battery charge and load," echo " measured in minutes." echo " linev = Line voltage." echo " battv = Battery voltage." echo " outputv = UPS output voltage." echo " linefreq = Line frequency." echo " battdate = Battery replacement date (specify warning_value" echo " and critical_value in months)." echo "" exit $STATE_UNKNOWN } checkCheck() { if [ "$ARG" = "all" ] then index=0 while [ "$index" -lt "${#EXCLUSIONS[*]}" ] do if [ "${EXCLUSIONS[$index]}" = "$1" ] then return 1 fi ((index++)) done return 0 else return [ "$ARG" = "$1" ] fi } getValue() { VALUE=`echo "$FULLSTATUS" | grep -i "^$1 *:" | \ sed 's/.*: *\([-0-9][0-9.]*\)[^0-9].*/\1/'` if [ "$VALUE" != "0" ]; then VALUE=`echo $VALUE | sed 's/^0*//'` fi ROUNDED=`echo $VALUE | sed 's/\..*//'` FULLSTATUS=`echo "$FULLSTATUS" | grep -vi "^$1 *:"` } getString() { STRING=`echo "$FULLSTATUS" | grep -i "^$1 *:" | cut -d':' -f2-` STRING=${STRING%% } STRING=${STRING## } FULLSTATUS=`echo "$FULLSTATUS" | grep -vi "^$1 *:"` } HOSTNAME=localhost PORT=3551 DETAILS_SEPARATOR=" ##" EXCLUSIONS=() while getopts c:h:p:vw:x: OPTNAME; do case "$OPTNAME" in h) HOSTNAME="$OPTARG";; p) PORT="$OPTARG";; w) WARNVAL="$OPTARG";; c) CRITVAL="$OPTARG";; v) VERBOSE="INFO: ";; x) EXCLUSIONS[${#EXCLUSIONS[*]}]="$OPTARG";; *) usage;; esac done ARG="$@" while [ $OPTIND -gt 1 ]; do ARG=`echo "$ARG" | sed 's/^[^ ][^ ]* *//'` OPTIND=$(($OPTIND-1)) done if [ "$ARG" != "bcharge" -a "$ARG" != "itemp" -a "$ARG" != "loadpct" \ -a "$ARG" != "timeleft" -a "$ARG" != "linev" -a "$ARG" != "battv" \ -a "$ARG" != "outputv" -a "$ARG" != "linefreq" -a "$ARG" != "all" ] then usage fi if [ "`echo $PORT | grep '^[0-9]\{1,5\}$'`" = "" ]; then echo "Error: port must be a positive integer!" exit $STATE_UNKNOWN fi if [ "$WARNVAL" != "" -a "`echo $WARNVAL | grep '^[0-9]*$'`" = "" ]; then echo "Error: warning_value must be a positive integer!" exit $STATE_UNKNOWN fi if [ "$CRITVAL" != "" -a "`echo $CRITVAL | grep '^[0-9]*$'`" = "" ]; then echo "Error: critical_value must be a positive integer!" exit $STATE_UNKNOWN fi if [ "$WARNVAL" != "" -a "$CRITVAL" != "" ]; then if [ "$ARG" = "bcharge" -o "$ARG" = "battv" -o "$ARG" = "battdate" -o "$ARG" = "timeleft" ]; then if [ $WARNVAL -le $CRITVAL ]; then echo "Error: warning_value must be greater than critical_value!" exit $STATE_UNKNOWN fi else if [ $WARNVAL -ge $CRITVAL ]; then echo "Error: warning_value must be less than critical_value!" exit $STATE_UNKNOWN fi fi fi if [ ! -x "$APCACCESS" ]; then echo "Error: $APCACCESS must exist and be executable!" exit $STATE_UNKNOWN fi $APCACCESS status $HOSTNAME:$PORT > /dev/null if [ $? -ne 0 ]; then # The error message from apcaccess will do fine. exit $STATE_UNKNOWN fi FULLSTATUS=`$APCACCESS status $HOSTNAME:$PORT` ISSUECRIT="" ISSUEWARN="" ISSUEOK="" STATS="" CAUSE="" getString "UPSNAME" MSG="${DETAILS_SEPARATOR}UPS ${STRING}" getString "MODEL" MSG=${MSG}" (${STRING}, " getString "SERIALNO" MSG=${MSG}"s/n: ${STRING})" getString "LASTXFER" LASTXFER="${STRING}" getString "XONBATT" if [ -z "$STRING" ]; then STRING="N/A"; fi LASTXFER="\"${LASTXFER}\" from ${STRING}" getString "STATUS" MSG="${MSG} is ${STRING} " if [ "$STRING" = "COMMLOST" ]; then echo "Error: communication lost! (cable disconnected?)" exit $STATE_UNKNOWN elif [ "$STRING" != "ONLINE" ] && ! expr match "$LASTXFER" '.*self test.*' > /dev/null; then # issues a Warning when UPS is on battery, except if the cause is a self test if [ "${STRING:0:6}" == "ONLINE" ]; then ISSUEWARN="${ISSUEWARN}${MSG}" else ISSUEWARN="${ISSUEWARN}${MSG}(caused by ${LASTXFER}) " fi else ISSUEOK=${ISSUEOK}${MSG} getString "XOFFBATT" LASTXFER="${LASTXFER} to ${STRING}" CAUSE="(caused by ${LASTXFER}) " fi #if [ "$ARG" = "bcharge" -o "$ARG" = "all" ]; then if ( checkCheck "bcharge" ) then getValue "bcharge" if [ "$ARG" = "all" ]; then CRITVAL=50 WARNVAL=95 fi STATS=${STATS}"battcharge=${VALUE}% " MSG="${DETAILS_SEPARATOR}Battery Charge: ${VALUE}% " if [ "$CRITVAL" != "" -a $ROUNDED -lt $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG}${CAUSE} elif [ "$WARNVAL" != "" -a $ROUNDED -lt $WARNVAL ]; then if ! expr match "$LASTXFER" '.*self test.*' > /dev/null; then ISSUEWARN=${ISSUEWARN}${MSG}${CAUSE} else ISSUEOK=${ISSUEWARN}${MSG}${CAUSE} fi else VERBOSE="${VERBOSE}${MSG}${DETAILS_SEPARATOR}Last battery transfer: ${LASTXFER} " fi fi #if [ "$ARG" = "itemp" -o "$ARG" = "all" ]; then if ( checkCheck "itemp" ) then getValue "itemp" if [ "$ARG" = "all" ]; then CRITVAL=40 WARNVAL=35 fi STATS=${STATS}"temp=${VALUE} " MSG="${DETAILS_SEPARATOR}Internal Temperature: ${VALUE}C " if [ "$CRITVAL" != "" -a $ROUNDED -ge $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -ge $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "loadpct" -o "$ARG" = "all" ]; then if ( checkCheck "loadpct" ) then getValue "loadpct" if [ "$ARG" = "all" ]; then CRITVAL=85 WARNVAL=70 fi STATS=${STATS}"load=${VALUE}% " MSG="${DETAILS_SEPARATOR}Load: ${VALUE}% " if [ "$CRITVAL" != "" -a $ROUNDED -ge $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -ge $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "timeleft" -o "$ARG" = "all" ]; then if ( checkCheck "timeleft" ) then getValue "timeleft" if [ "$ARG" = "all" ]; then CRITVAL=8 WARNVAL=10 fi STATS=${STATS}"minleft=${VALUE} " MSG="${DETAILS_SEPARATOR}Time Left: ${VALUE}m " if [ "$CRITVAL" != "" -a $ROUNDED -lt $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -lt $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "linev" -o "$ARG" = "all" ]; then if ( checkCheck "linev" ) then getValue "linev" if [ "$ARG" = "all" ]; then CRITVAL=242 WARNVAL=238 fi STATS=${STATS}"linevolt=${VALUE} " MSG="${DETAILS_SEPARATOR}Line Voltage: ${VALUE}V " if [ "$CRITVAL" != "" -a $ROUNDED -ge $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -ge $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "battv" -o "$ARG" = "all" ]; then if ( checkCheck "battv" ) then getValue "battv" if [ "$ARG" = "all" ]; then CRITVAL=25 WARNVAL=35 fi STATS=${STATS}"battvolt=${VALUE} " MSG="${DETAILS_SEPARATOR}Battery Voltage: ${VALUE}V " if [ "$CRITVAL" != "" -a $ROUNDED -le $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -le $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "outputv" -o "$ARG" = "all" ]; then if ( checkCheck "outputv" ) then getValue "outputv" if [ "$ARG" = "all" ]; then CRITVAL=242 WARNVAL=238 fi STATS=${STATS}"outvolt=${VALUE} " MSG="${DETAILS_SEPARATOR}Output Voltage: ${VALUE}V " if [ "$CRITVAL" != "" -a $ROUNDED -ge $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -ge $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "linefreq" -o "$ARG" = "all" ]; then if ( checkCheck "linefreq" ) then getValue "linefreq" if [ "$ARG" = "all" ]; then CRITVAL=52 WARNVAL=51 fi STATS=${STATS}"linefreq=${VALUE} " MSG="${DETAILS_SEPARATOR}Line Frequency: ${VALUE}Hz " if [ "$CRITVAL" != "" -a $ROUNDED -ge $CRITVAL ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNVAL" != "" -a $ROUNDED -ge $WARNVAL ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi #if [ "$ARG" = "battdate" -o "$ARG" = "all" ]; then if ( checkCheck "battdate" ) then getString "battdate" if [ "$ARG" = "all" ]; then CRITVAL=60 WARNVAL=36 fi MSG="${DETAILS_SEPARATOR}Battery replacement date: ${STRING} " BATTDATE=`date -d "${STRING}" +"%Y%m%d"` if [ "$CRITVAL" != "" ]; then CRITDATE=`date -d "${CRITVAL} months ago" +"%Y%m%d"` fi if [ "$WARNVAL" != "" ]; then WARNDATE=`date -d "${WARNVAL} months ago" +"%Y%m%d"` fi if [ "$CRITDATE" != "" -a $BATTDATE -le $CRITDATE ]; then ISSUECRIT=${ISSUECRIT}${MSG} elif [ "$WARNDATE" != "" -a $BATTDATE -le $WARNDATE ]; then ISSUEWARN=${ISSUEWARN}${MSG} else VERBOSE=${VERBOSE}${MSG} fi fi # let's remove some redundant output for i in "APC" "DATE" "HOSTNAME" "VERSION" "UPSMODE" "STARTTIME" "DSHUTD" "END APC"; do getString "$i" done RETSTATE=$STATE_OK if [ -n "$ISSUECRIT" ]; then echo -n "CRITICAL: $ISSUECRIT - " RETSTATE=$STATE_CRITICAL fi if [ -n "$ISSUEWARN" ]; then echo -n "WARNING: $ISSUEWARN - " if [ "$RETSTATE" -lt "$STATE_WARNING" ]; then RETSTATE=$STATE_WARNING fi fi if [ -n "$ISSUEOK" ]; then echo -n "OK: $ISSUEOK" fi if [ "${VERBOSE:0:5}" = "INFO:" ]; then echo -n " - ${VERBOSE}" else FULLSTATUS="INFO:${VERBOSE}\n\n${FULLSTATUS}" fi echo " | $STATS" echo "" echo -e "$FULLSTATUS" exit $RETSTATE