#!/bin/bash #==============================================================================# # # # check status of sensor of HW Group Poseidon 3268. For more info refer to: # # http://www.hw-group.com/products/poseidon/poseidon_3268_en.html # # 2012 by Florian Lechner # # # #==============================================================================# # # # 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 . # # # #==============================================================================# # Munin autoconf and snmpautoconf magic #%# family=auto snmpauto contrib #%# capabilities=snmpconf E_OK="0" # everything went alright 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_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=" " #==============================================================================# # 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 sensors 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 $SNMPCOMMUNITY\ $_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 () # print usage usage () { echo "usage: snmp__poseidon-sensors [config|snmpconf]" 1>&2 exit $E_USAGE } # 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 occurred! Exiting..." _exitCode="$E_UNKNOWN" fi # print error message to STDERR ... echo "$_errorMsg" >&2 # ... and exit with error code. exit $_exitCode } #==============================================================================# # SNMP Config MIBS=":" # we don't use any configured MIBs so we don't #+ have to deal with errors in the MIBs if [ -z $SNMPVERSION ]; then SNMPVERSION="1" # as of firmware 3.1.5 only SNMPv1 is supported fi if [ -z $SNMPCOMMUNITY ]; then SNMPCOMMUNITY="public" # SNMP community string to read from the device fi # 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 # extract pluginname ... myName="`basename "$0" | cut -d "_" -f 1,3`" # ...and hostname hostAddr="`basename "$0" | cut -d "_" -f 2`" if [ "$myName" = "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