bash を使って zabbix_get.sh を作ってみる


zabbix_get と同等のものを bash とその他一般的なコマンドラインツールだけを使って作ってみました。
きっかけは、@ さんからの 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 の表示内容は @ さんの 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