てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] community.zabbix 内のモジュールを httpapi で使うとエラー「Invalid JSON response」となる場合の対処

この記事は、Ansible Advent Calendar 2022 (Adventar 版) の 22日目の記事です。

はじめに

community.zabbix コレクション内のモジュールは、最近のバージョンでは httpapi コネクションプラグインに対応してきたようです。

これにより、各タスクで server_urllogin_userlogin_password のような接続先や認証情報の指定をする必要がなくなります。

その代わり ansible_hostansible_useransible_password のような変数が利用できるようになります。

ちょっと試したところ、「Invalid JSON response」というが発生しました。今回の環境では ansible_zabbix_url_path を調整する必要がありました。

エラーの内容と対処をまとめます。

  • 環境
    • ansible 7.0.0
    • ansible-core 2.14.0
    • community.zabbix 1.9.0
    • Zabbix Server 6.2

試した Playbook と変数定義ファイル

Playbook(ホストを追加するだけのかんたんなもの)

---
- name: Zabbix test
  hosts: zabbix
  gather_facts: false

  tasks:
    - name: zabbix_host
      community.zabbix.zabbix_host:
        host_name: test_host
        host_groups:
          - Virtual machines
          - Linux servers

インベントリ

[zabbix]
zabbix01 ansible_host=192.168.1.9

グループ変数ファイル group_vars/zabbix.yml

---
ansible_network_os: community.zabbix.zabbix
ansible_connection: ansible.netcommon.httpapi
ansible_httpapi_port: 80        # 簡易的な検証環境
ansible_httpapi_use_ssl: false
ansible_user: dummy_admin
ansible_password: dummy_password

エラー

Playbook を実行すると以下のエラーになりました。

抜粋

The error was: ansible.module_utils.connection.ConnectionError: Invalid JSON response: File not found.

全エラー

% ansible-playbook -i inventory.ini test.yml

PLAY [Zabbix test] *******************************************************************************************************************************************************

TASK [zabbix_host] *******************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: Invalid JSON response: File not found.
fatal: [zabbix01]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/Users/sakana/.ansible/tmp/ansible-local-60674wfla4vy1/ansible-tmp-1670681807.339254-60677-162818002374491/AnsiballZ_zabbix_host.py\", line 107, in <module>\n    _ansiballz_main()\n  File \"/Users/sakana/.ansible/tmp/ansible-local-60674wfla4vy1/ansible-tmp-1670681807.339254-60677-162818002374491/AnsiballZ_zabbix_host.py\", line 99, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/Users/sakana/.ansible/tmp/ansible-local-60674wfla4vy1/ansible-tmp-1670681807.339254-60677-162818002374491/AnsiballZ_zabbix_host.py\", line 47, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.community.zabbix.plugins.modules.zabbix_host', init_globals=dict(_module_fqn='ansible_collections.community.zabbix.plugins.modules.zabbix_host', _modlib_path=modlib_path),\n  File \"/usr/local/Cellar/python@3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py\", line 210, in run_module\n    return _run_module_code(code, init_globals, run_name, mod_spec)\n  File \"/usr/local/Cellar/python@3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py\", line 97, in _run_module_code\n    _run_code(code, mod_globals, init_globals,\n  File \"/usr/local/Cellar/python@3.9/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py\", line 87, in _run_code\n    exec(code, run_globals)\n  File \"/var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/ansible_community.zabbix.zabbix_host_payload_87ej1ch7/ansible_community.zabbix.zabbix_host_payload.zip/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py\", line 1289, in <module>\n  File \"/var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/ansible_community.zabbix.zabbix_host_payload_87ej1ch7/ansible_community.zabbix.zabbix_host_payload.zip/ansible_collections/community/zabbix/plugins/modules/zabbix_host.py\", line 1083, in main\n  File \"/var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/ansible_community.zabbix.zabbix_host_payload_87ej1ch7/ansible_community.zabbix.zabbix_host_payload.zip/ansible_collections/community/zabbix/plugins/module_utils/base.py\", line 33, in __init__\n  File \"/var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/ansible_community.zabbix.zabbix_host_payload_87ej1ch7/ansible_community.zabbix.zabbix_host_payload.zip/ansible_collections/community/zabbix/plugins/module_utils/api_request.py\", line 53, in api_version\n  File \"/var/folders/2s/h6djr0fn3773tj1zy4mg442c0000gn/T/ansible_community.zabbix.zabbix_host_payload_87ej1ch7/ansible_community.zabbix.zabbix_host_payload.zip/ansible/module_utils/connection.py\", line 200, in __rpc__\nansible.module_utils.connection.ConnectionError: Invalid JSON response: File not found.\n\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

PLAY RECAP ***************************************************************************************************************************************************************
zabbix01                   : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

レスポンスが正しい JSON ではないようで、何でだろうとしばらく悩んでいました。調べてみると、Ansible からは http://IPアドレス/zabbix/api_jsonrpc.php にリクエストしているのに対して、今回 docker で構築した Zabbix の場合、正しいリクエスト先は http://IPアドレス/api_jsonrpc.php でした(/zabbix が不要)。

モジュール側のデフォルトの挙動は、よくある環境に合わせているようです。

今回の場合は、404 の HTML が返ってきていました。なので 「Invalid JSON response」と判断されていたようです。

対策

ansible_zabbix_url_path という変数で、パスを調整できる事がわかりました。

ということで、group/zabbix.yml に以下を追加して Playbook を実行したら正常にできました。

ansible_zabbix_url_path: ""

関連

github.com

github.com