Zabbixのデータベースを覗くと幸せになれるかもしれない


## レガシィな方法でZabbixとお付き合いする

さっそくタイトルと内容あってないんじゃねぇの？というスタートですが、お付き合いください。

さて、Zabbix 2.2以前（だっと思う）は、SNMPTrapを受信した場合の、検知方法として、zabbix_senderで値を渡すか、ログ出力してそのログを監視する方法しかありませんでした。

それが、SNMPTTなどのあらたなプログラムを導入することで、ちょっと便利になるのですが、学習コストが高かったり、運用側に説明するのが大変だったりと、移行の妨げになったりしなくもないわけです。

いまだに古いZabbixが稼働していたりして、SNMPTrapの受信を旧方式から変えられない・・・なんて方もいらっしゃると思います。

たとえば、Trap受信アイテムを一つで運用していたり・・・本当は、ホストごとに分けたいんだけど、ホスト登録事に変更するのが大変だから…のような状況に陥ってませんか？

## SNMPTrap受信を考えてみる

SNMPTrapの受信は、snmptrapdで受け取りますよね？
ZabbixのオフィシャルなSNMPTrap監視は、SNMPTTもしくは付属のPerlスクリプトを使って、snmptrapdで受け取ったものを、成形して受信するようになってます。
（SNMPトラッパーが働きます）

しかしながら、古いZabbixシステムではそのような仕組みがなかったので、snmptrapdが受信したものをなにかしらのスクリプトで受けて処理したりしていました。
(Trapperプロセスが働きます)

旧Zabbixでも以下で紹介する方法で、各ホスト宛てに投げ込めたりするのですが、どういうわけかやってなかったりするのです。（ひとつのtrapアイテムで頑張ってたりする）

ではZabbix3.0系を例にとって、各ホストが発したトラップを各ホストの情報としてZabbixに渡す！をやってみようと思います。

## 実践
### 前提

- 登録してあるホストには、snmptrapというキーのアイテムを作成しておきます。
- SNMPTrapをそのまま投げ込みますので、テキストで受けるようにしてください。
- アイテムタイプはZABBIXトラッパーを指定します。

### zabbix_senderの使い方

```
zabbix_sender -z $ZABBIX_IP -s $HOST_NAME -k $KEY_NAME -o $VALUE
```

### snmptrapd の設定

適当にググったらたくさん出てくるので割愛

### Script で処理する

今回は、Shell Scriptでやります。PerlでもPHPでもRubyでもPythonでもなんでもいいです。
そのへんは、読み替えて実装ください。
Shell Scriptでやるのは、たいていのばあい何もしなくても動くから。。。以上。

本題。
SNMPTrapdで受け取った情報は、標準入力から取得が可能です。
ですので・・・

```
#!/bin/bash

_trap=()                       #あとで使い回しが楽なように配列で宣言

while [ 1 ] ;do

 read _LINE || break	       # 標準入力がなくなったらwhile抜ける
 _trap+="${_LINE} "            # 受けた文字列をスペース区切りで格納

done

echo ${_trap[@]} >> trap.log

```
これだけの処理で、テキストファイルへの書き出しが可能です。
※logオプション使えよっていうのは置いておく。

今のZabbixでのSNMPTrap監視は、この受信トラップをうまいことパースしてくれたりするわけですが、OIDのまんま受け取るからSNMPTTじゃなくていいし！！って場合とかは特にいらなくね？ってなるわけです。

これをログファイルではなく、Zabbixの画面から個別ホストの情報
としてみたい！！としたときはどうしたら良いでしょうか？

Zabbixは、zabbix_senderで通知された情報のうち、Zabbixに登録された
ホスト名とそのホストにあるアイテムキーをもとに、情報を保存します。
※Activeチェックなログとかも基本的には同じ仕組みだと思われ。

受信したトラップは・・・
```
host_name UDP: [XXX.XXX.XXX.XXX]:aaaaa->[Zabbix_IP]:162 ～～～
```
のようになっているはずです。

このとき、正常に名前解決ができる状態であれば、host_nameの箇所にホスト名
が記載されますが、必ずしもZabbixに登録している名前と一致しないか、unknown
となることが予想されます。

しかし、[XXX.XXX.XXX.XXX]は送信元アドレスであるので、Zabbixにホスト登録
があるはずです。じゃなければZabbixに飛ばしてこないですよね？？？
（なければ無視するとかも有りですね）

と、いうわけでZabbixのDBからホスト情報を拝借します。

※適当なREAD権限をもったユーザをつくることをお勧めします。

さて、それでは本題のDBのぞいて、必要な情報もってこようぜ！！な話ですね。

## DBを覗くよ！！

MySQL/MariaDB はコマンドベースでSQLが発行できます。

```
> # mysql -uDBUSER -pPASSWD -e "show databases;" 
```
※DBUSER PASSWD はDBアクセス用のユーザを作成してる前提※

と、コマンドラインから打つと、データベース一覧が表示されます。
そのデータベースにどのよなテーブルが構成されているかは、

```
> # mysql -uDBUSER -pPASSWD -e "show tables from zabbix;
```

とかやると、テーブル情報がだだーーーーーっとでてきます。
各テーブルにはどんなカラムがあるのーーーー？ってのは

```
> # mysql -uDBUSER -pPASSWD -e "show columns from zabbix.hosts;"
```
とやると、カラムの情報がだだーーーーっと出ます。

ちなみに、zabbix.hostsテーブルは、Zabbixに登録されているホスト情報が入っているテーブルです。
では、中身を見てみましょう。

```
> # mysql -uDBUSER -pPASSWD -e "select * from zabbix.hosts;"
```

いっぱい出てきてよくわかんね。。。ってなりますね？
まぁ・・・そうなります。

表示されるデータのうち、とりあえず必要そうな項目はどれかなぁ・・・
のあたりをつけましょう。

```
> # mysql -uDBUSER -pPASSWD -e "show columns from zabbix.hosts;"
```

このコマンドでカラム名が表示されているのだから、なんとなくわかるかもしれない！！

と、いうことで

```
> # mysql -uDBUSER -pPASSWD -e "select hostid,host from zabbix.hosts;"
```

とやると、ホストIDと登録ホスト名（表示名ではない）の一覧が表示されるはずです。
しかし、さきほどのカラムの情報を見てもip に関する箇所がないことに気付くと思います。

Zabbixいくつからかは忘れましたが、インターフェースを複数登録できるようになったため、インターフェース情報が別テーブルで管理されるようになりました。
そのため、intarfaceテーブルを参照する必要があるわけです。

ただ、このinterfaceというテーブルは、
hostid,ip
の二つのカラムしかありません。
ホスト名を知るために、このhostidを入手して、対象となるホストを割り出します。

実行するSQLは

```
 SELECT hostid from zabbix.interface where ip = 'IP_ADDR';
```

です。これでhostidがわかります。
このhostidを使って、hostsテーブルからホスト名を抜けばいい！というわけです。

```
 SELECT host FROM zbbix.host WHERE hostid = ${_HOSTID}";
```

うん。簡単。

このへんのテーブル構造とかは、適当にしらべてみてください。ネットにも情報があったりしますが、オフィシャルなものは無いようです。

ちなみに私は、普通にSQL叩いて眺めて、「ふ━━（ ´_ゝ｀）━━ん」ってなった感じです。

SQL文はもっと複雑な検索もできるので、構造を押さえておけば一撃で探し出すこともできます。

```
SELECT
	host						※お名前おしえて
FROM
	zabbix.hosts					※hostsテーブルからもってくる
INNTER JOIN
	zabbix.interface 				※インターフェースくっつける
ON
	zabbix.hosts.hostid = zabbix.interface.hostid	※両方のhostidをキーに結合する
WHERE
	ip='_IP_ADDR_';					※このIPもってるやつ誰？
```

とかって書けば、一撃で目的のホスト名が取れるわけです。※これがイケてるSQLなのかは知らない。

このホスト名をつかって

```
zabbix_sender -z ${_ZABBIX_SERVER} -s "${_HOSTNAME}" -k snmptrap -o "${_traps[@]}"
```

ってやってあげると、対象のホストに値を投げ込める！！！というわけです。

これが出来ると、なにが嬉しいのかって、Zabbixでなんでも監視できるようになる！！！
と、いうことになります。

たとえば、なにかをトリガーにもう１回なにかチェックしたい・・・とか。

Aサーバのサービスからが応答ありません！！！！

まじか！？でも次の周期までだと遠いし、たまに胡散臭い挙動してるし・・・もう１回だけチェックできれば・・・

そんなとき！！！
とかに役立ちます。

アラートだー！！→スクリプトキック→やっぱだめでした→正式アラート。
アラートだー！！→スクリプトキック→誤報でした→そっクロ（そっとクローズ）

今回は、SNMPTrapを例に書きましたが、このレガシーなやりかたは、推奨されるかどうかは別として、意外と役に立ちます。

※登録ホスト数とかが多かったりすると、無駄な負荷をかけることになるかもなので、
　夜中に１回ホストリスト作るとかの方法が良いのかもしれませんが、環境によるので
　そのへんは、よしなに。。。

```　
mysql -e "SELECT host,ip FROM zabbix.hosts INNTER JOIN zabbix.interface ON zabbix.hosts.hostid = zabbix.interface.hostid" | sort | uniq > host.list
```
とかやれば、すぐホストリスト作れちゃうしね。。。

と、いうわけでレガシーな方法も役に立つ講座でした。
（あれ、主題が変わっている・・・）


※API使えよ。とか言わないで…