これは Ansible Advent Calendar 2020 (Qiita版) の 21日目の記事です。
■ はじめに
Ansible には callback plugin という仕組みがあり、結果出力の形式を変更できます。
JSON Callback Plugin もあり、Playbook の実行結果を JSON で得て、jq
などと組み合わせて必要な箇所だけ切り取って表示できます。
この記事では、簡単なサンプルでご紹介します。
- 動作確認環境
- ansible 2.9.14
前提とする Playbook
以下の Playbook で試すこととします。Cisco IOS のネットワーク機器に show ip route
コマンドを実行するだけです。
--- - hosts: ios1 gather_facts: false tasks: - name: show ip route ios_command: commands: - show ip route
まずは普通に
比較用に普通実行、つまりデフォルトの callback plugin で実行した場合は以下のようになります。
$ ansible-playbook -i ../inventory.ini iproute.yml PLAY [ios1] *********************************************************************************************************************** TASK [show ip route] ********************************************************************************************************************** ok: [ios1] PLAY RECAP ******************************************************************************************************************************** ios1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
デバッグ表示用のタスクはないので、ただ ok
と表示されるだけです。
json callback plugin の場合
今度は ANSIBLE_STDOUT_CALLBACK=json
を指定して、実行します。stdout
や stdout_lines
に実行結果が含まれていることが分かります。
全出力
まず、jq
で絞らず、そのまま出力する方法です。
$ ANSIBLE_STDOUT_CALLBACK=json ansible-playbook -i ../inventory.ini iproute.yml { "custom_stats": {}, "global_custom_stats": {}, "plays": [ { "play": { "duration": { "end": "2020-12-20T12:16:22.379916Z", "start": "2020-12-20T12:16:04.563589Z" }, "id": "acde4800-1122-37cb-6431-00000000002c", "name": "ios1" }, "tasks": [ { "hosts": { "ios1": { "_ansible_no_log": false, "action": "ios_command", "changed": false, "invocation": { "module_args": { "auth_pass": null, "authorize": null, "commands": [ "show ip route" ], "host": null, "interval": 1, "match": "all", "password": null, "port": null, "provider": null, "retries": 10, "ssh_keyfile": null, "timeout": null, "username": null, "wait_for": null } }, "stdout": [ "Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP\n D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area \n N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2\n E1 - OSPF external type 1, E2 - OSPF external type 2\n i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2\n ia - IS-IS inter area, * - candidate default, U - per-user static route\n o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP\n a - application route\n + - replicated route, % - next hop override, p - overrides from PfR\n\nGateway of last resort is 10.10.20.254 to network 0.0.0.0\n\nS* 0.0.0.0/0 [1/0] via 10.10.20.254, GigabitEthernet1\n 10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks\nC 10.10.20.0/24 is directly connected, GigabitEthernet1\nL 10.10.20.48/32 is directly connected, GigabitEthernet1" ], "stdout_lines": [ [ "Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP", " D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area ", " N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2", " E1 - OSPF external type 1, E2 - OSPF external type 2", " i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2", " ia - IS-IS inter area, * - candidate default, U - per-user static route", " o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP", " a - application route", " + - replicated route, % - next hop override, p - overrides from PfR", "", "Gateway of last resort is 10.10.20.254 to network 0.0.0.0", "", "S* 0.0.0.0/0 [1/0] via 10.10.20.254, GigabitEthernet1", " 10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks", "C 10.10.20.0/24 is directly connected, GigabitEthernet1", "L 10.10.20.48/32 is directly connected, GigabitEthernet1" ] ] } }, "task": { "duration": { "end": "2020-12-20T12:16:22.379916Z", "start": "2020-12-20T12:16:04.580088Z" }, "id": "acde4800-1122-37cb-6431-00000000002e", "name": "show ip route" } } ] } ], "stats": { "ios1": { "changed": 0, "failures": 0, "ignored": 0, "ok": 1, "rescued": 0, "skipped": 0, "unreachable": 0 } } }
jq で絞る
今度は jq
と組み合わせて結果の一部のみを表示する方法です。
ここでは、1つめのタスクのホスト ios1
の実行結果の stdout_lines[0]
をターゲットにします。
% ANSIBLE_STDOUT_CALLBACK=json ansible-playbook -i ../inventory.ini iproute.yml | jq ".plays[0].tasks[0].hosts.ios1.stdout_lines[0]" [ "Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP", " D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area ", " N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2", " E1 - OSPF external type 1, E2 - OSPF external type 2", " i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2", " ia - IS-IS inter area, * - candidate default, U - per-user static route", " o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP", " a - application route", " + - replicated route, % - next hop override, p - overrides from PfR", "", "Gateway of last resort is 10.10.20.254 to network 0.0.0.0", "", "S* 0.0.0.0/0 [1/0] via 10.10.20.254, GigabitEthernet1", " 10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks", "C 10.10.20.0/24 is directly connected, GigabitEthernet1", "L 10.10.20.48/32 is directly connected, GigabitEthernet1" ]
抽出されました。
callback plugin の指定方法
今回は、環境変数で callback plugin を指定しましたが、ansible.cfg
でも指定できます。
詳細は、公式ドキュメントをご参照ください。
おわりに
Playbook の実行結果を抽出したり、プログラム的に処理させたいときは json callback plugin は便利だと思います。