てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 「つまずき Ansible 【Part15】cli_parse モジュールで構造化データを取得する」ふりかえり

はじめに

2020/09/12 に、YouTube Live で「つまずき Ansible 【Part15】cli_parse モジュールで構造化データを取得する」という配信をしました。

実際に作業しながらエラーと戦って進めるシリーズです。

tekunabe.connpass.com

今回は、ansible.netcommon collectioncli_parse モジュールを使って、ネットワーク機器への show コマンドの実行結果を構造化データで取得する Playbook を書いてみました。

cli_parse モジュールは、パーサーとして以下のものを選べるようです。

  • native
  • ntc-templates
  • pyats
  • textfsm
  • ttp
  • xml

今回は ntc-templatespyats に挑戦しました。

やったことや、わかったことをふりかえります。

  • 環境
    • ansible-base 2.10.0

[2020/12/14 追記] ansible.utils colleciton に移動するという動きがありました

動画

www.youtube.com


■ やったこと

ansible.netcommon collection のアップデート

手元の環境の ansible.netcommon collection が、cli_parse モジュールが導入された 1.2.0 より古かったのでアップデートしまし。

  • 事前状態
# ansible-galaxy collection list

# /root/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
ansible.netcommon 1.1.2  
cisco.ios         1.0.2  
  • アップデート
# ansible-galaxy collection install ansible.netcommon -f
  • 事後状態
# ansible-galaxy collection list

# /root/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
ansible.netcommon 1.2.1  
cisco.ios         1.0.2  

何も考えずに ntc_templates を指定

エラーが出るだろうと思いつつ、パーサーに ansible.netcommon.ntc_templates を指定して実行しました。対象は Cisco IOS です。

---
- hosts: rt01
  gather_facts: false

  tasks:
    - name: test
      ansible.netcommon.cli_parse:
        command: "show interface"
        parser:
          name: ansible.netcommon.ntc_templates
      register: parser_output
    
    - name: debug
      debug:
        msg: "{{ parser_output.parsed }}"

※(注)ここでは show interface のように微妙に省略したコマンドを指定していますが、show interfaces のようにフル表記したほうが安全です(このせいであとでひっかかります)。

こんなエラーが。Python ライブラリ ntc-templates がないとのこと。

TASK [test] ****************************************************************************************************************
fatal: [rt01]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (ntc-templates) on 2a5505f15a98's Python /root/envs/ab210/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter"}

パーサーやテンプレートは自分で用意する感じですね。

ntc-templates をインストールして再実行

エラーメッセージ通り、ntc-templates をインストールします。

# pip install ntc-templates
...(略)...
# pip freeze 
...(略)...
ntc-templates==1.5.0
...(略)...
textfsm==1.1.0
...(略)...

テンプレート集の ntc-templates だけでなく、パーサー本体の textfsm もインストールされました。

再実行します。今度は無事に実行できました。パースされたデータは parsed に、生の結果は stdoutstdout_lines に入りました。

ログ(クリックして開く)

# ansible-playbook -i inventory.ini cli_parce.yml 

PLAY [rt01] ****************************************************************************************************************

TASK [test] ****************************************************************************************************************
ok: [rt01]

TASK [debug] ***************************************************************************************************************
ok: [rt01] => {
    "msg": {
        "changed": false,
        "failed": false,
        "parsed": [
            {
                "abort": "",
                "address": "5254.001c.d627",
                "bandwidth": "1000000 Kbit",
                "bia": "5254.001c.d627",
                "crc": "0",
                "delay": "10 usec",
                "description": "",
                "duplex": "Auto Duplex",
                "encapsulation": "ARPA",
                "hardware_type": "iGbE",
                "input_errors": "40",
                "input_packets": "2924240",
                "input_rate": "0",
                "interface": "GigabitEthernet0/0",
                "ip_address": "192.168.1.11/24",
                "last_input": "00:00:00",
                "last_output": "00:00:00",
                "last_output_hang": "never",
                "link_status": "up",
                "media_type": "RJ45",
                "mtu": "1500",
                "output_errors": "0",
                "output_packets": "642722",
                "output_rate": "0",
                "protocol_status": "up",
                "queue_strategy": "fifo",
                "speed": "Auto Speed"
            },
            {
                "abort": "",
                "address": "5254.0003.86e2",
                "bandwidth": "1000000 Kbit",
                "bia": "5254.0003.86e2",
                "crc": "0",
                "delay": "10 usec",
                "description": "",
                "duplex": "Auto Duplex",
                "encapsulation": "ARPA",
                "hardware_type": "iGbE",
                "input_errors": "0",
                "input_packets": "0",
                "input_rate": "0",
                "interface": "GigabitEthernet0/1",
                "ip_address": "",
                "last_input": "never",
                "last_output": "never",
                "last_output_hang": "never",
                "link_status": "administratively down",
                "media_type": "RJ45",
                "mtu": "1500",
                "output_errors": "0",
                "output_packets": "0",
                "output_rate": "0",
                "protocol_status": "down",
                "queue_strategy": "fifo",
                "speed": "Auto Speed"
            },
            {
                "abort": "",
                "address": "5254.001c.3b2b",
                "bandwidth": "1000000 Kbit",
                "bia": "5254.001c.3b2b",
                "crc": "0",
                "delay": "10 usec",
                "description": "",
                "duplex": "Auto Duplex",
                "encapsulation": "ARPA",
                "hardware_type": "iGbE",
                "input_errors": "0",
                "input_packets": "0",
                "input_rate": "0",
                "interface": "GigabitEthernet0/2",
                "ip_address": "",
                "last_input": "never",
                "last_output": "never",
                "last_output_hang": "never",
                "link_status": "administratively down",
                "media_type": "RJ45",
                "mtu": "1500",
                "output_errors": "0",
                "output_packets": "0",
                "output_rate": "0",
                "protocol_status": "down",
                "queue_strategy": "fifo",
                "speed": "Auto Speed"
            },
            {
                "abort": "",
                "address": "5254.000a.86a0",
                "bandwidth": "1000000 Kbit",
                "bia": "5254.000a.86a0",
                "crc": "0",
                "delay": "10 usec",
                "description": "aaa",
                "duplex": "Auto Duplex",
                "encapsulation": "ARPA",
                "hardware_type": "iGbE",
                "input_errors": "0",
                "input_packets": "570744",
                "input_rate": "0",
                "interface": "GigabitEthernet0/3",
                "ip_address": "10.0.0.1/24",
                "last_input": "00:00:00",
                "last_output": "00:00:01",
                "last_output_hang": "never",
                "link_status": "up",
                "media_type": "RJ45",
                "mtu": "1500",
                "output_errors": "0",
                "output_packets": "1014665",
                "output_rate": "0",
                "protocol_status": "up",
                "queue_strategy": "fifo",
                "speed": "Auto Speed"
            },
            {
                "abort": "0",
                "address": "",
                "bandwidth": "8000000 Kbit",
                "bia": "",
                "crc": "0",
                "delay": "5000 usec",
                "description": "",
                "duplex": "",
                "encapsulation": "LOOPBACK",
                "hardware_type": "Loopback",
                "input_errors": "0",
                "input_packets": "0",
                "input_rate": "0",
                "interface": "Loopback0",
                "ip_address": "10.255.255.1/32",
                "last_input": "never",
                "last_output": "never",
                "last_output_hang": "never",
                "link_status": "up",
                "media_type": "",
                "mtu": "1514",
                "output_errors": "0",
                "output_packets": "0",
                "output_rate": "0",
                "protocol_status": "up",
                "queue_strategy": "fifo",
                "speed": ""
            }
        ],
        "stdout": "GigabitEthernet0/0 is up, line protocol is up \n  Hardware is iGbE, address is 5254.001c.d627 (bia 5254.001c.d627)\n  Internet address is 192.168.1.11/24\n  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, \n     reliability 255/255, txload 1/255, rxload 1/255\n  Encapsulation ARPA, loopback not set\n  Keepalive set (10 sec)\n  Auto Duplex, Auto Speed, link type is auto, media type is RJ45\n  output flow-control is unsupported, input flow-control is unsupported\n  ARP type: ARPA, ARP Timeout 04:00:00\n  Last input 00:00:00, output 00:00:00, output hang never\n  Last clearing of \"show interface\" counters never\n  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0\n  Queueing strategy: fifo\n  Output queue: 0/40 (size/max)\n  5 minute input rate 0 bits/sec, 0 packets/sec\n  5 minute output rate 0 bits/sec, 0 packets/sec\n     2924240 packets input, 236479720 bytes, 0 no buffer\n     Received 2688720 broadcasts (0 IP multicasts)\n     40 runts, 0 giants, 0 throttles \n     40 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored\n     0 watchdog, 0 multicast, 0 pause input\n     642722 packets output, 74165870 bytes, 0 underruns\n     0 output errors, 0 collisions, 1 interface resets\n     1943 unknown protocol drops\n     0 babbles, 0 late collision, 0 deferred\n     0 lost carrier, 0 no carrier, 0 pause output\n     0 output buffer failures, 0 output buffers swapped out\nGigabitEthernet0/1 is administratively down, line protocol is down \n  Hardware is iGbE, address is 5254.0003.86e2 (bia 5254.0003.86e2)\n  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, \n     reliability 255/255, txload 1/255, rxload 1/255\n  Encapsulation ARPA, loopback not set\n  Keepalive set (10 sec)\n  Auto Duplex, Auto Speed, link type is auto, media type is RJ45\n  output flow-control is unsupported, input flow-control is unsupported\n  ARP type: ARPA, ARP Timeout 04:00:00\n  Last input never, output never, output hang never\n  Last clearing of \"show interface\" counters never\n  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0\n  Queueing strategy: fifo\n  Output queue: 0/40 (size/max)\n  5 minute input rate 0 bits/sec, 0 packets/sec\n  5 minute output rate 0 bits/sec, 0 packets/sec\n     0 packets input, 0 bytes, 0 no buffer\n     Received 0 broadcasts (0 IP multicasts)\n     0 runts, 0 giants, 0 throttles \n     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored\n     0 watchdog, 0 multicast, 0 pause input\n     0 packets output, 0 bytes, 0 underruns\n     0 output errors, 0 collisions, 1 interface resets\n     0 unknown protocol drops\n     0 babbles, 0 late collision, 0 deferred\n     0 lost carrier, 0 no carrier, 0 pause output\n     0 output buffer failures, 0 output buffers swapped out\nGigabitEthernet0/2 is administratively down, line protocol is down \n  Hardware is iGbE, address is 5254.001c.3b2b (bia 5254.001c.3b2b)\n  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, \n     reliability 255/255, txload 1/255, rxload 1/255\n  Encapsulation ARPA, loopback not set\n  Keepalive set (10 sec)\n  Auto Duplex, Auto Speed, link type is auto, media type is RJ45\n  output flow-control is unsupported, input flow-control is unsupported\n  ARP type: ARPA, ARP Timeout 04:00:00\n  Last input never, output never, output hang never\n  Last clearing of \"show interface\" counters never\n  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0\n  Queueing strategy: fifo\n  Output queue: 0/40 (size/max)\n  5 minute input rate 0 bits/sec, 0 packets/sec\n  5 minute output rate 0 bits/sec, 0 packets/sec\n     0 packets input, 0 bytes, 0 no buffer\n     Received 0 broadcasts (0 IP multicasts)\n     0 runts, 0 giants, 0 throttles \n     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored\n     0 watchdog, 0 multicast, 0 pause input\n     0 packets output, 0 bytes, 0 underruns\n     0 output errors, 0 collisions, 1 interface resets\n     0 unknown protocol drops\n     0 babbles, 0 late collision, 0 deferred\n     0 lost carrier, 0 no carrier, 0 pause output\n     0 output buffer failures, 0 output buffers swapped out\nGigabitEthernet0/3 is up, line protocol is up \n  Hardware is iGbE, address is 5254.000a.86a0 (bia 5254.000a.86a0)\n  Description: aaa\n  Internet address is 10.0.0.1/24\n  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, \n     reliability 255/255, txload 1/255, rxload 1/255\n  Encapsulation ARPA, loopback not set\n  Keepalive set (10 sec)\n  Auto Duplex, Auto Speed, link type is auto, media type is RJ45\n  output flow-control is unsupported, input flow-control is unsupported\n  ARP type: ARPA, ARP Timeout 04:00:00\n  Last input 00:00:00, output 00:00:01, output hang never\n  Last clearing of \"show interface\" counters never\n  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0\n  Queueing strategy: fifo\n  Output queue: 0/40 (size/max)\n  5 minute input rate 0 bits/sec, 0 packets/sec\n  5 minute output rate 0 bits/sec, 0 packets/sec\n     570744 packets input, 82482023 bytes, 0 no buffer\n     Received 5 broadcasts (0 IP multicasts)\n     0 runts, 0 giants, 0 throttles \n     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored\n     0 watchdog, 0 multicast, 0 pause input\n     1014665 packets output, 108824924 bytes, 0 underruns\n     0 output errors, 0 collisions, 1 interface resets\n     0 unknown protocol drops\n     0 babbles, 0 late collision, 0 deferred\n     0 lost carrier, 0 no carrier, 0 pause output\n     0 output buffer failures, 0 output buffers swapped out\nLoopback0 is up, line protocol is up \n  Hardware is Loopback\n  Internet address is 10.255.255.1/32\n  MTU 1514 bytes, BW 8000000 Kbit/sec, DLY 5000 usec, \n     reliability 255/255, txload 1/255, rxload 1/255\n  Encapsulation LOOPBACK, loopback not set\n  Keepalive set (10 sec)\n  Last input never, output never, output hang never\n  Last clearing of \"show interface\" counters never\n  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0\n  Queueing strategy: fifo\n  Output queue: 0/0 (size/max)\n  5 minute input rate 0 bits/sec, 0 packets/sec\n  5 minute output rate 0 bits/sec, 0 packets/sec\n     0 packets input, 0 bytes, 0 no buffer\n     Received 0 broadcasts (0 IP multicasts)\n     0 runts, 0 giants, 0 throttles \n     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort\n     0 packets output, 0 bytes, 0 underruns\n     0 output errors, 0 collisions, 0 interface resets\n     0 unknown protocol drops\n     0 output buffer failures, 0 output buffers swapped out",
        "stdout_lines": [
            "GigabitEthernet0/0 is up, line protocol is up ",
            "  Hardware is iGbE, address is 5254.001c.d627 (bia 5254.001c.d627)",
            "  Internet address is 192.168.1.11/24",
            "  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, ",
            "     reliability 255/255, txload 1/255, rxload 1/255",
            "  Encapsulation ARPA, loopback not set",
            "  Keepalive set (10 sec)",
            "  Auto Duplex, Auto Speed, link type is auto, media type is RJ45",
            "  output flow-control is unsupported, input flow-control is unsupported",
            "  ARP type: ARPA, ARP Timeout 04:00:00",
            "  Last input 00:00:00, output 00:00:00, output hang never",
            "  Last clearing of \"show interface\" counters never",
            "  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0",
            "  Queueing strategy: fifo",
            "  Output queue: 0/40 (size/max)",
            "  5 minute input rate 0 bits/sec, 0 packets/sec",
            "  5 minute output rate 0 bits/sec, 0 packets/sec",
            "     2924240 packets input, 236479720 bytes, 0 no buffer",
            "     Received 2688720 broadcasts (0 IP multicasts)",
            "     40 runts, 0 giants, 0 throttles ",
            "     40 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored",
            "     0 watchdog, 0 multicast, 0 pause input",
            "     642722 packets output, 74165870 bytes, 0 underruns",
            "     0 output errors, 0 collisions, 1 interface resets",
            "     1943 unknown protocol drops",
            "     0 babbles, 0 late collision, 0 deferred",
            "     0 lost carrier, 0 no carrier, 0 pause output",
            "     0 output buffer failures, 0 output buffers swapped out",
            "GigabitEthernet0/1 is administratively down, line protocol is down ",
            "  Hardware is iGbE, address is 5254.0003.86e2 (bia 5254.0003.86e2)",
            "  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, ",
            "     reliability 255/255, txload 1/255, rxload 1/255",
            "  Encapsulation ARPA, loopback not set",
            "  Keepalive set (10 sec)",
            "  Auto Duplex, Auto Speed, link type is auto, media type is RJ45",
            "  output flow-control is unsupported, input flow-control is unsupported",
            "  ARP type: ARPA, ARP Timeout 04:00:00",
            "  Last input never, output never, output hang never",
            "  Last clearing of \"show interface\" counters never",
            "  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0",
            "  Queueing strategy: fifo",
            "  Output queue: 0/40 (size/max)",
            "  5 minute input rate 0 bits/sec, 0 packets/sec",
            "  5 minute output rate 0 bits/sec, 0 packets/sec",
            "     0 packets input, 0 bytes, 0 no buffer",
            "     Received 0 broadcasts (0 IP multicasts)",
            "     0 runts, 0 giants, 0 throttles ",
            "     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored",
            "     0 watchdog, 0 multicast, 0 pause input",
            "     0 packets output, 0 bytes, 0 underruns",
            "     0 output errors, 0 collisions, 1 interface resets",
            "     0 unknown protocol drops",
            "     0 babbles, 0 late collision, 0 deferred",
            "     0 lost carrier, 0 no carrier, 0 pause output",
            "     0 output buffer failures, 0 output buffers swapped out",
            "GigabitEthernet0/2 is administratively down, line protocol is down ",
            "  Hardware is iGbE, address is 5254.001c.3b2b (bia 5254.001c.3b2b)",
            "  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, ",
            "     reliability 255/255, txload 1/255, rxload 1/255",
            "  Encapsulation ARPA, loopback not set",
            "  Keepalive set (10 sec)",
            "  Auto Duplex, Auto Speed, link type is auto, media type is RJ45",
            "  output flow-control is unsupported, input flow-control is unsupported",
            "  ARP type: ARPA, ARP Timeout 04:00:00",
            "  Last input never, output never, output hang never",
            "  Last clearing of \"show interface\" counters never",
            "  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0",
            "  Queueing strategy: fifo",
            "  Output queue: 0/40 (size/max)",
            "  5 minute input rate 0 bits/sec, 0 packets/sec",
            "  5 minute output rate 0 bits/sec, 0 packets/sec",
            "     0 packets input, 0 bytes, 0 no buffer",
            "     Received 0 broadcasts (0 IP multicasts)",
            "     0 runts, 0 giants, 0 throttles ",
            "     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored",
            "     0 watchdog, 0 multicast, 0 pause input",
            "     0 packets output, 0 bytes, 0 underruns",
            "     0 output errors, 0 collisions, 1 interface resets",
            "     0 unknown protocol drops",
            "     0 babbles, 0 late collision, 0 deferred",
            "     0 lost carrier, 0 no carrier, 0 pause output",
            "     0 output buffer failures, 0 output buffers swapped out",
            "GigabitEthernet0/3 is up, line protocol is up ",
            "  Hardware is iGbE, address is 5254.000a.86a0 (bia 5254.000a.86a0)",
            "  Description: aaa",
            "  Internet address is 10.0.0.1/24",
            "  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, ",
            "     reliability 255/255, txload 1/255, rxload 1/255",
            "  Encapsulation ARPA, loopback not set",
            "  Keepalive set (10 sec)",
            "  Auto Duplex, Auto Speed, link type is auto, media type is RJ45",
            "  output flow-control is unsupported, input flow-control is unsupported",
            "  ARP type: ARPA, ARP Timeout 04:00:00",
            "  Last input 00:00:00, output 00:00:01, output hang never",
            "  Last clearing of \"show interface\" counters never",
            "  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0",
            "  Queueing strategy: fifo",
            "  Output queue: 0/40 (size/max)",
            "  5 minute input rate 0 bits/sec, 0 packets/sec",
            "  5 minute output rate 0 bits/sec, 0 packets/sec",
            "     570744 packets input, 82482023 bytes, 0 no buffer",
            "     Received 5 broadcasts (0 IP multicasts)",
            "     0 runts, 0 giants, 0 throttles ",
            "     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored",
            "     0 watchdog, 0 multicast, 0 pause input",
            "     1014665 packets output, 108824924 bytes, 0 underruns",
            "     0 output errors, 0 collisions, 1 interface resets",
            "     0 unknown protocol drops",
            "     0 babbles, 0 late collision, 0 deferred",
            "     0 lost carrier, 0 no carrier, 0 pause output",
            "     0 output buffer failures, 0 output buffers swapped out",
            "Loopback0 is up, line protocol is up ",
            "  Hardware is Loopback",
            "  Internet address is 10.255.255.1/32",
            "  MTU 1514 bytes, BW 8000000 Kbit/sec, DLY 5000 usec, ",
            "     reliability 255/255, txload 1/255, rxload 1/255",
            "  Encapsulation LOOPBACK, loopback not set",
            "  Keepalive set (10 sec)",
            "  Last input never, output never, output hang never",
            "  Last clearing of \"show interface\" counters never",
            "  Input queue: 0/75/0/0 (size/max/drops/flushes); Total output drops: 0",
            "  Queueing strategy: fifo",
            "  Output queue: 0/0 (size/max)",
            "  5 minute input rate 0 bits/sec, 0 packets/sec",
            "  5 minute output rate 0 bits/sec, 0 packets/sec",
            "     0 packets input, 0 bytes, 0 no buffer",
            "     Received 0 broadcasts (0 IP multicasts)",
            "     0 runts, 0 giants, 0 throttles ",
            "     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort",
            "     0 packets output, 0 bytes, 0 underruns",
            "     0 output errors, 0 collisions, 0 interface resets",
            "     0 unknown protocol drops",
            "     0 output buffer failures, 0 output buffers swapped out"
        ]
    }
}

PLAY RECAP *****************************************************************************************************************
rt01                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

# ansible-playbook -i inventory.ini cli_parce.yml 

PLAY [rt01] ****************************************************************************************************************

TASK [test] ****************************************************************************************************************
ok: [rt01]

TASK [debug] ***************************************************************************************************************
ok: [rt01] => {
    "msg": [
        {
            "abort": "",
            "address": "5254.001c.d627",
            "bandwidth": "1000000 Kbit",
            "bia": "5254.001c.d627",
            "crc": "0",
            "delay": "10 usec",
            "description": "",
            "duplex": "Auto Duplex",
            "encapsulation": "ARPA",
            "hardware_type": "iGbE",
            "input_errors": "40",
            "input_packets": "2924457",
            "input_rate": "1000",
            "interface": "GigabitEthernet0/0",
            "ip_address": "192.168.1.11/24",
            "last_input": "00:00:00",
            "last_output": "00:00:00",
            "last_output_hang": "never",
            "link_status": "up",
            "media_type": "RJ45",
            "mtu": "1500",
            "output_errors": "0",
            "output_packets": "642879",
            "output_rate": "1000",
            "protocol_status": "up",
            "queue_strategy": "fifo",
            "speed": "Auto Speed"
        },
        {
            "abort": "",
            "address": "5254.0003.86e2",
            "bandwidth": "1000000 Kbit",
            "bia": "5254.0003.86e2",
            "crc": "0",
            "delay": "10 usec",
            "description": "",
            "duplex": "Auto Duplex",
            "encapsulation": "ARPA",
            "hardware_type": "iGbE",
            "input_errors": "0",
            "input_packets": "0",
            "input_rate": "0",
            "interface": "GigabitEthernet0/1",
            "ip_address": "",
            "last_input": "never",
            "last_output": "never",
            "last_output_hang": "never",
            "link_status": "administratively down",
            "media_type": "RJ45",
            "mtu": "1500",
            "output_errors": "0",
            "output_packets": "0",
            "output_rate": "0",
            "protocol_status": "down",
            "queue_strategy": "fifo",
            "speed": "Auto Speed"
        },
        {
            "abort": "",
            "address": "5254.001c.3b2b",
            "bandwidth": "1000000 Kbit",
            "bia": "5254.001c.3b2b",
            "crc": "0",
            "delay": "10 usec",
            "description": "",
            "duplex": "Auto Duplex",
            "encapsulation": "ARPA",
            "hardware_type": "iGbE",
            "input_errors": "0",
            "input_packets": "0",
            "input_rate": "0",
            "interface": "GigabitEthernet0/2",
            "ip_address": "",
            "last_input": "never",
            "last_output": "never",
            "last_output_hang": "never",
            "link_status": "administratively down",
            "media_type": "RJ45",
            "mtu": "1500",
            "output_errors": "0",
            "output_packets": "0",
            "output_rate": "0",
            "protocol_status": "down",
            "queue_strategy": "fifo",
            "speed": "Auto Speed"
        },
        {
            "abort": "",
            "address": "5254.000a.86a0",
            "bandwidth": "1000000 Kbit",
            "bia": "5254.000a.86a0",
            "crc": "0",
            "delay": "10 usec",
            "description": "aaa",
            "duplex": "Auto Duplex",
            "encapsulation": "ARPA",
            "hardware_type": "iGbE",
            "input_errors": "0",
            "input_packets": "570759",
            "input_rate": "0",
            "interface": "GigabitEthernet0/3",
            "ip_address": "10.0.0.1/24",
            "last_input": "00:00:01",
            "last_output": "00:00:03",
            "last_output_hang": "never",
            "link_status": "up",
            "media_type": "RJ45",
            "mtu": "1500",
            "output_errors": "0",
            "output_packets": "1014690",
            "output_rate": "0",
            "protocol_status": "up",
            "queue_strategy": "fifo",
            "speed": "Auto Speed"
        },
        {
            "abort": "0",
            "address": "",
            "bandwidth": "8000000 Kbit",
            "bia": "",
            "crc": "0",
            "delay": "5000 usec",
            "description": "",
            "duplex": "",
            "encapsulation": "LOOPBACK",
            "hardware_type": "Loopback",
            "input_errors": "0",
            "input_packets": "0",
            "input_rate": "0",
            "interface": "Loopback0",
            "ip_address": "10.255.255.1/32",
            "last_input": "never",
            "last_output": "never",
            "last_output_hang": "never",
            "link_status": "up",
            "media_type": "",
            "mtu": "1514",
            "output_errors": "0",
            "output_packets": "0",
            "output_rate": "0",
            "protocol_status": "up",
            "queue_strategy": "fifo",
            "speed": ""
        }
    ]
}

PLAY RECAP *****************************************************************************************************************
rt01                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

parsed 配下を一部抜粋すると、このようになっています。

        "parsed": [
            {
                "abort": "",
                "address": "5254.001c.d627",
                "bandwidth": "1000000 Kbit",
                "bia": "5254.001c.d627",
                "crc": "0",
                "delay": "10 usec",
                "description": "",
                "duplex": "Auto Duplex",
                "encapsulation": "ARPA",
                "hardware_type": "iGbE",
                "input_errors": "40",
                "input_packets": "2924240",
                "input_rate": "0",
                "interface": "GigabitEthernet0/0",
                "ip_address": "192.168.1.11/24",
                "last_input": "00:00:00",
                "last_output": "00:00:00",
                "last_output_hang": "never",
                "link_status": "up",
                "media_type": "RJ45",
                "mtu": "1500",
                "output_errors": "0",
                "output_packets": "642722",
                "output_rate": "0",
                "protocol_status": "up",
                "queue_strategy": "fifo",
                "speed": "Auto Speed"
            },

ntc-temlates の実際のテンプレートを見ると、キーは大文字なのですが、cli_parse モジュールを経由すると小文字になるようです。(参考: parse_cli_textfsm フィルターを使う場合は大文字

# cat ~/envs/ab210/lib/python3.6/site-packages/ntc_templates/templates/cisco_ios_show_interfaces.textfsm 
Value Required INTERFACE (\S+)
Value LINK_STATUS (.+?)
Value PROTOCOL_STATUS (.+?)
Value HARDWARE_TYPE ([\w ]+)
...(略)...

リポジトリ上の cisco_ios_show_interfaces.textfsm はこちら

pyats に挑戦

何も考えずに実行

パーサーに pyats も選べるようだったので、Playbook を以下のように修正して実行しました。

---
- hosts: rt01
  gather_facts: false

  tasks:
    - name: test
      ansible.netcommon.cli_parse:
        command: "show interface"
        parser:
          name: ansible.netcommon.pyats   # パーサー変更
      register: parser_output
    
    - name: debug
      debug:
        msg: "{{ parser_output.parsed }}"

やはり、まだ必要なライブラリをインストールしていないので、その旨のエラーが出ました。

TASK [test] ****************************************************************************************************************
fatal: [rt01]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (genie) on 2a5505f15a98's Python /root/envs/ab210/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter Failed to import the required Python library (pyats) on 2a5505f15a98's Python /root/envs/ab210/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter"}

geniepyats のインストール

ということで、geniepyats をインストール。

# pip install genie
...(略)...
# pip install pyats
...(略)...

pyats のインストールは、以下のような gcc がないというエラーが表示されました。

  gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -DPSUTIL_POSIX=1 -DPSUTIL_SIZEOF_PID_T=4 -DPSUTIL_VERSION=572 -DPSUTIL_LINUX=1 -DPSUTIL_ETHTOOL_MISSING_TYPES=1 -I/root/envs/ab210/include -I/usr/include/python3.6m -c psutil/_psutil_common.c -o build/temp.linux-x86_64-3.6/psutil/_psutil_common.o
  unable to execute 'gcc': No such file or directory
  C compiler or Python headers are not installed on this system. Try to run:
  sudo yum install gcc python3-devel
  error: command 'gcc' failed with exit status 1

以下のコマンドで対策後、再度 pip install pyats したところ無事にインストールできました。

# yum install gcc python3-devel

※動画では、genie をインストールしたあとの Playbook の実行で、まだ同様のエラーがでたため、 ansible_python_interpreter 変数を設定していましたが、あとで切り分けたところ不要でした。

再実行(パーサーがないエラー)

Playbook を再実行したところ以下のエラー。ライブラリ自体の問題は解消されたようですが、もう一息のようで・・。コマンドに対応するパーサーがないといったメッセージのようです。

TASK [test] ***********************************************************************************************************
fatal: [rt01]: FAILED! => {"changed": false, "msg": "The pyats library return an error for 'show interface' for 'iosxe'. Error: Could not find parser for 'show interface' under ('iosxe',)."}

追加インストール、そして破壊

なにかインストールが足りないのかなぁと思いながら、pyATS のサイトをみながら、かなり乱暴に pip install pyats[full] をすれば行けるんじゃないかと思いました(だめでした)。

# pip install pyats[full] 
...(略)...
Collecting ansible (from pyats.contrib<20.9.0,>=20.8.0; extra == "full"->pyats[full])
...(略)...

すると、依存ライブラリとして ansible 2.9.13 がインストールされました。

もとの環境は ansible ではなく、ansible-base 2.10.0 だったので、すでにインストール済みとはみなされず、別途 ansible がインストールされたのだと思います。

嫌な予感がしたのですが、バージョン表示すらできないほど環境が壊れてしまいました。

# ansible --version
ERROR! Unexpected Exception, this is probably a bug: cannot import name 'AnsibleCollectionLoader'
the full traceback was:

Traceback (most recent call last):
  File "/root/envs/ab210/bin/ansible", line 92, in <module>
    mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
  File "/root/envs/ab210/lib64/python3.6/site-packages/ansible/cli/__init__.py", line 22, in <module>
    from ansible.inventory.manager import InventoryManager
  File "/root/envs/ab210/lib64/python3.6/site-packages/ansible/inventory/manager.py", line 38, in <module>
    from ansible.plugins.loader import inventory_loader
  File "/root/envs/ab210/lib64/python3.6/site-packages/ansible/plugins/loader.py", line 26, in <module>
    from ansible.utils.collection_loader import AnsibleCollectionLoader, AnsibleFlatMapLoader, AnsibleCollectionRef
ImportError: cannot import name 'AnsibleCollectionLoader'

ここで時間切れ。ありがとうございました。

環境は壊れてしまいましたが、venv 内だったので復旧は難しくはないです。venv 環境の初期化は--clear オプションが便利です。

後日解決・・!(コマンドは省略しない表記にするのがポイント)

pyATS に詳しい後輩氏からアドバイスがあり、show interfaceshow interfaces (末尾sあり)にしたら無事に実行できました。

show interface のような省略コマンドでは、対応するパーサーを見つけられなかったようです。

うまく実行できた例(クリックして開く)

TASK [debug] **********************************************************************************************************
ok: [rt01] => {
    "msg": {
        "GigabitEthernet0/0": {
            "arp_timeout": "04:00:00",
            "arp_type": "arpa",
            "auto_negotiate": true,
            "bandwidth": 1000000,
            "counters": {
                "in_broadcast_pkts": 0,
                "in_crc_errors": 0,
                "in_errors": 40,
                "in_frame": 0,
                "in_giants": 0,
                "in_ignored": 0,
                "in_mac_pause_frames": 0,
                "in_multicast_pkts": 0,
                "in_no_buffer": 0,
                "in_octets": 240967333,
                "in_overrun": 0,
                "in_pkts": 2981249,
                "in_runts": 40,
                "in_throttles": 0,
                "in_watchdog": 0,
                "last_clear": "never",
                "out_babble": 0,
                "out_buffer_failure": 0,
                "out_buffers_swapped": 0,
                "out_collision": 0,
                "out_deferred": 0,
                "out_errors": 0,
                "out_interface_resets": 1,
                "out_late_collision": 0,
                "out_lost_carrier": 0,
                "out_mac_pause_frames": 0,
                "out_no_carrier": 0,
                "out_octets": 76473991,
                "out_pkts": 658729,
                "out_underruns": 0,
                "out_unknown_protocl_drops": 1943,
                "rate": {
                    "in_rate": 1000,
                    "in_rate_pkts": 1,
                    "load_interval": 300,
                    "out_rate": 1000,
                    "out_rate_pkts": 1
                }
            },
            "delay": 10,
            "duplex_mode": "auto",
            "enabled": true,
            "encapsulations": {
                "encapsulation": "arpa"
            },
            "flow_control": {
                "receive": false,
                "send": false
            },
            "ipv4": {
                "192.168.1.11/24": {
                    "ip": "192.168.1.11",
                    "prefix_length": "24"
                }
            },
            "keepalive": 10,
            "last_input": "00:00:00",
            "last_output": "00:00:00",
            "line_protocol": "up",
            "link_type": "auto",
            "mac_address": "5254.001c.d627",
            "media_type": "RJ45",
            "mtu": 1500,
            "oper_status": "up",
            "output_hang": "never",
            "phys_address": "5254.001c.d627",
            "port_channel": {
                "port_channel_member": false
            },
            "port_speed": "auto speed",
            "queues": {
                "input_queue_drops": 0,
                "input_queue_flushes": 0,
                "input_queue_max": 75,
                "input_queue_size": 1,
                "output_queue_max": 40,
                "output_queue_size": 0,
                "queue_strategy": "fifo",
                "total_output_drop": 0
            },
            "reliability": "255/255",
            "rxload": "1/255",
            "txload": "1/255",
            "type": "iGbE"
        },
        "GigabitEthernet0/1": {
            "arp_timeout": "04:00:00",
            "arp_type": "arpa",
            "auto_negotiate": true,
            "bandwidth": 1000000,
            "counters": {
                "in_broadcast_pkts": 0,
                "in_crc_errors": 0,
                "in_errors": 0,
                "in_frame": 0,
                "in_giants": 0,
                "in_ignored": 0,
                "in_mac_pause_frames": 0,
                "in_multicast_pkts": 0,
                "in_no_buffer": 0,
                "in_octets": 0,
                "in_overrun": 0,
                "in_pkts": 0,
                "in_runts": 0,
                "in_throttles": 0,
                "in_watchdog": 0,
                "last_clear": "never",
                "out_babble": 0,
                "out_buffer_failure": 0,
                "out_buffers_swapped": 0,
                "out_collision": 0,
                "out_deferred": 0,
                "out_errors": 0,
                "out_interface_resets": 1,
                "out_late_collision": 0,
                "out_lost_carrier": 0,
                "out_mac_pause_frames": 0,
                "out_no_carrier": 0,
                "out_octets": 0,
                "out_pkts": 0,
                "out_underruns": 0,
                "out_unknown_protocl_drops": 0,
                "rate": {
                    "in_rate": 0,
                    "in_rate_pkts": 0,
                    "load_interval": 300,
                    "out_rate": 0,
                    "out_rate_pkts": 0
                }
            },
            "delay": 10,
            "duplex_mode": "auto",
            "enabled": false,
            "encapsulations": {
                "encapsulation": "arpa"
            },
            "flow_control": {
                "receive": false,
                "send": false
            },
            "keepalive": 10,
            "last_input": "never",
            "last_output": "never",
            "line_protocol": "down",
            "link_type": "auto",
            "mac_address": "5254.0003.86e2",
            "media_type": "RJ45",
            "mtu": 1500,
            "oper_status": "down",
            "output_hang": "never",
            "phys_address": "5254.0003.86e2",
            "port_channel": {
                "port_channel_member": false
            },
            "port_speed": "auto speed",
            "queues": {
                "input_queue_drops": 0,
                "input_queue_flushes": 0,
                "input_queue_max": 75,
                "input_queue_size": 0,
                "output_queue_max": 40,
                "output_queue_size": 0,
                "queue_strategy": "fifo",
                "total_output_drop": 0
            },
            "reliability": "255/255",
            "rxload": "1/255",
            "txload": "1/255",
            "type": "iGbE"
        },
        "GigabitEthernet0/2": {
            "arp_timeout": "04:00:00",
            "arp_type": "arpa",
            "auto_negotiate": true,
            "bandwidth": 1000000,
            "counters": {
                "in_broadcast_pkts": 0,
                "in_crc_errors": 0,
                "in_errors": 0,
                "in_frame": 0,
                "in_giants": 0,
                "in_ignored": 0,
                "in_mac_pause_frames": 0,
                "in_multicast_pkts": 0,
                "in_no_buffer": 0,
                "in_octets": 0,
                "in_overrun": 0,
                "in_pkts": 0,
                "in_runts": 0,
                "in_throttles": 0,
                "in_watchdog": 0,
                "last_clear": "never",
                "out_babble": 0,
                "out_buffer_failure": 0,
                "out_buffers_swapped": 0,
                "out_collision": 0,
                "out_deferred": 0,
                "out_errors": 0,
                "out_interface_resets": 1,
                "out_late_collision": 0,
                "out_lost_carrier": 0,
                "out_mac_pause_frames": 0,
                "out_no_carrier": 0,
                "out_octets": 0,
                "out_pkts": 0,
                "out_underruns": 0,
                "out_unknown_protocl_drops": 0,
                "rate": {
                    "in_rate": 0,
                    "in_rate_pkts": 0,
                    "load_interval": 300,
                    "out_rate": 0,
                    "out_rate_pkts": 0
                }
            },
            "delay": 10,
            "duplex_mode": "auto",
            "enabled": false,
            "encapsulations": {
                "encapsulation": "arpa"
            },
            "flow_control": {
                "receive": false,
                "send": false
            },
            "keepalive": 10,
            "last_input": "never",
            "last_output": "never",
            "line_protocol": "down",
            "link_type": "auto",
            "mac_address": "5254.001c.3b2b",
            "media_type": "RJ45",
            "mtu": 1500,
            "oper_status": "down",
            "output_hang": "never",
            "phys_address": "5254.001c.3b2b",
            "port_channel": {
                "port_channel_member": false
            },
            "port_speed": "auto speed",
            "queues": {
                "input_queue_drops": 0,
                "input_queue_flushes": 0,
                "input_queue_max": 75,
                "input_queue_size": 0,
                "output_queue_max": 40,
                "output_queue_size": 0,
                "queue_strategy": "fifo",
                "total_output_drop": 0
            },
            "reliability": "255/255",
            "rxload": "1/255",
            "txload": "1/255",
            "type": "iGbE"
        },
        "GigabitEthernet0/3": {
            "arp_timeout": "04:00:00",
            "arp_type": "arpa",
            "auto_negotiate": true,
            "bandwidth": 1000000,
            "counters": {
                "in_broadcast_pkts": 0,
                "in_crc_errors": 0,
                "in_errors": 0,
                "in_frame": 0,
                "in_giants": 0,
                "in_ignored": 0,
                "in_mac_pause_frames": 0,
                "in_multicast_pkts": 0,
                "in_no_buffer": 0,
                "in_octets": 84398478,
                "in_overrun": 0,
                "in_pkts": 581431,
                "in_runts": 0,
                "in_throttles": 0,
                "in_watchdog": 0,
                "last_clear": "never",
                "out_babble": 0,
                "out_buffer_failure": 0,
                "out_buffers_swapped": 0,
                "out_collision": 0,
                "out_deferred": 0,
                "out_errors": 0,
                "out_interface_resets": 1,
                "out_late_collision": 0,
                "out_lost_carrier": 0,
                "out_mac_pause_frames": 0,
                "out_no_carrier": 0,
                "out_octets": 111123544,
                "out_pkts": 1032226,
                "out_underruns": 0,
                "out_unknown_protocl_drops": 0,
                "rate": {
                    "in_rate": 0,
                    "in_rate_pkts": 0,
                    "load_interval": 300,
                    "out_rate": 0,
                    "out_rate_pkts": 0
                }
            },
            "delay": 10,
            "description": "aaa",
            "duplex_mode": "auto",
            "enabled": true,
            "encapsulations": {
                "encapsulation": "arpa"
            },
            "flow_control": {
                "receive": false,
                "send": false
            },
            "ipv4": {
                "10.0.0.1/24": {
                    "ip": "10.0.0.1",
                    "prefix_length": "24"
                }
            },
            "keepalive": 10,
            "last_input": "00:00:01",
            "last_output": "00:00:03",
            "line_protocol": "up",
            "link_type": "auto",
            "mac_address": "5254.000a.86a0",
            "media_type": "RJ45",
            "mtu": 1500,
            "oper_status": "up",
            "output_hang": "never",
            "phys_address": "5254.000a.86a0",
            "port_channel": {
                "port_channel_member": false
            },
            "port_speed": "auto speed",
            "queues": {
                "input_queue_drops": 0,
                "input_queue_flushes": 0,
                "input_queue_max": 75,
                "input_queue_size": 0,
                "output_queue_max": 40,
                "output_queue_size": 0,
                "queue_strategy": "fifo",
                "total_output_drop": 0
            },
            "reliability": "255/255",
            "rxload": "1/255",
            "txload": "1/255",
            "type": "iGbE"
        },
        "Loopback0": {
            "bandwidth": 8000000,
            "counters": {
                "in_abort": 0,
                "in_broadcast_pkts": 0,
                "in_crc_errors": 0,
                "in_errors": 0,
                "in_frame": 0,
                "in_giants": 0,
                "in_ignored": 0,
                "in_multicast_pkts": 0,
                "in_no_buffer": 0,
                "in_octets": 0,
                "in_overrun": 0,
                "in_pkts": 0,
                "in_runts": 0,
                "in_throttles": 0,
                "last_clear": "never",
                "out_buffer_failure": 0,
                "out_buffers_swapped": 0,
                "out_collision": 0,
                "out_errors": 0,
                "out_interface_resets": 0,
                "out_octets": 0,
                "out_pkts": 0,
                "out_underruns": 0,
                "out_unknown_protocl_drops": 0,
                "rate": {
                    "in_rate": 0,
                    "in_rate_pkts": 0,
                    "load_interval": 300,
                    "out_rate": 0,
                    "out_rate_pkts": 0
                }
            },
            "delay": 5000,
            "enabled": true,
            "encapsulations": {
                "encapsulation": "loopback"
            },
            "ipv4": {
                "10.255.255.1/32": {
                    "ip": "10.255.255.1",
                    "prefix_length": "32"
                }
            },
            "keepalive": 10,
            "last_input": "never",
            "last_output": "never",
            "line_protocol": "up",
            "mtu": 1514,
            "oper_status": "up",
            "output_hang": "never",
            "port_channel": {
                "port_channel_member": false
            },
            "queues": {
                "input_queue_drops": 0,
                "input_queue_flushes": 0,
                "input_queue_max": 75,
                "input_queue_size": 0,
                "output_queue_max": 0,
                "output_queue_size": 0,
                "queue_strategy": "fifo",
                "total_output_drop": 0
            },
            "reliability": "255/255",
            "rxload": "1/255",
            "txload": "1/255",
            "type": "Loopback"
        }
    }
}

冪等性の観点で、設定コマンドは省略せずに書くことを意識していましたが、show コマンドについても省略せずに書くのが良いですね。

なお、ntc-templates のときに、省略形の show interface でもパースできていたのは、以下のように、省略形コマンドでも大丈夫なような割当になっていたからのようです。

# cat ~/envs/ab210/lib/python3.6/site-packages/ntc_templates/templates/index | grep cisco_ios_show_interfaces_status.textfsm
cisco_ios_show_interfaces_status.textfsm, .*, cisco_ios, sh[[ow]] int[[erfaces]] st[[atus]]


補足

[2020/09/16 追記] 後日、モジュールの説明ページより詳しいページを教えていただきました。

ansible/cli_parsing.rst at 9b66d7f7a47fa9596965e110384473b5ea38a3ee · ansible/ansible · GitHub

[2020/09/23 追記] 上記のページが、最新安定版のドキュメントとして公開されました。

docs.ansible.com

Part16 にむけて

以下のネタを検討中です。気が向いたものをやります。

  • connection: local ななにか
  • Ansible Toewr / AWX をコマンドがら操作する
  • ansible.cfg
  • Jinja2、フィルター
  • Windows
  • when、assert など