【Zabbix】監視の正常性を監視する仕組み

#■監視ツールを監視する必要性
監視はミッションクリティカルではないものの、監視でサービス停止を検知ができなかった場合、サービスへの影響が出たことに気付いた時点から対応が始まることになるため、迅速な対処ができない。

監視ツール側or監視対象側の問題どちらにせよ、バグを含め、突然監視ができなくことは、しばしばあることである。

単純な話だと、ログがローテーション時にパーミッションが変わってしまって、監視ユーザからログファイルを読み取れなくなってしまったり、監視ツールで、Windowsのパフォーマンスカウンタ値を収集している場合は、パフォーマンスオブジェクトの値が数字の羅列になってしまい、値が取れなくなるなど、恐ろしい現象まで存在する。
[参考URL:]https://support.microsoft.com/ja-jp/kb/152513

監視が正常にできている仕組みを考える必要がある。

#■Zabbixでの監視正常性確認（アイテム取得不可対応）
Zabbixでの監視正常性確認の方法は様々あって、代表的なものでは、アイテムキーagent.pingを使用したものだが、実際に特定のアイテムのみが取得できなくなった場合は、これでは対処できない。

アイテム監視には、zabbix[items] 、zabbix[items_unsupported] などを取得して監視すれば、アイテム数の変動を検知できるが、"このアイテム自体が取得できなくなった場合は気づけない"のと、"あくまで数のみを監視しているため、どのアイテムが取得できなくなったかわからない(※)"という問題になる。
※あらかじめ、全て監視できていれば問題ないが、監視できてなくて良いものを放置している(orこれから監視対象のログファイルを置くから事前に監視だけていれておいて、監視できていない状態を容認している)場合などがある。

これを解消するため、Zabbixサーバ側で、監視できていない項目をMySQLから抽出するようにした。

#■SQL解説
itemid、hostidはデータベースにあるユニークな値で都合上入れているのだが、GUIからみえるものをSQLでSELECTすることにしている。host=ホスト名、name=名前、key_=キー、item_status=ステータス（アイテム設定が有効）、host_status=ステータス（ホスト設定が有効）、available=エージェントの状態、error=エラーとなるよう紐づけた。GUIとSQLの結果を比較してほしい。

監視できていない場合は、errorカラムに何らかの文字列が出力される。ここでは、ZBX_NOTSUPPORTEDである。そのため、items.error != "";をwhere句に入れることで、監視できていないアイテムを抽出することにしている。

##●監視できていないアイテムを抽出するSQL

```
mysql>select items.itemid,items.hostid,hosts.host,items.name,items.key_,items.status as host_status,hosts.available,items.error from items INNER JOIN hosts ON items.hostid = hosts.hostid where hosts.status = 0 and hosts.available = 1 and items.status = 0 and items.error != "";
+--------+--------+---------------+------------------------+------------------------------+-------------+-----------+------------------+
| itemid | hostid | host          | name                   | key_                         | host_status | available | error            |
+--------+--------+---------------+------------------------+------------------------------+-------------+-----------+------------------+
|  23660 |  10084 | Zabbix server | ログ監視[messages]     | log[/var/log/messages,error] |           0 |         1 | ZBX_NOTSUPPORTED |
+--------+--------+---------------+------------------------+------------------------------+-------------+-----------+------------------+
1 row in set (0.00 sec)
```
![zabbix3.png](https://qiita-image-store.s3.amazonaws.com/0/98996/1086a805-a14c-db54-bc74-ba19136273db.png)

![zabbix2.png](https://qiita-image-store.s3.amazonaws.com/0/98996/cdeed305-1d81-3e2e-f3b3-8d27d1abfbd6.png)

##●監視できているアイテムを抽出するSQL
監視できている場合は、items.error = ""とすればよいので、以下のようになる。

```
mysql>select items.itemid,items.hostid,hosts.host,items.name,items.key_,items.status as host_status,hosts.available,items.error from items INNER JOIN hosts ON items.hostid = hosts.hostid where hosts.status = 0 and hosts.available = 1 and items.status = 0 and items.error = "";
+--------+--------+---------------+------------------------------------+--------------------------+-------------+-----------+-------+
| itemid | hostid | host          | name                               | key_                     | host_status | available | error |
+--------+--------+---------------+------------------------------------+--------------------------+-------------+-----------+-------+
|  23287 |  10084 | Zabbix server | Agent ping                         | agent.ping               |           0 |         1 |       |
|  23288 |  10084 | Zabbix server | Version of zabbix_agent(d) running | agent.version            |           0 |         1 |       |
|  23299 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,idle]   |           0 |         1 |       |
|  23301 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,iowait] |           0 |         1 |       |
|  23302 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,nice]   |           0 |         1 |       |
|  23305 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,system] |           0 |         1 |       |
|  23306 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,user]   |           0 |         1 |       |
|  23307 |  10084 | Zabbix server | Host name                          | system.hostname          |           0 |         1 |       |
|  23312 |  10084 | Zabbix server | System information                 | system.uname             |           0 |         1 |       |
|  23313 |  10084 | Zabbix server | System uptime                      | system.uptime            |           0 |         1 |       |
+--------+--------+---------------+------------------------------------+--------------------------+-------------+-----------+-------+
```

##●設定が有効になっているものを抽出するSQL
設定が入っていて、取得できているかいないかを関係なく出力する場合は以下である。

```
mysql>select items.itemid,items.hostid,hosts.host,items.name,items.key_,items.status as host_status,hosts.available,items.error from items INNER JOIN hosts ON items.hostid = hosts.hostid where hosts.status = 0 and hosts.available = 1 and items.status = 0;
+--------+--------+---------------+------------------------------------+------------------------------+-------------+-----------+------------------+
| itemid | hostid | host          | name                               | key_                         | host_status | available | error            |
+--------+--------+---------------+------------------------------------+------------------------------+-------------+-----------+------------------+
|  23287 |  10084 | Zabbix server | Agent ping                         | agent.ping                   |           0 |         1 |                  |
|  23288 |  10084 | Zabbix server | Version of zabbix_agent(d) running | agent.version                |           0 |         1 |                  |
|  23660 |  10084 | Zabbix server | ログ監視[messages]                 | log[/var/log/messages,error] |           0 |         1 | ZBX_NOTSUPPORTED |
|  23299 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,idle]       |           0 |         1 |                  |
|  23301 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,iowait]     |           0 |         1 |                  |
|  23302 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,nice]       |           0 |         1 |                  |
|  23305 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,system]     |           0 |         1 |                  |
|  23306 |  10084 | Zabbix server | CPU $2 time                        | system.cpu.util[,user]       |           0 |         1 |                  |
|  23307 |  10084 | Zabbix server | Host name                          | system.hostname              |           0 |         1 |                  |
|  23312 |  10084 | Zabbix server | System information                 | system.uname                 |           0 |         1 |                  |
|  23313 |  10084 | Zabbix server | System uptime                      | system.uptime                |           0 |         1 |                  |
+--------+--------+---------------+------------------------------------+------------------------------+-------------+-----------+------------------+
11 rows in set (0.00 sec)
```

#カラム解説
host、name、key_はみたままなので、割愛する。

それ以外は、
host_status…0は有効、1は無効、3はテンプレート？
available…0がテンプレート？、1が正常(GUI上緑)、2が以上(GUI上赤)
items.status=0が有効、1が無効
となっているようです。

items.statusのSQLの結果を出力させていないのは、アイテム取得不可となった場合、GUI上のステータスは"取得不可"と表示されますが、設定上は"有効"のままとなっているため、SQL出力するとやや混乱すると思ったためです(私の主観の問題かもですが)。

そのため、where句でhosts.status=0、available=1、items.status=0、で正常に監視設定が入っている条件を入れたうえで、エラーとなっているものを出力することで、監視できていないアイテムを抽出することが可能である。

#スクリプト
スクリプト(/root/Tools/bin/zabbix-check.sh)を作成しました。ディレクトリ構成はシェルの中身の変数をみて確認してください。。


```zabbix-check.sh
#!/bin/bash
#
# zabbix-check.sh                                       ver.1.0.0  2016.01.17
#
# Author:
#     hogehoge hogehoge
#
# Usage:
#     zabbix-check.sh
#
# Description :
#     This script checks zabbix-items-status.
#
# Caution:
#     You must make $MASTER,$SQL before this script executes.
#
#########################################################################

### Variable
MASTER=/root/Tools/etc/master
TRAN=/root/Tools/etc/trans.txt
SQL=/root/Tools/sql/items.error.sql
LOGS=/root/Tools/log/zabbix-check.log
DATE=`date "+%Y%m%d %H:%M"`
MAIL_TO=hogehoge@hogehoge.com
MAIL_FROM=hogehoge2@hogehoge2.com
SUBJECT=Zabbix-Check

### SQL Execute
mysql -uroot -phogehoge zabbix < ${SQL} > ${TRAN}

### diff
diff ${MASTER} ${TRAN}

if [ $? = 0 ]; then
    echo "${DATE} zabbix-check OK" > ${LOGS}
    echo "zabbix-check OK" | mail -s ${SUBJECT} -r ${MAIL_FROM} ${MAIL_TO}

else
    echo "${DATE} zabbix-check error" > ${LOGS}
    echo "zabbix-check error" | mail -s ${SUBJECT} -r ${MAIL_FROM} ${MAIL_TO}
fi
```

事前に実施することは、以下となります。
・"監視できていないアイテムを抽出するSQL"を、items.error.sqlとして作成
・masterの作成。特に監視できていないアイテムがないのようであれば、空ファイルでＯＫ

masterとtransファイルを比較して、差分がある場合は、ログにerror出力したうえで、メール送信(ログを監視してもいいが、その監視もできなくなった場合も想定し、メール送信)。

cronに登録して、定期的にチェックするようにしましょう(日次ぐらい)。

#その他
トリガーや他にも応用できると思うので、良かったらやってみてください。
スクリプトをGithub上にあげましたので、最新版はこちらをご確認ください。
[Github]https://github.com/domonjo01/zabbix-check