【5.0対応済】Python3を使ってZabbix APIを呼び出そう(はじめてのZabbix API)

2020年7月28日Python,Zabbix,Zabbix API

こんにちは。プラットフォーム技術部の飯出(いいで)です。

近年、日本市場でもZabbixが普及し、私たちZabbix認定パートナー企業もZabbix監視環境の新規構築やバージョンアップ、他の監視システムからの移行依頼を受けることが多くなっています。

そして、Zabbixフロントエンド(Zabbix WebUI)をはじめとする監視設定や運用支援のお問い合わせを受けることが多いのですが、Zabbix APIに関するお問い合わせはほぼありません。

しかし、Zabbix APIを使う上で自動化できる業務(作業)は結構あると思います。Zabbix APIは、ZabbixのWebUIで行うさまざまな操作を管理画面を介さずにできます。例えば、大量のホスト設定を一覧から登録する、など。

以前、当社の近藤が「大量のホストならびにホストグループを登録する方法をbashで実装する」という記事を執筆いたしましたが、今回はPythonを使用した実装方法を紹介したいと思います。

この記事はZabbix APIをPython3で扱うために必要となる準備ならびに前提となる知識について説明しています。一度この記事を読んでいただいた後に、Zabbix APIの実践記事を読んでいただけますと、より理解が深まると思います。連載記事に対するリンクは都度追加いたしますので、公開をお待ちください。

開発環境と前提条件

ローカルの開発環境はWindows 10 Pro、IDEはVisual Studio Codeを用いています。Zabbix APIの呼び出しにはPython 3.6.8を採用しています。Visual Studio CodeのPython拡張などは、あらかじめインストールしてください。

ZabbixサーバーはVersion5.0.0を用います。今回はZabbix APIを呼び出すだけですので、ZabbixのダウンロードサイトからZabbix Applianceをダウンロードし、Hyper-VやVirtual Boxなどに展開すれば、簡単に構築できるでしょう。

そして、Zabbixの仕様(WebUIにてホストや監視設定を追加できる)をおおむね理解している方を対象に説明をしたいと思います。

公式にはZabbix API用のライブラリも存在する

Zabbix Enterpriseサポートを契約されているお客様向けに、Zabbix Japan LLCよりZabbix API用のPythonライブラリが提供されていますが、今回は全実装を独自におこないます。

Zabbix APIの概要

公式の説明は、以下のサイトにあります。

Zabbix APIは、ZabbixサーバーとHTTPを用いたJSON-RPC形式でやりとりをします。API用のURLに対して、JSON形式のデータをリクエストすることで、JSON形式のレスポンスを取得します。

そして、Zabbix APIは、api_jsonrpc.phpを呼び出して使います。

例えば、Zabbixが http://hostname/zabbix にインストールされている場合は、以下のように呼び出します。これは、Zabbixのバージョン番号を取得するapiinfo.versionメソッドの例です。

POST http://hostname/zabbix/api_jsonrpc.php HTTP/1.1
Content-Type: application/json-rpc

{"jsonrpc":"2.0","method":"apiinfo.version","id":1,"auth":null,"params":{}}

リクエスト時に渡しているパラメーターの概要

リクエスト時に渡しているパラメーターを簡単に説明します。このフォーマットが、Zabbix APIを呼び出すときに用いる基本形です。

  • jsonrpc
    JSON-RPCプロトコルのバージョン。Zabbix APIはバージョン2.0を使います。
  • method
    呼び出すZabbix APIのメソッド名です。
  • id
    リクエスト時に使う任意の識別子。公式のサンプルでは、数値をカウントアップしています。
  • auth
    ユーザー認証トークン。apiinfo.versionやuser.loginなど、認証していない状態で呼び出せるメソッドでは、nullを設定します。
  • params
    Zabbix APIのメソッドに渡すパラメーター。呼び出すメソッドによって、中身が変わります。

リクエストに対するレスポンスの概要

リクエストに対するZabbix APIのレスポンスを簡単に説明します。

正常時のレスポンス

{
    "jsonrpc": "2.0",
    "result": "5.0.0",
    "id": 1
}
  • jsonrpc
    JSON-RPCプロトコルのバージョン。Zabbix APIはバージョン2.0を使います。(再掲)
  • result
    Zabbix APIが返却したデータです。呼び出したメソッドによって、中身が変わります。
  • id
    リクエスト時に設定した任意の識別子です。

異常発生時のレスポンス

{
    "jsonrpc": "2.0",
    "error": {
        "code": -32602,
        "message": "Invalid params.",
        "data": "Incorrect method xxx.."
    },
    "id": 1
}
  • jsonrpc
    JSON-RPCプロトコルのバージョン。Zabbix APIはバージョン2.0を使います。(再々掲)
  • error
    • code
      エラーコードです。
    • message
      エラーの概要です。
    • data
      messageより詳細なエラーメッセージです。
  • id
    リクエスト時に設定した任意の識別子です。(再掲)

何らかの異常が発生した場合、Zabbix APIはresultの代わりにerrorを返却します。うまくいかない場合はerrorの中身を確認して、適切な対処をしましょう。

PythonでZabbix APIのバージョン番号を取得する

早速、Pythonを使ってZabbix APIを呼び出してみましょう。手始めに、apiinfo.versionメソッドを呼び出してみます。公式のマニュアルはこちらです。

Zabbix APIに対するHTTP要求と応答を関数で切り出す

まず、Zabbix APIに対するHTTP要求の送信と、その応答の受信をPythonで実装します。この部分を関数にして、他のZabbix APIを呼び出す場合に再利用しましょう。function.pyファイルとして実装します。

import json
import urllib.request

def invoke(server, parameter, content):
    result = False
    url = server + "/api_jsonrpc.php"
    request = urllib.request.Request(
        url = url,
        data = json.dumps(parameter).encode(),
        headers = {"Content-Type": "application/json-rpc"}
    )

    try:
        with urllib.request.urlopen(request) as response:
            dictionary = json.loads(response.read())
            if "result" in dictionary:
                content["result"] = dictionary["result"]
                result = True

            else:
                content["error"] = dictionary["error"]

    except:
        raise

    return result

関数に渡す引数と戻り値の説明

  • server [in]
    文字列(str)値、ZabbixサーバーのURLを渡します。例)http://hostname/zabbix
  • parameter [in]
    辞書(dictionary)型、Zabbix APIに渡すパラメーターをKVS(key-valueストア)で渡します。
  • content [out]
    辞書(dictionary)型、Zabbix APIの応答をKVSで返却します。
  • 戻り値
    真偽(bool)値、Zabbix APIの呼び出しに成功した場合はTrue、そうでない場合はFalse

Zabbix APIに渡すJSON-RPCフォーマットを作成する

実装サンプルの7行目~、urllib.request.Requestに以下のパラメーターをセットして、POST形式のリクエストを生成します。

  • url
    Zabbix APIのエンドポイントを渡します。引数で受領したZabbixサーバーのURL + “/api_jsonrpc.php"。
  • data
    Zabbix APIに渡すパラメーターをJSON形式に変換したものをセットします。
  • headers
    HTTPリクエストヘッダーをセットします。Zabbix APIでは “Content-Type": “application/json-rpc" 固定。

サードパーティライブラリのRequestsを使えばもっとシンプルに実装できますが、pipでサードパーティライブラリをインストールできない環境を考慮し、標準ライブラリを使って実装しました。

Zabbix APIを呼び出す

14行目~、urllib.request.urlopenに生成したPOST形式のリクエストを渡すことで、Zabbixサーバーとの通信が始まります。15行目でZabbixサーバーからの応答をJSON形式として受け取り、辞書型(dictionary)にセットしています。

その後、dictionaryの中にresultがセットされているか否かを判断することによって、正常または異常を判定しています。そして、contentにZabbix APIの応答をセットして、呼び出し元に返却しています。

例外の捕捉

Zabbix APIを呼び出す際に、urllibが例外を返却することがあります。例外を返却する具体的なシナリオは、Zabbixサーバーが起動していない。または、ネットワークがつながっていない場合。です。その例外を捕捉するために、13~24行目をtry~exceptブロックで括っています。このようなシナリオ下で通信をすると、URLErrorやHTTPErrorなどの例外が発生するので、呼び出し元に例外を送出しています。

実際にZabbix APIのバージョン番号を取得する

ここまでに作成した関数を使って、実際にZabbix APIのバージョン番号を取得してみましょう。使用するZabbix APIのメソッドは、apiinfo.versionです。

要求フォーマット

{
    "jsonrpc": "2.0",
    "method": "apiinfo.version",
    "params": [],
    "id": 1
}

応答フォーマット

{
    "jsonrpc": "2.0",
    "result": "5.0.0",
    "id": 1
}

Pythonで実装します

HTTPによるZabbixサーバーとのやり取りをinvoke関数(17行目)に隠ぺいしたので、実装もスッキリしますね。invoke関数の呼び出しが正常だった場合、応答フォーマットのresultにZabbix APIのバージョンが入ってきますので、print文でコンソールに出力しています。実際は、別の変数に格納するなどして、利用してください。

import os
import traceback
from function import invoke

def main():
    server = "http://hostname/zabbix"

    request = {
        "jsonrpc": "2.0",
        "method": "apiinfo.version",
        "params": [],
        "id": 1
    }

    try:
        response = {}
        if invoke(server, request, response):
            print("Zabbix Version = {}".format(response["result"]))

        else:
            print("{}: error: message={}, data={}, code={}".format(
                os.path.basename(__file__),
                response["error"]["message"],
                response["error"]["data"],
                response["error"]["code"])
            )

    except Exception as e:
        print("{}: exception: {}".format(
            os.path.basename(__file__),
            traceback.format_exc())
        )

if __name__ == "__main__":
    main()

invoke関数の呼び出しに失敗した場合は、Zabbix APIが返却したエラー情報をコンソールに出力しています。また、例外が送出された場合は捕捉して、スタックトレースをコンソールに出力しています。

今回の実装は、ここまで。

Zabbix 4.0→5.0の変更点

あ、ありません(汗)
Zabbix APIが応答するバージョン番号が、4.0.x から 5.0.x に変わっただけです。

ホスト(インターフェース)やメディアタイプなどのZabbix APIメソッドには変更点がありますので、そちらは今後公開する記事で説明します。

まとめ

この記事では、Zabbix APIの概要とZabbix APIの仕組みについて、そして実際にZabbix APIを呼び出す実装を紹介しました。

非常に膨大な量のZabbix APIのドキュメントを見て、その物量に圧倒されたり日本語版ドキュメントが存在しなかったりなど、難しいものと思い込んでしまいますが、この記事を読んでいただきハードルが下がればいいなと思っています。

次回はより実践に近づき、「Zabbix APIによる認証」と「ホストの一覧を取得する方法」を紹介したいと思います。

アークシステムは Zabbix Japan LLC の認定パートナー企業です。 当社はZabbixバージョン1.1の時代から監視ソリューションの活用を進め、Zabbixに関する製品・サービスの販売に加え、Zabbix関連サービスの提供を行っています。

Zabbixに関するお問い合わせはこちらからお願いいたします。
  • 株式会社アークシステムの来訪管理・会議室予約システム BRoomHubs
  • 低コスト・短納期で提供するまるごとおまかせZabbix