てくなべ (tekunabe)

ansible / network / automation

[Ansible] 見やすい json に整形するには to_nice_json フィルターが nice で便利

はじめに

Ansible には、テキストデータの内容を整形するための多数のフィルターがあります。

json 形式に変換するフィルターもいくつかあり、そのなかで to_nice_json フィルターは、人にとって見やすく整形するのにとても便利です。

公式ドキュメントでは出力例の記載がないので、イマイチありがたみが分からないかもしれません。

この記事では、簡単なサンプルを利用してご紹介します。

f:id:akira6592:20200215182502p:plain:w400
こんなイメージ


サンプル

Playbook の作成

処理内容は以下の通りです。

  • uri モジュールで、Google Public DNSDNS-over-HTTPS (DoH)を利用して www.ansible.com の Aレコードのデータを JSON で取得
  • 結果を、整形なし、to_nice_yaml フィルターで整形、のそれぞれのパターンでファイルに出力
- hosts: localhost
  gather_facts: no
  connection: local

  tasks:
    - name: get json
      uri:
        url:  https://dns.google.com/resolve?name=www.ansible.com&type=A
      register: result

    - name: raw json
      copy:
        content: "{{ result }}"
        dest: raw.json       # 整形なしで出力
    
    - name: nice json
      copy:
        content: "{{ result | to_nice_json }}"
        dest: nice_json.json  # to_nice_json 適用結果を出力

Playbook 実行

Playbook を実行します。

$ ansible-playbook -i localhost, nice.yml 

PLAY [localhost] **************************************************************************************************

TASK [get json] ***************************************************************************************************
ok: [localhost]

TASK [raw json] ***************************************************************************************************
changed: [localhost]

TASK [nice json] **************************************************************************************************
changed: [localhost]

PLAY RECAP ********************************************************************************************************
localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

特に整形せずに出力した raw.json は以下のようになります。データフォーマットとしては正しいですが、改行がないので見にくいですね。

{"redirected": false, "url": "https://dns.google.com/resolve?name=www.ansible.com&type=A", "status": 200, "strict_transport_security": "max-age=31536000; includeSubDomains; preload", "access_control_allow_origin": "*", "date": "Sat, 15 Feb 2020 08:48:47 GMT", "expires": "Sat, 15 Feb 2020 08:48:47 GMT", "cache_control": "private, max-age=119", "content_type": "application/x-javascript; charset=UTF-8", "server": "HTTP server (unknown)", "x_xss_protection": "0", "x_frame_options": "SAMEORIGIN", "alt_svc": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000", "accept_ranges": "none", "vary": "Accept-Encoding", "connection": "close", "cookies_string": "", "cookies": {}, "msg": "OK (unknown bytes)", "elapsed": 0, "changed": false, "json": {"Status": 0, "TC": false, "RD": true, "RA": true, "AD": false, "CD": false, "Question": [{"name": "www.ansible.com.", "type": 1}], "Answer": [{"name": "www.ansible.com.", "type": 5, "TTL": 299, "data": "330046g46.secure0032.hubspot.net."}, {"name": "330046g46.secure0032.hubspot.net.", "type": 5, "TTL": 299, "data": "330046.group46.sites.hubspot.net."}, {"name": "330046.group46.sites.hubspot.net.", "type": 5, "TTL": 119, "data": "group46.sites.hscoscdn40.net."}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.114.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.115.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.112.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.116.180"}, {"name": "group46.sites.hscoscdn40.net.", "type": 1, "TTL": 299, "data": "104.17.113.180"}], "Comment": "Response from 173.245.59.182."}, "failed": false}

一方、to_nice_json フィルターを適用した nice_json.json は以下のようになります。見やすいです。

{
    "accept_ranges": "none",
    "access_control_allow_origin": "*",
    "alt_svc": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000",
    "cache_control": "private, max-age=119",
    "changed": false,
    "connection": "close",
    "content_type": "application/x-javascript; charset=UTF-8",
    "cookies": {},
    "cookies_string": "",
    "date": "Sat, 15 Feb 2020 08:48:47 GMT",
    "elapsed": 0,
    "expires": "Sat, 15 Feb 2020 08:48:47 GMT",
    "failed": false,
    "json": {
        "AD": false,
        "Answer": [
            {
                "TTL": 299,
                "data": "330046g46.secure0032.hubspot.net.",
                "name": "www.ansible.com.",
                "type": 5
            },
            {
                "TTL": 299,
                "data": "330046.group46.sites.hubspot.net.",
                "name": "330046g46.secure0032.hubspot.net.",
                "type": 5
            },
            {
                "TTL": 119,
                "data": "group46.sites.hscoscdn40.net.",
                "name": "330046.group46.sites.hubspot.net.",
                "type": 5
            },
            {
                "TTL": 299,
                "data": "104.17.114.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.115.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.112.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.116.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            },
            {
                "TTL": 299,
                "data": "104.17.113.180",
                "name": "group46.sites.hscoscdn40.net.",
                "type": 1
            }
        ],
        "CD": false,
        "Comment": "Response from 173.245.59.182.",
        "Question": [
            {
                "name": "www.ansible.com.",
                "type": 1
            }
        ],
        "RA": true,
        "RD": true,
        "Status": 0,
        "TC": false
    },
    "msg": "OK (unknown bytes)",
    "redirected": false,
    "server": "HTTP server (unknown)",
    "status": 200,
    "strict_transport_security": "max-age=31536000; includeSubDomains; preload",
    "url": "https://dns.google.com/resolve?name=www.ansible.com&type=A",
    "vary": "Accept-Encoding",
    "x_frame_options": "SAMEORIGIN",
    "x_xss_protection": "0"
}

応用編

to_nice_json フィルターはインデント数の指定もできます。デフォルトは4個です。

例えば、2個にする場合は、以下のように指定します。

        content: "{{ result | to_nice_json(indent=2) }}"

結果

{
  "accept_ranges": "none",
  "access_control_allow_origin": "*",
  "alt_svc": "quic=\":443\"; ma=2592000; v=\"46,43\",h3-Q050=\":443\"; ma=2592000,h3-Q049=\":443\"; ma=2592000,h3-Q048=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000",
  "cache_control": "private, max-age=119",
  "changed": false,
  // ...(略)...
}


さいごに

json 以外にも yaml 関連、その他様々なフィルターが用意されているので、たまに眺めてみると欲しかったフィルターが見つかるかもしれません。

docs.ansible.com