■ はじめに
Ansible はCisco IOS や、Juniper JUNOSなど様々なネットワーク機器に対応するモジュールがあります。 show系のコマンドを実行して結果を取得することもできますが、取得した結果を良い感じにパースしてくれるフィルタープラグイン 「ansible_helpers」を見つけたので試してみます。
作者はnetmikoの作者でもある Kirk Byers (@ktbyers) さんです。
▼本プラグインを知るきっかけとなったツイート
Ansible filter plugin I wrote to help convert unstructured data to structured data using ntc-templates and TextFSM https://t.co/D3SyGzjVLK
— Kirk Byers (@kirkbyers) 2017年5月19日
■ 仕組み
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 以上あります。パース処理は自力で作るとなかなか大変ですので、ここにあるものを参考にするのも良いのではないでしょうか。