てくなべ

インフラ、ネットワーク、自動化などの技術的なことを書いていきます。

Ansible でネットワーク機器のコマンド結果をパースしてくれるフィルタープラグイン「ansible_helpers」を試してみた

f:id:akira6592:20170521163508p:plain

■ はじめに

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 IOSshow 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 以上あります。パース処理は自力で作るとなかなか大変ですので、ここにあるものを参考にするのも良いのではないでしょうか。