これは Ansible Advent Calendar 2020 (Qiita版) の 21日目の記事です。
■ はじめに
Ansible には callback plugin という仕組みがあり、結果出力の形式を変更できます。
JSON Callback Plugin もあり、Playbook の実行結果を JSON で得て、jq
などと組み合わせて必要な箇所だけ切り取って表示できます。
この記事では、簡単なサンプルでご紹介します。
前提とする 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
でも指定できます。
詳細は、公式ドキュメントをご参照ください。
docs.ansible.com
おわりに
Playbook の実行結果を抽出したり、プログラム的に処理させたいときは json callback plugin は便利だと思います。
参考
rheb.hatenablog.com
tekunabe.hatenablog.jp