bash を使って zabbix_get.sh を作ってみる
zabbix_get と同等のものを bash とその他一般的なコマンドラインツールだけを使って作ってみました。
きっかけは、@sechiro さんからの RT で、 bash では /dev/tcp を使うとネットワーク通信ができるということを知ったので、試しに作ってみました。
zabbix_get のプロトコル解説
まず、zabbix_get を自作するにあたり、zabbix_get のプロトコルを解説します。
Zabbix agent の動作しているマシンの 10050 ポートに監視キーをそのまま文字列で送りつける。
以上。
ヘッダも何もありません。
楽です。(追記: その後よく見たところ、これは旧版のプロトコルのようです。ただ、最新のZabbix1.8.3でも互換性のために、server側はこの形式でデータを送信していました。zabbix_getではまた別の新版のプロトコルでした。)
返ってくるデータにはヘッダがあります。ヘッダ部分は、Zabbix Sender のプロトコル解説の P.7 と同じ構造になっています。
データ部分は、Zabbix Sender とは異なり、JSONではなく、じかに監視結果が入っているだけになります。
例えば、'system.cpu.load[all,avg1]'を送ると、以下のようなデータが返ってきます。
16進数で表記していますが、ASCIIで表示できるところは()で表記しています。
以下のデータでは、監視結果として「1.700000」が返ってきていることがわかります。
送信データ
data (key) |
73(s) 79(y) 73(s) 74(t) 65(e) 6D(m) 2E(.) 63(c) 70(p) 75(u) 2E(.) 6C(l) 6F(o) 61(a) 64(d) 5B([) 61(a) 6C(l) 6C(l) 2C(,) 61(a) 76(v) 67(g) 31(1) 5D(]) |
受信データ
header | protocol version |
data length (uint64 LE) | data (result) |
5a(Z) 42(B) 58(X) 44(D) | 01 | 08 00 00 00 00 00 00 00 | 31(1) 2e(.) 37(7) 30(0) 30(0) 30(0) 30(0) 30(0) |
コード
制限がほとんど無い、DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE にしておきました。
どうせネタだしね。。。
https://github.com/BlueSkyDetector/code-snippet/tree/master/bash-zabbix-tools
ポイントは以下の部分になります。
ファイルディスクリプタ3にZabbixエージェントのポートを割り当てて、監視キーを流し込んで、それで返ってきた結果をRETに入れてます。
$RETに代入するところで od とかを使っているのは、バイト列をテキストの16進数表示に変換しているためです。
...snip exec 3<>/dev/tcp/${server}/${port} echo -n "${key}" >&3 RET=$(cat <&3 | od -v -An -tx1 | while read line; do echo -n "$line "; done) ...snip
それ以降は、get_in_hex_text_le や get_in_text といった関数を使って、$RETから任意の箇所のデータをバイト列やテキスト変換してから処理しています。
今回 bash でバイナリを扱うにあたり、バイナリをテキストの16進数表示に変換して保存しておくことがコツなのではないか、と少しわかった気がします
使用方法
zabbix_get.sh をそのまま実行すると使用法が表示されます。
$ zabbix_get.sh usage: zabbix_get.sh -s <host name or IP> [-p <port>] -k <key> Options: -s <host name or IP> Specify host name or IP address of a host. -p <port number> Specify port number of agent running on the host. Default is 10050. -k <key of metric> Specify metric name (key) we want to retrieve. -v Verbose mode. Example: zabbix_get.sh -s 127.0.0.1 -p 10050 -k "system.cpu.load[all,avg1]"
実際に実行してみます。
$ zabbix_get.sh -s 192.168.0.16 -p 10050 -k "system.cpu.load[all,avg1]" 1.490000
vorboseモードも作ってみました。
一応ヘッダの文字列やデータの長さも取得できるようにしています。
$ zabbix_get.sh -s 192.168.0.16 -p 10050 -k "system.cpu.load[all,avg1]" -v raw data: 5a 42 58 44 01 08 00 00 00 00 00 00 00 31 2e 37 30 30 30 30 30 header: "ZBXD" ...ok version: "0x01" ...ok length: 8 data: 1.700000 1.700000
zabbix_top.sh
zabbix_get.sh と同じ内容のコードを使って zabbix_top.sh も作ってみました。
zabbix_top.sh の表示内容は @mikeda さんの zabtop を参考にしてみました。
が、やっているうちにやる気が衰えたために、zabtop のような%の計算とかはできてません。
$ zabbix_top.sh usage: zabbix_top.sh -s <host name or IP list> [-r <sec>] [-d] Options: -s <host name or IP> Specify host name or IP address list of a hosts. Such as "host1 host2 host3" -r <sec> Refresh rate. -d Debug mode. Example: zabbix_top.sh -s "host1 host2 host3" -r 1 -d
$ zabbix_top.sh -s '192.168.0.16 192.168.0.166' server name: load_avg1 load_avg5 load_avg15 mem_avail mem_total swap_used cpu_user cpu_system cpu_idle cpu_wait cpu_nice 192.168.0.16 : 1.870000 1.660000 1.680000 399609856 1046474752 11.331122 9.697584 4.223686 55.735766 29.278594 0.625106 192.168.0.166 : 3.540000 3.350000 3.500000 277200896 2078892032 41.327874 7.055448 6.616592 85.981939 0.151912 0.118153