【SNMP】標準 MIB で CPU / メモリ / Disk の使用率を計算するスクリプトを作る

こんにちは。
とあるネットワーク機器をモニタリングする必要があり、SNMP を用いたリソース情報の取得諸々について調べてみたので備忘録を残しておきます。

※ というのも普段 Linux デバイスに定義されている UCD-SNMP-MIB が定義されていなかったため、どうすればいいんだろう?と悩んだ結果です。 SNMPv2 前提です。

メモリ/ディスク

メモリ / ディスク の情報については、hrStorageDescr の OID で一覧と割り当てられた index 番号を取得できるようです。

[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrStorageDescr
HOST-RESOURCES-MIB::hrStorageDescr.1 = STRING: Physical memory
HOST-RESOURCES-MIB::hrStorageDescr.3 = STRING: Virtual memory
HOST-RESOURCES-MIB::hrStorageDescr.6 = STRING: Memory buffers
HOST-RESOURCES-MIB::hrStorageDescr.7 = STRING: Cached memory
HOST-RESOURCES-MIB::hrStorageDescr.8 = STRING: Shared memory
HOST-RESOURCES-MIB::hrStorageDescr.10 = STRING: Swap space
HOST-RESOURCES-MIB::hrStorageDescr.35 = STRING: /dev/shm
HOST-RESOURCES-MIB::hrStorageDescr.37 = STRING: /run
HOST-RESOURCES-MIB::hrStorageDescr.38 = STRING: /sys/fs/cgroup
HOST-RESOURCES-MIB::hrStorageDescr.55 = STRING: /
HOST-RESOURCES-MIB::hrStorageDescr.63 = STRING: /run/user/1000
[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrStorageDescr HOST-RESOURCES-MIB::hrStorageDescr.1 = STRING: Physical memory HOST-RESOURCES-MIB::hrStorageDescr.3 = STRING: Virtual memory HOST-RESOURCES-MIB::hrStorageDescr.6 = STRING: Memory buffers HOST-RESOURCES-MIB::hrStorageDescr.7 = STRING: Cached memory HOST-RESOURCES-MIB::hrStorageDescr.8 = STRING: Shared memory HOST-RESOURCES-MIB::hrStorageDescr.10 = STRING: Swap space HOST-RESOURCES-MIB::hrStorageDescr.35 = STRING: /dev/shm HOST-RESOURCES-MIB::hrStorageDescr.37 = STRING: /run HOST-RESOURCES-MIB::hrStorageDescr.38 = STRING: /sys/fs/cgroup HOST-RESOURCES-MIB::hrStorageDescr.55 = STRING: / HOST-RESOURCES-MIB::hrStorageDescr.63 = STRING: /run/user/1000
[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrStorageDescr
HOST-RESOURCES-MIB::hrStorageDescr.1 = STRING: Physical memory
HOST-RESOURCES-MIB::hrStorageDescr.3 = STRING: Virtual memory
HOST-RESOURCES-MIB::hrStorageDescr.6 = STRING: Memory buffers
HOST-RESOURCES-MIB::hrStorageDescr.7 = STRING: Cached memory
HOST-RESOURCES-MIB::hrStorageDescr.8 = STRING: Shared memory
HOST-RESOURCES-MIB::hrStorageDescr.10 = STRING: Swap space
HOST-RESOURCES-MIB::hrStorageDescr.35 = STRING: /dev/shm
HOST-RESOURCES-MIB::hrStorageDescr.37 = STRING: /run
HOST-RESOURCES-MIB::hrStorageDescr.38 = STRING: /sys/fs/cgroup
HOST-RESOURCES-MIB::hrStorageDescr.55 = STRING: /
HOST-RESOURCES-MIB::hrStorageDescr.63 = STRING: /run/user/1000

※ 上記だと、index 1 が物理メモリ、index 55 がディスクの ルートパーティション となります。

index を参考に下記の OID を取得することで、Total / 使用量 / 使用率 が割り出せます。

HOST-RESOURCES-MIB::hrStorageAllocationUnits
HOST-RESOURCES-MIB::hrStorageSize
HOST-RESOURCES-MIB::hrStorageUsed
HOST-RESOURCES-MIB::hrStorageAllocationUnits HOST-RESOURCES-MIB::hrStorageSize HOST-RESOURCES-MIB::hrStorageUsed
HOST-RESOURCES-MIB::hrStorageAllocationUnits
HOST-RESOURCES-MIB::hrStorageSize
HOST-RESOURCES-MIB::hrStorageUsed

※ 計算式は下記の通りです。
Total = HOST-RESOURCES-MIB::hrStorageSize * HOST-RESOURCES-MIB::hrStorageAllocationUnits
使用量 = HOST-RESOURCES-MIB::hrStorageUsed * HOST-RESOURCES-MIB::hrStorageAllocationUnits
使用率 = 使用量 / Total * 100
Total = HOST-RESOURCES-MIB::hrStorageSize * HOST-RESOURCES-MIB::hrStorageAllocationUnits 使用量 = HOST-RESOURCES-MIB::hrStorageUsed * HOST-RESOURCES-MIB::hrStorageAllocationUnits 使用率 = 使用量 / Total * 100
Total = HOST-RESOURCES-MIB::hrStorageSize * HOST-RESOURCES-MIB::hrStorageAllocationUnits
使用量 = HOST-RESOURCES-MIB::hrStorageUsed * HOST-RESOURCES-MIB::hrStorageAllocationUnits
使用率 = 使用量 / Total * 100

諸々を bash と awk でスクリプトに纏めると下記の通りとなります。
※ シェルスクリプトだと小数点が扱えないので、演算部分は awk で賄います。
※ 第一引数に求める値(Total/使用量/使用率)、第二引数に領域の index を指定します。

#!/usr/bin/bash
# MEMO: 引数チェック
if [ $# != 2 ]; then
echo "ERR:invalid argument"
exit 1
fi
COMMUNITY_NAME=<CommunityName>
IP_ADDR=xxx.xxx.xxx.xxx
ALLOCATIONUNITS=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageAllocationUnits | grep "HOST-RESOURCES-MIB::hrStorageAllocationUnits.${2} = INTEGER:" | awk '{print $4}'`
HRSTORAGESIZE=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageSize | grep "HOST-RESOURCES-MIB::hrStorageSize.${2} = INTEGER:" | awk '{print $4}'`
HRSTORAGEUSED=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageUsed | grep "HOST-RESOURCES-MIB::hrStorageUsed.${2} = INTEGER:" | awk '{print $4}'`
USED_MEMORY=$(( HRSTORAGEUSED * ALLOCATIONUNITS ))
ALL_MEMORY=$(( HRSTORAGESIZE * ALLOCATIONUNITS ))
USED_RATIO=`awk "BEGIN { print $USED_MEMORY / $ALL_MEMORY * 100 }"`
case ${1} in
# NOTE: Total
"1")
echo ${ALL_MEMORY}
;;
# NOTE: Used
"2")
echo ${USED_MEMORY}
;;
# NOTE: Ratio
"3")
echo ${USED_RATIO}
;;
# NOTE: Ratio
*)
echo ${USED_RATIO}
;;
esac
#!/usr/bin/bash # MEMO: 引数チェック if [ $# != 2 ]; then echo "ERR:invalid argument" exit 1 fi COMMUNITY_NAME=<CommunityName> IP_ADDR=xxx.xxx.xxx.xxx ALLOCATIONUNITS=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageAllocationUnits | grep "HOST-RESOURCES-MIB::hrStorageAllocationUnits.${2} = INTEGER:" | awk '{print $4}'` HRSTORAGESIZE=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageSize | grep "HOST-RESOURCES-MIB::hrStorageSize.${2} = INTEGER:" | awk '{print $4}'` HRSTORAGEUSED=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageUsed | grep "HOST-RESOURCES-MIB::hrStorageUsed.${2} = INTEGER:" | awk '{print $4}'` USED_MEMORY=$(( HRSTORAGEUSED * ALLOCATIONUNITS )) ALL_MEMORY=$(( HRSTORAGESIZE * ALLOCATIONUNITS )) USED_RATIO=`awk "BEGIN { print $USED_MEMORY / $ALL_MEMORY * 100 }"` case ${1} in # NOTE: Total "1") echo ${ALL_MEMORY} ;; # NOTE: Used "2") echo ${USED_MEMORY} ;; # NOTE: Ratio "3") echo ${USED_RATIO} ;; # NOTE: Ratio *) echo ${USED_RATIO} ;; esac
#!/usr/bin/bash

# MEMO: 引数チェック
if [ $# != 2 ]; then
    echo "ERR:invalid argument"
    exit 1
fi

COMMUNITY_NAME=<CommunityName>
IP_ADDR=xxx.xxx.xxx.xxx

ALLOCATIONUNITS=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageAllocationUnits | grep "HOST-RESOURCES-MIB::hrStorageAllocationUnits.${2} = INTEGER:" | awk '{print $4}'`
HRSTORAGESIZE=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageSize | grep "HOST-RESOURCES-MIB::hrStorageSize.${2} = INTEGER:" | awk '{print $4}'`
HRSTORAGEUSED=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrStorageUsed | grep "HOST-RESOURCES-MIB::hrStorageUsed.${2} = INTEGER:" | awk '{print $4}'`

USED_MEMORY=$(( HRSTORAGEUSED * ALLOCATIONUNITS ))
ALL_MEMORY=$(( HRSTORAGESIZE * ALLOCATIONUNITS ))

USED_RATIO=`awk "BEGIN { print $USED_MEMORY / $ALL_MEMORY * 100 }"`

case ${1} in
    # NOTE: Total
    "1")
        echo ${ALL_MEMORY}
        ;;
    # NOTE: Used
    "2")
        echo ${USED_MEMORY}
        ;;
    # NOTE: Ratio
    "3")
        echo ${USED_RATIO}
        ;;
    # NOTE: Ratio
    *)
        echo ${USED_RATIO}
        ;;
esac

CPU

CPU 使用率は hrProcessorLoad の OID で1コア辺りの 使用率を参照できます。

[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrProcessorLoad
HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 2
[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrProcessorLoad HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 2 HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 2
[sanuki@sanuki-wd01 ~]$ snmpwalk -v 2c -c <CommunityName> xxx.xxx.xxx.xxx hrProcessorLoad
HOST-RESOURCES-MIB::hrProcessorLoad.196608 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196609 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196610 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196611 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196612 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196613 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196614 = INTEGER: 2
HOST-RESOURCES-MIB::hrProcessorLoad.196615 = INTEGER: 2

※ 上記だとノードに 8コアの CPU が詰まれていて、1コア辺り 2% の使用率となる。

こちらも bash と awk でスクリプトに纏めると下記の通りとなります。
※ 1 コア辺りの平均値を求めます。

#!/usr/bin/bash
COMMUNITY_NAME=<CommunityName>
IP_ADDR=xxx.xxx.xxx.xxx
TOTAL_CPU_LOAD=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | awk '{print $4}' | awk '{s += $1} END {print s}'`
CPU_NUM=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | wc -l`
echo $(( TOTAL_CPU_LOAD / CPU_NUM ))
#!/usr/bin/bash COMMUNITY_NAME=<CommunityName> IP_ADDR=xxx.xxx.xxx.xxx TOTAL_CPU_LOAD=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | awk '{print $4}' | awk '{s += $1} END {print s}'` CPU_NUM=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | wc -l` echo $(( TOTAL_CPU_LOAD / CPU_NUM ))
#!/usr/bin/bash

COMMUNITY_NAME=<CommunityName>
IP_ADDR=xxx.xxx.xxx.xxx

TOTAL_CPU_LOAD=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | awk '{print $4}' | awk '{s += $1} END {print s}'`
CPU_NUM=`snmpwalk -v 2c -c ${COMMUNITY_NAME} ${IP_ADDR} hrProcessorLoad | wc -l`

echo $(( TOTAL_CPU_LOAD / CPU_NUM ))

終わりに

上 2つのスクリプトで対象の機器に対してポーリング → DB にデータ格納 でモニタリングできますね。