はじめに
Zabbix は、Zabbix API を通して操作することができますが、言語毎に Zabbix API ライブラリ が複数種存在しているため、どれを使用すればいいか分かりづらい状態です。加えて、Zabbix API は非常に膨大なメソッド (Method reference) とオプションを持つため、各種ライブラリが、そのどれだけを保証範囲とし保守するのかまで突き詰めると選定は非常に困難になるでしょう。
これはあくまで私の持論ですが、全容を把握できない保守の保証もないライブラリを使うくらいならば、時間がかかっても大本を理解するほうがよいと思っています。Zabbix API を使いたいのに、Zabbix API ライブラリに骨を折るのは本末転倒です。
ありがたいことに Zabbix API の仕組みは非常に単純です。この記事では、Zabbix API について説明した後、最小限に Zabbix API を利用する実装を紹介したいと思います。もし、誤りなどがあれば 優しく 指摘していただけると幸いです。
JSON-RPC 2.0
Zabbix API は、要求-応答のプロトコルに JSON-RPC 2.0 を使用しています。JSON-RPC は、データ形式に JSON を使用した状態を保持しない軽量の RPC (Remote Procedure Call) プロトコルです。仕様が非常に短いので、仕様を読むことが最も手軽で正しく内容を理解する近道になるでしょう。そのため、ここでは後の説明に必要な部分のみを説明します。
JSON-RPC 2.0 での要求は、jsonrpc
、method
、params
、id
から構成されます。jsonrpc
は JSON-RPC のヴァージョン番号で "2.0"
、method
は呼び出す手続きの名称、params
は呼び出した手続きに渡す引数 (省略可)、id
は要求と応答のひも付けを行うための識別子でクライアント側で決めた値となります。手続名と引数を JSON 形式で送ってやるだけという非常に分かりやすい作りです。
{
"jsonrpc": "2.0",
"method": "hoge",
"params": {
"foo": "bar",
"spam": "ham"
},
"id": 1
}
他方、JSON-RPC 2.0 での応答は、jsonrpc
、result
もしくは error
、id
から構成されます。jsonrpc
は JSON-RPC のヴァージョン番号で "2.0"
、result
は要求が成功した場合の返し値、error
は要求が失敗した場合のエラー情報、id
は要求に対応する識別子と同じ値となります。要求同様、結果もしくはエラーが JSON 形式で返ってくるだけという非常に分かりやすい作りです。
{
"jsonrpc": "2.0",
"result": "hoge",
"id": 1
}
{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Invalid params",
"data": "hogehoge"
},
"id": 1
}
Zabbix API
Zabbix API と JSON-RPC 2.0 の節での説明で異なるのは、要求に auth
が含まれる点だけです。auth
はユーザ認証用のトークンで、Zabbix API における user.login
メソッドを叩くことで得られます。user.login
メソッドを叩く時は auth
は null
で構いません。
{
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"user": "Admin",
"password": "zabbix"
},
"id": 1,
"auth": null
}
{
"jsonrpc": "2.0",
"result": "0424bd59b807674191e7d77572075f33",
"id": 1
}
user.login
メソッドの返し値としてトークンを得ることができれば、後はそのトークンを auth
に入れ、JSON-RPC 2.0 の要求-応答の仕組みに則って、やり取りをすれば良いだけです。
{
"jsonrpc": "2.0",
"method": "host.get",
"params": {
"output": [
"hostid",
"host"
],
"selectInterfaces": [
"interfaceid",
"ip"
]
},
"id": 2,
"auth": "0424bd59b807674191e7d77572075f33"
}
{
"jsonrpc": "2.0",
"result": [
{
"hostid": "10084",
"host": "Zabbix server",
"interfaces": [
{
"interfaceid": "1",
"ip": "127.0.0.1"
}
]
}
],
"id": 2
}
最小限に Zabbix API を利用する実装
最小限に Zabbix API を利用したい場合、以下のクラスを作っておけば事足ります。インスタンス作成時に認証を行い、トークンをインスタンス内で保持しておき、以降は適当に method
と params
を与えて応答を受け取る。応答に、成功時は result
が、失敗時には error
が含まれているはずなので分岐させて処理を行う。
# -*- coding: utf-8 -*-
import json
import urllib
import urllib2
class ZabbixApi(object):
def __init__(self, host, user, password):
"""Zabbix API インスタンスを返す
:param host: Zabbix サーバの IP アドレス
:param user: Zabbix API のアクセスユーザ
:param password: Zabbix API のアクセスユーザパスワード
:return:
"""
self.request_id = 1
self.host = host
self.auth_token = self.request('user.login', {'user': user, 'password': password})
def request(self, method, params, auth_token=None):
"""Zabbix API にリクエストを送信する
id は現行特に必要ないため単純にインクリメントした数値を代入している。
:param method: Zabbix API のメソッド名
:param params: Zabbix API のメソッドの引数
:param auth_token: Zabbix API の認証トークン
:return: JSON-RPC2.0 形式の応答
"""
if hasattr(self, 'auth_token'):
auth_token = self.auth_token
headers = {"Content-Type": "application/json-rpc"}
uri = "http://{0}/zabbix/api_jsonrpc.php".format(self.host)
data = json.dumps({'jsonrpc': '2.0',
'method': method,
'params': params,
'auth': auth_token,
'id': self.request_id})
request = urllib2.Request(uri, data, headers)
self.request_id += 1
return json.loads(urllib2.urlopen(request).read())
if __name__ == '__main__':
api = ZabbixApi(192.168.0.2, 'Admin', 'zabbix')
response = api.request('host.get', {'output': 'hostid', 'search': {'host': 'hoge'}})
if 'result' in response:
pass # 成功時の処理
elif 'error' in response:
pass # 失敗時の処理
else:
pass # 不具合時の処理
実際に Zabbix API ライブラリの幾つかは、上のような内容のコードだけだったりします。ですので、JSON-RPC 2.0 と auth
を理解できさえすれば、不要なライブラリを導入するのではなく、自身の必要にあった軽量の実装を行ったほうが後々楽になるかもしれません。
まとめ
この記事では、Zabbix API で使用されている JSON-RPC 2.0 を簡単に説明した後、Zabbix API の仕組みについて触れ、最小限に Zabbix API を利用するための実装を紹介しました。
Zabbix API のドキュメント群は非常に膨大なため、その量に圧倒され、難しいものと思い込んでしまいそうになりますが、いざ腰を据えて見て見ると実に単純で分かりやすいものでした。メソッドにどのような引数を渡せばいいのかは難しかったりするのですが…。
この記事で、Zabbix API へのハードルが下がり、より安心の運用に繋げて頂ければ幸いです。