Skip to content
Snippets Groups Projects
check_snmp_data 9.41 KiB
#!/usr/bin/env bash
# ======================================================================
#
# NAGIOS / ICINGA CHECK :: check_snmp_data
#
# DOCS:
#   - Synology - see docs:
#     https://global.download.synology.com/download/Document/Software/DeveloperGuide/Firmware/DSM/All/enu/Synology_DiskStation_MIB_Guide.pdf
#
#   - IODs uc davis http://oidref.com/1.3.6.1.4.1.2021
#
# ----------------------------------------------------------------------
#
# SYNTAX: 
# label    --> DATA:[method]:label:[text]
# n x data --> DATA:[method]:data:[perf-label]:[oid]:[optional unit]:[loop oid]
#
# ---------- General infos for all devices:
#
# DATA:about:label:About... general device infos
# DATA:about:out:text:sysDescr:1.3.6.1.2.1.1.1.0:
# DATA:about:out:text:sysObjectID:1.3.6.1.2.1.1.2.0:
# DATA:about:out:text:sysUpTime:1.3.6.1.2.1.1.3.0:
# DATA:about:out:text:sysContact:1.3.6.1.2.1.1.4.0:
# DATA:about:out:text:sysName:1.3.6.1.2.1.1.5.0:
# DATA:about:out:text:sysLocation:1.3.6.1.2.1.1.6.0:
#
# DATA:cpu:label:CPU usage
# DATA:cpu:out:data:cpu-user:1.3.6.1.4.1.2021.11.9.0:%
# DATA:cpu:out:data:cpu-system:1.3.6.1.4.1.2021.11.10.0:%
# DATA:cpu:out:data:cpu-idle:1.3.6.1.4.1.2021.11.11.0:%
#
# DATA:load:label:System load
# DATA:load:out:data:load1:1.3.6.1.4.1.2021.10.1.5.1:
# DATA:load:out:data:load5:1.3.6.1.4.1.2021.10.1.5.2:
# DATA:load:out:data:load15:1.3.6.1.4.1.2021.10.1.5.3:
#
# DATA:mem:label:Memory status
# DATA:mem:out:data:memTotalSwap:1.3.6.1.4.1.2021.4.3.0:
# DATA:mem:out:data:memAvailSwap:1.3.6.1.4.1.2021.4.4.0:
# DATA:mem:out:data:memTotalReal:1.3.6.1.4.1.2021.4.5.0:
# DATA:mem:out:data:memAvailReal:1.3.6.1.4.1.2021.4.6.0:
# DATA:mem:out:data:memTotalFree:1.3.6.1.4.1.2021.4.11.0:
# DATA:mem:out:data:memShared:1.3.6.1.4.1.2021.4.13.0:
# DATA:mem:out:data:memBuffer:1.3.6.1.4.1.2021.4.14.0:
# DATA:mem:out:data:memCached:1.3.6.1.4.1.2021.4.15.0:
#
# DATA:netio:label:Network IO
# DATA:netio:out:data:in:1.3.6.1.2.1.4.3.0:
# DATA:netio:out:data:out:1.3.6.1.2.1.4.10.0:
#
# ---------- SYNOLOGY specific:
#
# DATA:synodisc:label:Synology Disc usage
# DATA:synodisc:out:data:disc-free:1.3.6.1.4.1.6574.3.1.1.2::1.3.6.1.4.1.6574.3.1.1.4
# DATA:synodisc:out:data:disc-space:1.3.6.1.4.1.6574.3.1.1.2::1.3.6.1.4.1.6574.3.1.1.5
#
# DATA:synotemp:label:Synology NAS temperature
# DATA:synotemp:out:data:temp:1.3.6.1.4.1.6574.1.2.0:°C
#
# DATA:synoio:label:Synology Space IO
# DATA:synoio:out:data:syno-io-read:1.3.6.1.4.1.6574.102.1.1.12.1
# DATA:synoio:out:data:syno-io-write:1.3.6.1.4.1.6574.102.1.1.13.1
#
# ----------------------------------------------------------------------
# 2020-08-11  <axel.hahn@iml.unibe.ch>            initial version
# 2020-08-13  <axel.hahn@iml.unibe.ch>            add host in label for counter data
# 2022-10-21  v0.4  <axel.hahn@unibe.ch>          remove grep: warning: stray \ before white space
# 2022-10-21  v0.5  <andrea.gottsponer@unibe.ch>  remove grep: warning: stray \ before white space
# 2022-10-25  v0.6  <axel.hahn@unibe.ch>          fix empty value in performance data; shell fixes
# 2023-05-05  v0.7  <axel.hahn@unibe.ch>          source shared func, support snmpv3; add synoio
# 2023-05-16  v0.8  <axel.hahn@unibe.ch>          add about for general infos and without perf data
# 2025-02-12  v1.0  <axel.hahn@unibe.ch>          add IML header in help
# ======================================================================

. $(dirname $0)/inc_pluginfunctions
. $(dirname $0)/check_snmp_includes

# --- basic vars
self_APPNAME=$( basename $0 | tr [:lower:] [:upper:] )
self_APPVERSION=1.0

METHOD=""

# --- output variables
SYNO=""
out=""

#---------------------------------------------------
# FUNCTIONS
#---------------------------------------------------

# --- write verbose text
_wd()
{
    if [ "$verbose" = "yes" ] ; then 
        out="${out}$*
" ; fi
}

#---------------------------------------------------
# --- get config entries in the DATA comment lines

# get line(s) for config
# param  string  one of label|data
_cfg_reader(){
    grep "^# DATA:${METHOD}${1}" $0
}
_cfg_getlabel(){
    _cfg_reader ":label:" | cut -f 4- -d ":"
}
_cfg_dataitem(){
    _cfg_reader ":out:" | cut -f $1 -d ":" | while read item
    do
        echo -n "$item "
    done
}

# get a list existing methods
_cfg_getMethods(){
    grep "^# DATA:.*:label:" $0 | cut -f 2 -d ":"
}

#---------------------------------------------------
# --- get a value from SNMP output data
# global string  $SYNO  output of snmpget
# param  string  mib    string
_getresult(){
    echo "$SYNO" | grep "${1} " | cut -d "=" -f2 | cut -f 2- -d " "
}

# --- get a value from SNMP output data
# param  string  mib    string
_get(){
    _getresult $1 | cut -d ":" -f2 | cut -f 2- -d " "
}

# is given oid a counter?
# function resturns "true" or "false" 
_iscounter(){
    if _getresult $1 | cut -d ":" -f1 | grep -i "Counter" >/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}
_isinteger(){
    if _getresult $1 | cut -d ":" -f1 | grep -i "Integer" >/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}

#---------------------------------------------------
# --- show usage
function showHelp(){
    _self=$( basename $0 )
    local _methods=$(
        _cfg_getMethods | while read -r line
        do
            METHOD=$(echo "$line" | cut -f 2 -d ":")
            descr=$(_cfg_getlabel)
            printf "            %-10s %-50s\n" "$METHOD" "$descr"
        done        
    )
cat <<EOH
$( ph.showImlHelpHeader )

SNMP performance data of Synology storages.

USAGE:
    $_self [options] -h SNMPTARGET

PARAMETERS:
    -a STRING
        authentication params for snmpwalk/ snmpget to connect to target; 
        default: \"-v2c -c public\" (Snmpv2 with community string \"public\")
    -h SNMPTARGET
        as fqdn or ip address; default: localhost
    -f FILE
        read authentication from config file
        default: "/etc/icinga2/snmp.cfg"
    -m  METHOD
        what to show; METHOD is one of ...
$_methods
    -v  verbose output

CONFIG FILE:
    The config file can be multiline and has the syntax
    [SNMPTARGET[,target2]]:[auth parameters]
    The auth parameters set the version and all needed values to connect.
    Snmp v2 uses a community string.
    Snmp v3 is highly recommended (you should disable Snmp v2) and needs
    a user and password.

EXAMPLE:
    $_self -h 192.168.100.12 -v -m cpu

EOH
    ph.abort ""
}


#---------------------------------------------------
# MAIN
#---------------------------------------------------

while getopts a:h:m:v OPTNAME; do
        case "$OPTNAME" in

        a)
            SNMPAUTH="$OPTARG"
            ;;
		C)
			SNMPCOMMUNITY="$OPTARG"
			;;
        f)
            SNMPCONFIG="$OPTARG"
            ;;
        h)
            SNMPTARGET="$OPTARG"
            option_found=1
            ;;
        m)
            METHOD="$OPTARG"
            ;;
        v)
            verbose="yes"
            _wd ""
            ;;
        *)
            usage
            ;;
        esac
done

if [ "$option_found" = "0" ] || [ "$SNMPTARGET" = "" ] ; then
    usage
    # remark: script aborts ...
fi

test -z "$SNMPAUTH" && read_config

# --- read metadata of the selected METHOD
info=$(_cfg_getlabel)
if [ -z "$info" ]; then
    echo "ERROR: unknown METHOD [$METHOD]"
    showHelp
fi

prflist=( $(_cfg_dataitem 5) )
oidlist=( $(_cfg_dataitem 6) )
unitlist=( $(_cfg_dataitem 7) )
looplist=( $(_cfg_dataitem 8) )

# --- check for looplist
if [ -n "$looplist" ]; then
  nb=$($SNMPWALK -OQne -t $SNMPTIMEOUT $SNMPAUTH $SNMPTARGET ${oidlist[*]} 2> /dev/null | wc -l)

  declare -a tmpPrflist=()
  declare -a tmpOidlist=()
  declare -a tmpUnitlist=()
  for i in $(seq 1 $nb);
  do
    for j in $(seq 1 ${#looplist[@]})
    do
      tmpPrflist+=("${prflist[$(($j-1))]}.$(($i-1))")
      tmpOidlist+=("${looplist[$(($j-1))]}.$(($i-1))")
      tmpUnitlist+=("${unitlist[$(($j-1))]}")
    done
  done
  prflist=( "${tmpPrflist[@]}" )
  oidlist=( "${tmpOidlist[@]}" )
  unitlist=( "${tmpUnitlist[@]}" )
fi

# --- SNMPGET to all wanted oids
SYNO=$($SNMPGET -One -t $SNMPTIMEOUT $SNMPAUTH $SNMPTARGET ${oidlist[*]} 2> /dev/null)

if [ $? -ne 0 ] ; then
    $SNMPGET -One -t $SNMPTIMEOUT $SNMPAUTH $SNMPTARGET ${oidlist[*]}
    ph.abort "Problem with SNMP request"
fi


# --- performance data
# typeset -i value

for index in ${!oidlist[*]}
do
    label="${prflist[$index]}"
    value=$(_get ${oidlist[$index]})
    unit="${unitlist[$index]}"

    isperf=1

    outtype='text'
    test "$(_iscounter ${oidlist[$index]})" = 'true' && outtype='counter'
    test "$(_isinteger ${oidlist[$index]})" = 'true' && outtype='integer'
    test -n "$looplist" && outtype='looplist'

    # _wd ""; _wd "outtype = $outtype:"
    case $outtype in
        counter) 
            value2=$(ph.perfdeltaspeed "snmp-data-${SNMPTARGET}-${method}-${label}" $value)
            _wd "$( printf '%-14s total: %-14s delta: %6s %s per sec' $label $value $value2 $unit )"
            value=$value2
            ;;
        integer)
            _wd "$( printf '%-14s %s %s' $label $value $unit )"
            value2=$( echo "${value}" | sed -E "s#([0-9]*) (.).*#\1\2#g")
            value=${value2}
            ;;
        looplist) 
            _wd "$( printf '%-14s %s %s' $label "$value" $unit )"
            ;;
        text) 
            _wd "$( printf '%-14s %s %s' $label "$value" $unit )"
            isperf=0
            ;;
        *)
            echo "TODO: handle output of type $outtype"
            ;;
    esac

    test $isperf -eq 1 && ph.perfadd "${label}" "${value}"
done


# --- output
ph.status "SNMP performance data :: $info $out"
ph.exit