紅葉の時期になってまいりました。
この時期、NPB ではCS ~ 日本シリーズなんですが、私の愛するチームは今年は、、、逃しました。。。(泣)
ドラフトで新戦力確保で来年に向けて一から出直しです。
(・・・私が打ったり投げたりするわけじゃないんですが、、)
さて、お仕事の話をしましょう。
インフラの仕事って開発系の業務に比べると地味で、なかなか人に伝えるのにも何て伝えたらいいのか迷ってしまう時があります。
分かりやすい面でお話ししますと、ネットワーク機器やサーバ類の設定を考えたり、検証したり、実際に設定したりすること、、、になるんでしょうか。
しかし、多くはそれらを管理するためのドキュメントを起こすことにも費やされるのかなと思います。
そんな中、インフラ技術の中の一つに機器を監視するための仕組みとして SNMP というのがあるんですが、皆さん SNMP トラップってどうやって管理してます??
ポーリング(REQUEST)に関しては、監視機器上での設定をそのままドキュメントに起こせばよいと思いますが、トラップって取るには取るんだけど、機器から勝手に飛んでくるし何飛んでくるか把握してなくて、 human-readable ではない OID だけ表示される状態で垂れ流し、、、
・・・まあテキトーでいいか・・・なんて 状況はよくありがちです。
トラップもちゃんと管理しましょうね!
SNMPトラップ
取り扱った経験の無い方に SNMP のアーキテクチャについて簡単に説明しますと
マネージャ(監視システム等)からエージェント(各機器)方向に状態を取りに行く
エージェント(各機器)からマネージャ(監視システム等)方向に状態遷移や障害をイベント発生時に知らせる
と大きく2つに分類されます。
よく、CPU 使用率やディスク、ネットワーク帯域の使用状況をグラフ化した監視システムなんかは、前者の仕組みで定期的(一般的に 5 分毎等の間隔)に各機器上保持している値を取りにいくことで、それを可視化しているわけです。
ここで言う「値」の種別は MIB (管理情報の集合体:一般的に「ミブ」と言っています) 上で定義された階層化された OID (”.1.3.6.1.2.1.2.2.1.10″ みたいな数字の羅列)によって識別されます。
今回の観点は後者。
ネットワークインターフェースのリンクアップ・ダウン等、標準MIBで定義された一般的なトラップというのは存在しますが、プライベート MIB(いわゆるベンダ MIB)については機器ベンダが様々で、機器固有のトラップとして何が定義されているかはその機器の仕様によります。
導入した機器のマニュアルに一覧が掲載されていたり親切なベンダもあるのですが、定義ファイル(MIB ファイル)だけ提供しているところもあったりで様々です。
詳細設計で運用管理に使用するためにドキュメント化する場合、これらを調査して一覧化、、、なかなか大変ですね。
(やってます?? 少なくとも オモイヤリ設計 がモットーのワタクシならやりますよ)
そんなドキュメンテーションの補助用途として、簡単なスクリプトを作成してみました。
SNMPTT で MIB ファイルから snmptt.conf へコンバート
SMMP トラップを扱うのに必ず使用するのが SNMPTT ですね。
http://snmptt.sourceforge.net/
ZABBIX 等、監視マネージャ用途のサーバ上に導入して、snmptt.conf は監視マネージャのアプリケーション上で取り扱えるように出力フォーマット等を定義したファイル・・・
・・・まあトラップメッセージの実態ファイルです。
各所から掻き集めた MIB ファイルがこんな感じでサーバ上にあります。
※ 依存性は全てコンパイルできているものとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# ls /usr/share/snmp/mibs/ AGENTX-MIB.txt IPV6-ICMP-MIB.txt SCTP-MIB.txt AX2530S-MIB.my IPV6-MIB.txt SMUX-MIB.txt AX36S.my IPV6-TC.txt SNMP-COMMUNITY-MIB.txt Adapter-Series.mib IPV6-TCP-MIB.txt SNMP-FRAMEWORK-MIB.txt BGP4-MIB.my IPV6-UDP-MIB.txt SNMP-MPD-MIB.txt BRIDGE-MIB.txt LLDP-MIB.my SNMP-NOTIFICATION-MIB.txt DISMAN-EVENT-MIB.txt LM-SENSORS-MIB.txt SNMP-PROXY-MIB.txt DISMAN-SCHEDULE-MIB.txt MTA-MIB.txt SNMP-TARGET-MIB.txt DISMAN-SCRIPT-MIB.txt NET-SNMP-AGENT-MIB.txt SNMP-USER-BASED-SM-MIB.txt EtherLike-MIB.txt NET-SNMP-EXAMPLES-MIB.txt SNMP-USM-AES-MIB.txt FORTINET-CORE-MIB.mib NET-SNMP-EXTEND-MIB.txt SNMP-USM-DH-OBJECTS-MIB.txt FORTINET-FORTIGATE-MIB.mib NET-SNMP-MIB.txt SNMP-VIEW-BASED-ACM-MIB.txt FORTINET-FORTIMANAGER-FORTIANALYZER-MIB.mib NET-SNMP-PASS-MIB.txt SNMPv2-CONF.txt HCNUM-TC.txt NET-SNMP-TC.txt SNMPv2-MIB.txt HOST-RESOURCES-MIB.txt NET-SNMP-VACM-MIB.txt SNMPv2-SMI.txt HOST-RESOURCES-TYPES.txt NETWORK-SERVICES-MIB.txt SNMPv2-TC.txt IANA-ADDRESS-FAMILY-NUMBERS-MIB.txt NOTIFICATION-LOG-MIB.txt SNMPv2-TM.txt IANA-LANGUAGE-MIB.txt OSPF-MIB.my TCP-MIB.txt IANA-RTPROTO-MIB.txt OSPF-TRAP-MIB.my TOKEN-RING-RMON-MIB.my IANAifType-MIB.txt OSPFV3-MIB.my TRANSPORT-ADDRESS-MIB.txt IEEE8021-CFM-MIB.my P-BRIDGE.my UCD-DEMO-MIB.txt IEEE8021-PAE-MIB.my PIM-MIB.my UCD-DISKIO-MIB.txt IEEE8023-LAG-MIB.my PULSESECURE-PSG-MIB.txt UCD-DLMOD-MIB.txt IF-INVERTED-STACK-MIB.txt Q-BRIDGE-MIB.my UCD-IPFWACC-MIB.txt IF-MIB.txt RFC-1215.txt UCD-SNMP-MIB.txt |
snmptt.conf ファイル出力用のディレクトリ(ない場合作って)配下で作業します。
1 2 3 4 |
# mkdir -p /etc/snmp/snmptt.conf.d # cd /etc/snmp/snmptt.conf.d # pwd /etc/snmp/snmptt.conf.d |
各 MIB ファイルを “snmpttconvertmib” コマンドを使って以下のようなファイル命名ルールの snmptt.conf にコンバートしてみます。
snmptt.conf.<オリジナルの MIB ファイル名>.org
※ フォーマットを後で変更しようと思うので、末尾に “.org” をつけたファイルにします。
ワンライナーで一括でやっちゃいますか!
1 |
# MIBDIR=/usr/share/snmp/mibs; for FILE in `find ${MIBDIR} -type f | xargs -I {} basename {}`; do snmpttconvertmib --in=${MIBDIR}/${FILE} --out=./snmptt.conf.${FILE}.org --net_snmp_perl; done |
MIB ファイルからこんな感じの snmptt.conf ファイルができました。
※ 例:IF-MIB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# cat snmptt.conf.IF-MIB.txt.org # # # # MIB: IF-MIB (file:/usr/share/snmp/mibs/IF-MIB.txt) converted on Fri Oct 26 07:42:20 2018 using snmpttconvertmib v1.4beta2 # # # EVENT linkDown .1.3.6.1.6.3.1.1.5.3 "Status Events" Normal FORMAT A linkDown trap signifies that the SNMP entity, acting in $* SDESC A linkDown trap signifies that the SNMP entity, acting in an agent role, has detected that the ifOperStatus object for one of its communication links is about to enter the down state from some other state (but not from the notPresent state). This other state is indicated by the included value of ifOperStatus. Variables: 1: ifIndex Syntax="INTEGER32" Descr="A unique value, greater than zero, for each interface. It is recommended that values are assigned contiguously starting from 1. The value for each interface sub-layer must remain constant at least from one re-initialization of the entity's network management system to the next re- initialization." 2: ifAdminStatus Syntax="INTEGER" 1: up 2: down 3: testing Descr="The desired state of the interface. The testing(3) state indicates that no operational packets can be passed. When a managed system initializes, all interfaces start with ifAdminStatus in the down(2) state. As a result of either explicit management action or per configuration information retained by the managed system, ifAdminStatus is then changed to either the up(1) or testing(3) states (or remains in the down(2) state)." 3: ifOperStatus Syntax="INTEGER" 1: up 2: down 3: testing 4: unknown 5: dormant 6: notPresent 7: lowerLayerDown Descr="The current operational state of the interface. The testing(3) state indicates that no operational packets can be passed. If ifAdminStatus is down(2) then ifOperStatus should be down(2). If ifAdminStatus is changed to up(1) then ifOperStatus should change to up(1) if the interface is ready to transmit and receive network traffic; it should change to dormant(5) if the interface is waiting for external actions (such as a serial line waiting for an incoming connection); it should remain in the down(2) state if and only if there is a fault that prevents it from going to the up(1) state; it should remain in the notPresent(6) state if the interface has missing (typically, hardware) components." EDESC ~~~~~~~~~~~~ 省略 |
今回は ZABBIX で使うことを想定して、”FORMAT” 部分をゴニョゴニョ変更します。
※ FORMAT については SNMPTT のマニュアル参照
http://snmptt.sourceforge.net/docs/snmptt.shtml#SNMPTT.CONF-FORMAT
またワンライナーでやりますね。
1 |
# for FILE in `ls -1 snmptt.conf.*.org`; do sed -e 's/^FORMAT\s.*/FORMAT ZBXTRAP $aA $N - $+*/g' ${FILE} > `basename ${FILE} .org`; rm -f ${FILE}; done |
すると FORMAT 部分が書き換わった内容が、先ほどのファイルから “.org” が外れたファイルとして出来上がります。
1 2 3 4 5 |
# cat snmptt.conf.IF-MIB.txt ~~~~~~~~~~~~ 省略 EVENT linkDown .1.3.6.1.6.3.1.1.5.3 "Status Events" Normal FORMAT ZBXTRAP $aA $N - $+* ~~~~~~~~~~~~ 省略 |
トラップ自体が定義されていない MIB もありますので、そういったファイルは捨てることとします。
コンバートされた全ファイル数
1 2 |
# ls -l snmptt.conf.* | wc -l 86 |
“ZBXTRAP” の文字列が存在しない(トラップ定義のない)ファイルのみを削除
1 |
# grep -L ZBXTRAP ./* | grep '^./snmptt.conf' | xargs rm |
削除後の snmptt.conf ファイル数(だいぶ整理できました)
1 2 |
# ls -l snmptt.conf.* | wc -l 25 |
snmptt.ini ファイルにこれらファイルのパスを追記すれば、各 snmptt.conf ファイルに定義されたフォーマットでトラップが出力されます。
だいたいここぐらいまでは(手順はそれぞれと思いますが)構築の流れでやりますよね。
snmptt.conf の内容を CSV ファイルに変換する
これらファイルと内容を一覧にするためのシェルスクリプトを紹介します。
スクリプト名は “list_snmp_trap.sh” とでもしておきましょうか。
ウーン地味。。。ですが、実用性って大事です!
スクリプトのメイン機能自体はすぐ作れる簡単なものですが、ヘルプとかもちゃんと入れてみました。(オモイヤリポイント)
snmpttのマニュアルによると “SDESC” ~ “EDESC” 部分は必ずあるわけではなくオプション扱いとなっているようですので、若干変則のループ処理になっています。
http://snmptt.sourceforge.net/docs/snmptt.shtml#SNMPTT.CONF-SDESC
list_snmp_trap.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#!/bin/bash set -ou pipefail HELP=$(cat << _EOS_ _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ _/_/_/_/_/_/_/_/_/_/ _/_/_/_/_/ << list_snmp_trap.sh >> _/_/ _/_/ Dscriprion: _/_/ _/_/ - This script converts the 'snmptt.conf' files into a manageable _/_/ '.csv' format, and output to stdout. _/_/ _/_/ - The 'snmptt.conf' is the file that are converted from MIBs file _/_/ using following command. ( See 'snmpttconvertmib --help' ) _/_/ _/_/ snmpttconvertmib --in=<MIBs file> --out=<snmptt.conf> --net_snmp_perl _/_/ _/_/ Usage: _/_/ _/_/ ${0} <snmptt_conf_dir> _/_/ _/_/ Option: _/_/ _/_/ <snmptt_conf_dir> - Mandatory option. _/_/ - This script processes all files in the _/_/ specified directory. _/_/ _/_/ Example: _/_/ _/_/ ${0} ./snmptt.conf.d _/_/ _EOS_ ) if [[ ${#} -ne 1 ]]; then echo "${HELP}" >&2 exit 1 fi if [[ ${1} = '-h' ]] || [[ ${1} = '--help' ]]; then echo "${HELP}" >&2 exit 1 fi SNMPTT_CONF_DIR=${1} if [[ ! -d ${SNMPTT_CONF_DIR} ]]; then echo "Directory '${SNMPTT_CONF_DIR}' doesn't exist." >&2 exit 1 fi echo '"snmptt.conf","EVENT_NAME","EVENT_OID","EVENT_CATEGORY","EVENT_SEVERITY","FORMAT","DESCRIPTION"' FILES=(`find ${SNMPTT_CONF_DIR} -maxdepth 1 -type f`) for FILE in ${FILES[@]}; do TEXT=`cat ${FILE} | \ sed -n -e '/^EVENT/p' -e '/^FORMAT/p' -e '/^SDESC$/,/^EDESC$/p' | \ sed -e '/^Variables:$/,/^EDESC$/{/^EDESC/!d}'` [[ -z ${TEXT} ]] && continue INDEX=0 EVENT_NAME=() EVENT_OID=() EVENT_CATEGORY=() EVENT_SEVERITY=() FORMAT=() DESC=() { read LINE if [[ ${?} -eq 0 ]]; then eval "ITEMS=(`sed -e 's/^EVENT //' -e 's/ / "/' -e 's/ /" /2' <<< ${LINE}`)" EVENT_NAME[${INDEX}]=${ITEMS[0]} EVENT_OID[${INDEX}]=${ITEMS[1]} EVENT_CATEGORY[${INDEX}]=${ITEMS[2]} EVENT_SEVERITY[${INDEX}]=${ITEMS[3]} DESC[${INDEX}]='' while read LINE; do if [[ ${LINE} =~ ^FORMAT ]]; then FORMAT[${INDEX}]=`sed -e 's/^FORMAT //' <<< ${LINE}` elif [[ ${LINE} =~ ^SDESC$ ]]; then while read LINE; do [[ ${LINE} =~ ^EDESC$ ]] && break DESC[${INDEX}]+="${LINE}\n" done DESC[${INDEX}]=`echo -e "${DESC[${INDEX}]}" | sed -e '/^\s*$/d'` elif [[ ${LINE} =~ ^EVENT ]]; then INDEX=$(( ${INDEX} + 1 )) eval "ITEMS=(`sed -e 's/^EVENT //' -e 's/ / "/' -e 's/ /" /2' <<< ${LINE}`)" EVENT_NAME[${INDEX}]=${ITEMS[0]} EVENT_OID[${INDEX}]=${ITEMS[1]} EVENT_CATEGORY[${INDEX}]=${ITEMS[2]} EVENT_SEVERITY[${INDEX}]=${ITEMS[3]} DESC[${INDEX}]='' fi done fi } <<< "${TEXT}" for (( ID=0; ID <= ${INDEX}; ID++)); do echo "\"`basename ${FILE}`\",\"${EVENT_NAME[${ID}]}\",\"${EVENT_OID[${ID}]}\",\"${EVENT_CATEGORY[${ID}]}\",\"${EVENT_SEVERITY[${ID}]}\",\"${FORMAT[${ID}]}\",\"${DESC[${ID}]}\"" done done exit |
使い方
./list_snmp_trap.sh <snmptt.conf ファイルが配置されたデイレクリパス>
※ DESCRIPTION 内の “Variables:” 部分は除く(文が長すぎる場合があるため)
例
1 |
# ./list_snmp_trap.sh /etc/snmp/snmptt.conf.d > trap_list.csv |
結果
実行しますと下記のような内容のファイルができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# cat trap_list.csv "snmptt.conf","EVENT_NAME","EVENT_OID","EVENT_CATEGORY","EVENT_SEVERITY","FORMAT","DESCRIPTION" ~~~~~~~~~~~~ 省略 "snmptt.conf.IF-MIB.txt","linkDown",".1.3.6.1.6.3.1.1.5.3","Status Events","Normal","ZBXTRAP $aA $N - $+*","A linkDown trap signifies that the SNMP entity, acting in an agent role, has detected that the ifOperStatus object for one of its communication links is about to enter the down state from some other state (but not from the notPresent state). This other state is indicated by the included value of ifOperStatus." "snmptt.conf.IF-MIB.txt","linkUp",".1.3.6.1.6.3.1.1.5.4","Status Events","Normal","ZBXTRAP $aA $N - $+*","A linkUp trap signifies that the SNMP entity, acting in an agent role, has detected that the ifOperStatus object for one of its communication links left the down state and transitioned into some other state (but not into the notPresent state). This other state is indicated by the included value of ifOperStatus." ~~~~~~~~~~~~ 省略 |
では、表計算ソフトで表示してみましょう。
一覧ができましたねえ。
そのまま詳細設計書や、運用管理ドキュメントの元ネタに使用できます。
終わりに
大変地味なトピックとなりましたが、(インフラの仕事って地味な作業多いんです)実は、表計算ソフト上で severity やフォーマットを編集して CSV から snmptt.conf ファイルを逆コンバートするスクリプトも作成してます。
こちらは、またの機会に!
一連の動作を簡単な Web CGI なんかで動作させれば、簡易的な SNMP トラップ管理ユーティリティとして使うようなアイデアもありますよね!
※ この障害のトラップは影響度が高く、管理者へメールする対象にしたいから WEB UI から severity を “Critical” に変える、、とかそういったイメージ。
システムソリューション部の優秀な方々、(新人教育の一環でもいいから)誰か作ってちょ!!
インフラエンジニアってラック建てたり LAN ケーブル張ったり、機器設置する物理作業から、こういったちょっとした工夫のためのスクリプト書いたり、物理から論理まで幅が広くて楽しいですよ!