■ はじめに
Ansible はCisco IOS や、Juniper JUNOSなど様々なネットワーク機器に対応するモジュールがあります。
show系のコマンドを実行して結果を取得することもできますが、取得した結果を良い感じにパースしてくれるフィルタープラグイン
「ansible_helpers」を見つけたので試してみます。
作者はnetmikoの作者でもある Kirk Byers (@ktbyers) さんです。
▼本プラグインを知るきっかけとなったツイート
■ 仕組み
google/textfsm というネットワーク機器のコマンドの結果をパースする python ライブラリと、
そのテンプレート集(networktocode/ntc-templates )を組み合わせているようです。
■ インストール
ktbyers/ansible_helpers にインストール手順が記載されていますので、その手順を参考にインストールします。
■ その1: show ip int brief で試す
まず、サンプルにあるように、Cisco IOS の show ip int brief
コマンドを試してみます。
playbook
以下の playbook を用意します。
---
- name: parse sample
hosts: cisco
gather_facts: no
connection: local
vars:
cli:
host: "{{ inventory_hostname }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
platform: cisco_ios
command: show ip int brief
tasks:
- ios_command:
provider: "{{ cli }}"
commands: "{{ command }}"
register: output
- name: parse output
debug:
msg: "{{ output | net_textfsm_parse(platform, command) }}"
実行結果
以下のようにパースしてくれました。
[root@controller ~]# ansible-playbook cat_int.yml
PLAY [parse sample] ***************************
TASK [ios_command] *************************************************************
ok: [192.168.1.254]
TASK [parse output] ************************************************************
ok: [192.168.1.254] => {
"msg": [
{
"intf": "GigabitEthernet1",
"ipaddr": "10.0.0.51",
"proto": "up",
"status": "up"
},
{
"intf": "GigabitEthernet2",
"ipaddr": "10.0.2.1",
"proto": "up",
"status": "up"
},
{
"intf": "GigabitEthernet3",
"ipaddr": "unassigned",
"proto": "up",
"status": "up"
},
{
"intf": "GigabitEthernet4",
"ipaddr": "10.0.4.1",
"proto": "up",
"status": "up"
}
]
}
PLAY RECAP *********************************************************************
192.168.1.254 : ok=2 changed=0 unreachable=0 failed=0
(参考) 実際のコマンド実行結果
ネットワーク機器自身でのコマンド実行結果は以下の通りです。
csr1#show ip int brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.0.0.51 YES NVRAM up up
GigabitEthernet2 10.0.2.1 YES NVRAM up up
GigabitEthernet3 unassigned YES NVRAM up up
GigabitEthernet4 10.0.4.1 YES NVRAM up up
csr1#
■ その2: show ip route編 で試す
続けて、例にはない show ip route
も試してみます。
playbook
以下の playbook を用意します。(command の定義以外は先ほどと同じです)
---
- name: parse sample
hosts: cisco
gather_facts: no
connection: local
vars:
cli:
host: "{{ inventory_hostname }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
platform: cisco_ios
command: show ip route
tasks:
- ios_command:
provider: "{{ cli }}"
commands: "{{ command }}"
register: output
- name: parse output
debug:
msg: "{{ output | net_textfsm_parse(platform, command) }}"
実行結果
以下のようにパースしてくれました。
[root@controller ~]# ansible-playbook cat_route.yml
PLAY [parse sample] ***************************
TASK [ios_command] *************************************************************
ok: [192.168.1.254]
TASK [parse output] ************************************************************
ok: [192.168.1.254] => {
"msg": [
{
"distance": "",
"mask": "/24",
"metric": "",
"network": "10.0.2.0",
"nexthopif": "GigabitEthernet2",
"nexthopip": "",
"protocol": "C",
"type": "",
"uptime": ""
},
{
"distance": "",
"mask": "/32",
"metric": "",
"network": "10.0.2.1",
"nexthopif": "GigabitEthernet2",
"nexthopip": "",
"protocol": "L",
"type": "",
"uptime": ""
},
{
"distance": "110",
"mask": "/24",
"metric": "2",
"network": "10.0.3.0",
"nexthopif": "GigabitEthernet2",
"nexthopip": "10.0.2.2",
"protocol": "O",
"type": "",
"uptime": "00:37:41"
},
{
"distance": "",
"mask": "/24",
"metric": "",
"network": "10.0.4.0",
"nexthopif": "GigabitEthernet4",
"nexthopip": "",
"protocol": "C",
"type": "",
"uptime": ""
},
{
"distance": "",
"mask": "/32",
"metric": "",
"network": "10.0.4.1",
"nexthopif": "GigabitEthernet4",
"nexthopip": "",
"protocol": "L",
"type": "",
"uptime": ""
},
{
"distance": "110",
"mask": "/32",
"metric": "3",
"network": "10.10.10.10",
"nexthopif": "GigabitEthernet2",
"nexthopip": "10.0.2.2",
"protocol": "O",
"type": "",
"uptime": "00:37:41"
}
]
}
PLAY RECAP *********************************************************************
192.168.1.254 : ok=2 changed=0 unreachable=0 failed=0
(参考) 実際のコマンド実行結果
ネットワーク機器自身でのコマンド実行結果は以下の通りです。
csr1#sh ip route
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 not set
10.0.0.0/8 is variably subnetted, 6 subnets, 2 masks
C 10.0.2.0/24 is directly connected, GigabitEthernet2
L 10.0.2.1/32 is directly connected, GigabitEthernet2
O 10.0.3.0/24 [110/2] via 10.0.2.2, 00:33:38, GigabitEthernet2
C 10.0.4.0/24 is directly connected, GigabitEthernet4
L 10.0.4.1/32 is directly connected, GigabitEthernet4
O 10.10.10.10/32 [110/3] via 10.0.2.2, 00:33:38, GigabitEthernet2
csr1#
■ まとめ
パース処理のキモとなる Pythonライブラリである TextFSM 自身は以前からもありましたが、
Python のプログラム内ではなく、Ansible と連携して使いたいという時には、
この ansible_helpers が便利なのではないでしょうか。
また、TextFSMのテンプレート集には、 Cisco IOSだけでも 30 以上あります。パース処理は自力で作るとなかなか大変ですので、ここにあるものを参考にするのも良いのではないでしょうか。