From eec9de90b3243339158fcd756a4d35d13c529bdd Mon Sep 17 00:00:00 2001 From: Florian Lechner Date: Tue, 27 Mar 2012 14:17:15 +0200 Subject: [PATCH] inital commit --- plugins/environmental/snmp__poseidon-sensors | 402 +++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100755 plugins/environmental/snmp__poseidon-sensors diff --git a/plugins/environmental/snmp__poseidon-sensors b/plugins/environmental/snmp__poseidon-sensors new file mode 100755 index 00000000..08cc7072 --- /dev/null +++ b/plugins/environmental/snmp__poseidon-sensors @@ -0,0 +1,402 @@ +#!/bin/bash +#==============================================================================# +# # +# Check the sensor status of HW Group Poseidon family. For more info refer to:# +# http://www.hw-group.com/products/poseidon/poseidon_3268_en.html # +# 2012 by Florian Lechner (flo-github@catbull.com) # +# # +#==============================================================================# +# # +# 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, see . # +# # +#==============================================================================# +# # +# This plugin requires snmpget to work propperly # +# # +#==============================================================================# + +# Munin autoconf and snmpautoconf magic +#%# family=auto snmpauto contrib +#%# capabilities=snmpconf + +#==============================================================================# +# Config Section # +#==============================================================================# + +# SNMP Config +MIBS=":" # we don't use any configured MIBs so we don't + #+ have to deal with errors in the MIBs +SNMPVERSION="1" # as of firmware 3.1.5 only SNMPv1 is supported +SNMPCOMUNITY="public" # SNMP community string to read from the device + +#==============================================================================# +# No configuration beyonde this line! # +#==============================================================================# + +E_OK="0" # everything went allright +E_UNKNOWN="1" # "catch all" for otherwise unhandled errors + +E_ARG="81" # invalid argument +E_USAGE="82" # wrong program name or arguments +E_SNMPGET="83" # error while executing the 'snmpget' utility + +E_ICINGA_OK="0" # Icinga exitcodes for states 'ok', +E_ICINGA_WARN="1" #+ 'warning', and +E_ICINGA_CRIT="2" #+ 'critical' + +E_COMMANDNOTFOUND="127" # unable to locate binary + +#==============================================================================# +# SNMP OIDs from the Poseidon MIB # +#==============================================================================# + +SYS_LOC_OID=".1.3.6.1.2.1.1.6.0" # SNMP-location +SYS_NAME_OID=".1.3.6.1.2.1.1.5.0" # device name (string) +SYS_DESCR_OID=".1.3.6.1.2.1.1.1" # text describing the device +SYS_UPTIME_OID=".1.3.6.1.2.1.1.3.0" # time(in tens of milliseconds + #+ since the last reboot +IN_NAME_OID=".1.3.6.1.4.1.21796.3.3.1.1.3." # binary input name (string) +IN_STATE_OID=".1.3.6.1.4.1.21796.3.3.1.1.2." # binary input states(integer) +IN_ALARM_OID=".1.3.6.1.4.1.21796.3.3.1.1.4." # alarm for the binary input, + #+ generated by the device + #+ under defined conditions + #+ 0=Invalid, 1=Normal, + #+ 2=AlarmState, 3=Alarm +SENS_NAME_OID=".1.3.6.1.4.1.21796.3.3.3.1.2." # sensor name (string) +SENS_STATE_OID=".1.3.6.1.4.1.21796.3.3.3.1.4." # binary input states(integer) +SENS_VALUE_OID=".1.3.6.1.4.1.21796.3.3.3.1.6." # integer (decimal * 10) +SENS_ID_OID=".1.3.6.1.4.1.21796.3.3.99.1.2.1.4." # unique sensor ID (integer) + #+ representation of the + #+ temperature (integer) +SENS_UNIT_OID=".1.3.6.1.4.1.21796.3.3.3.1.9." # 0=°C,1=°F,2=°K,3=%,4=V,5=mA, +RTS_OUTPUT_OID=".1.3.6.1.4.1.21796.3.3.2.1.2." # binary input state (integer) + #+ 6=unknown, 7=pulse, 8=switch + +# define some Poseidon specific stuff: +STATE_OK="1" +STATE_WARN="2" +STATE_CRIT="3" +UNITS=("C" "F" "K" "%" "V" "mA" "unknown" "pulse" "switch") +TYPES=("Temp" "Temp" "Temp" "Hum" "Volt" "Curr" "Unkn" "Pulse" "Switch") + +declare -A sensorsOfType +IFS=" +" + +#==============================================================================# + +# printIcingaStatus (sensorNumber) +# print status output for icinga/icinga +printIcingaStatus () { + _sensorNumber="$1" + getSensorData $_sensorNumber + _name="$sensorType$_sensorNumber" # long name + _value="$(($sensorValue/10)),$(($sensorValue%10))" # decimal rep. + + if [ "$sensorState" = "$STATE_OK" ]; then + echo "$_name OK - $sensorName is $_value $sensorUnit." + return $E_ICINGA_OK + else + echo "$_name Critical - $sensorName is "$_value $sensorUnit"." + return $E_ICINGA_CRIT + fi +} + +# printMuninConfig () +# print output for munin auto configuration +printMuninConfig () { + if [ ! $hostAddr = 'localhost' ]; then + cat <<- EOT +host_name $hostAddr +EOT + fi + + for ((_sensorType=0; _sensorType<=${#UNITS[*]};_sensorType++)); do + # skip graphs without sensors + if [ -z "${sensorsOfType[$_sensorType]}" ]; then + continue + fi + + _firstSensor="1" + # print specific config for each sensor + for _sensorNr in ${sensorsOfType[$_sensorType]}; do + getSensorData $_sensorNr + getSystemInfo + + if [ $_firstSensor = "1" ]; then + # graph headers + cat <<- EOT +multigraph $sensorType +graph_title $sensorLocation - $sensorType [$sensorUnit] +graph_args --base 1000 -l 0 +graph_vlabel $sensorUnit +graph_category environment +graph_info This graph shows $sensorType history. +EOT + fi + _firstSensor="0" + cat <<- EOT +$sensorType$_sensorNr.label $sensorName +$sensorType$_sensorNr.info This graph shows $sensorType$_sensorNr history. +$sensorType$_sensorNr.draw LINE2 +EOT + done + done +} + +# printMuninSnmpConfig () +# print output for munin snmp auto configuration +printMuninSnmpConfig () { + cat <<- EOT +require $SENS_VALUE_OID$sensorNumber [0-9] +require $SENS_STATE_OID$sensorNumber +EOT + return 0; +} + +# printMuninStatus () +# print status output for munin +printMuninStatus () { + for ((_sensorType=0; _sensorType<=${#UNITS[*]};_sensorType++)); do + # skip graphs without sensors + if [ -z "${sensorsOfType[$_sensorType]}" ]; then + continue + fi + _firstSensor="1" + + # print config section + for _sensorNr in ${sensorsOfType[$_sensorType]}; do + getSensorData $_sensorNr + if [ $_firstSensor = "1" ]; then + # graph headers + cat <<- EOT +multigraph $sensorType +EOT + fi + _firstSensor="0" + + # print graph details + cat <<- EOT +$sensorType$_sensorNr.value $(( $sensorValue / 10 )) +EOT + done + echo "" + done +} + +# getSensorData(sensorNr) +# fetch state, value, name unit and sensor type for the sensor +#+ with the number "sensorNr" +getSensorData() { + _sensorNr=$1 + sensorState=`snmpGet $hostAddr $SENS_STATE_OID$_sensorNr || err \ + "Fatal: snmpget failed with code \"$?\"! Exiting..." $E_SNMPGET` + sensorValue=`snmpGet $hostAddr $SENS_VALUE_OID$_sensorNr || err \ + "Fatal: snmpget failed with code \"$?\"! Exiting..." $E_SNMPGET` + sensorName=`snmpGet $hostAddr $SENS_NAME_OID$_sensorNr || err \ + "Fatal: snmpget failed with code \"$?\"! Exiting..." $E_SNMPGET` + sensorUnit=`getSensorUnitString $_sensorNr` + sensorType=`getSensorType $_sensorNr` +} + +# getSystemInfo() +# fetch general information about the system +getSystemInfo() { + sensorLocation="`snmpGet $hostAddr $SYS_LOC_OID`" +} + +# snmpGet (hostAddr, OID) +# use snmpget to fetch a given OID, using above configuration +snmpGet () { + _oid="$2" + + _host="$1" + _exit="0" + + # fetch the requested OID + _longValue="`snmpget -O v\ + -m $MIBS\ + -v $SNMPVERSION\ + -c $SNMPCOMUNITY\ + $_host $_oid 2>/dev/null`" + + _exitStatus="$?" + + echo ${_longValue#*:} # remove the type from the answer + return $_exitStatus +} + +# get unit (string) +#+ find out the unit of the output of a given sensor. possible units are: +#+ "C" "F" "K" "%" "V" "mA" "unknown" "pulse" "switch" +getSensorUnitString () { + _sensorNr=$1 + _sensorUnit=`snmpGet $hostAddr $SENS_UNIT_OID$_sensorNr || err \ + "Fatal: snmpget failed with code \"$?\"! Exiting..." $E_SNMPGET` + echo ${UNITS[$_sensorUnit]} +} + +# get type (string) +#+ find out what type of sensor we are dealing with. possible types are: +#+ "Temp" "Hum" "Volt" "Curr" "Unkn" "Pulse" "Switch" +getSensorType () { + _sensorNr=$1 + _sensorUnit=`snmpGet $hostAddr $SENS_UNIT_OID$_sensorNr || err \ + "Fatal: snmpget failed with code \"$?\"! Exiting..." $E_SNMPGET` + echo ${TYPES[$_sensorUnit]} +} + +# getAvailableSensorsByType () +# check what sensors are available and store them +#+ in the array for the respective unit +getAvailableSensorsByType () { + _thisSensorNr="1" + + # initial fetch + _snmpget=`snmpGet $hostAddr $SENS_UNIT_OID$_thisSensorNr` + _nextSensorExits=$? + _unit=`echo "$_snmpget" | tr -d " "` + + # add next sensor if it exists + while [ true ]; do + # add sensors of the same type to a list + sensorsOfType[$_unit]="${sensorsOfType[$_unit]} $_thisSensorNr" + + # fetch next sensor + _thisSensorNr=$(($_thisSensorNr+1)) + _snmpget=`snmpGet $hostAddr $SENS_UNIT_OID$_thisSensorNr` + _nextSensorExits=$? + + # are we done? + if [ $_nextSensorExits -ne 0 ]; then + break + fi + + _unit=`echo "$_snmpget" |cut -d" " -f 4` + done +} + +# sanitize () +# use bash builtin substitutions to sanitize string +#+ allowed chars are: a-z,A-Z,0-9 and "." +#+ if chars have been removed return 1, else return 0 +sanitize () { + input="$1" + sanitizedInput="${1//[^a-zA-Z0-9.]/}" + echo "$sanitizedInput" + if [ "$input" = "$sanitizedInput" ]; then + return 0 + else + return 1 + fi +} + +# usage ([munin|icinga]) +# print either specific usage for use as munin/icinga plugin or long usage +usage () { + case $1 in + munin) echo "usage: snmp__poseidon-sensors [config|snmpconf]" 1>&2 + exit $E_USAGE + ;; + icinga) echo "usage: check_snmp_poseidon " 1>&2 + exit $E_USAGE + ;; + *) echo "usage: check_snmp_poseidon +for nagios/icinga compatible output. +usage: snmp__poseidon-sensors [config|snmpconf] +for munin compatible output" 1>&2 + exit $E_USAGE + ;; + esac +} + +# err (ErrorMsg, Exitcode) +# basic error handling +err () { + if [ $# -eq 2 -a "$2" -lt 256 ]; then + _errorMsg="$1" + _exitCode="$2" + else + _errorMsg="Fatal: An unknown error occured! Exiting..." + _exitCode="$E_UNKNOWN" + + fi + + # print error message to STDERR ... + echo "$_errorMsg" >&2 + # ... and exit with error code. + exit $_exitCode +} + +#==============================================================================# + +# handle -h option +while getopts ":h" opt; do + case $opt in + h) usage + ;; + \?) echo "Invalid option: -$OPTARG" >&2 + usage + ;; + esac +done + +# check for snmpget binary +if [ ! -x `which snmpget` ]; then + err "Fatal: unable to locate \'snmpget\'! Exiting..." $E_COMMANDNOTFOUND +fi + +# analyze how we have been called and... +myName="`basename "$0"`" + +hostAddr="`echo $myName | cut -d "_" -f 2`" +muninName="`echo $myName | cut -d "_" -f 1,3`" +icingaName="`echo $myName | cut -d "_" -f 1,2,3`" + +# ...and behave like a munin/icinga plugin... +if [ "$icingaName" = "check_snmp_poseidon" ]; then + # IP address of the Poseidon device + hostAddr=`sanitize $1 || err + "Fatal: Invalid argument \"$1\"! Exiting..." $E_ARG` + # number of the sensor + sensorNr=`sanitize $2 || err + "Fatal: Invalid argument \"$2\"! Exiting..." $E_ARG` + if [[ -n ${sensorNr//[0-9]/} ]]; then err \ + "Fatal: Invalid argument \"$sensorNr\"\! Exiting..." $E_ARG + fi + + printIcingaStatus "$sensorNr" + exit $? +# ...or as a munin plugin +elif [ "$muninName" = "snmp_poseidon-sensors" ]; then + hostAddr=`sanitize $hostAddr || err \ + "Fatal: Invalid argument \"$hostAddr\"! Exiting..." $E_ARG` + if [ -z "$hostAddr" ]; then + usage munin + fi + getAvailableSensorsByType + if [ "$1" = "config" ]; then + printMuninConfig + exit $E_OK + elif [ "$1" = "snmpconfig" ]; then + printMuninSnmpConfig + exit $E_OK + else + printMuninStatus + exit $E_OK + fi +else + usage +fi +