はじめに
2020/09/12 に、YouTube Live で「つまずき Ansible 【Part15】cli_parse モジュールで構造化データを取得する」という配信をしました。
実際に作業しながらエラーと戦って進めるシリーズです。
今回は、ansible.netcommon collection の cli_parse モジュールを使って、ネットワーク機器への show コマンドの実行結果を構造化データで取得する Playbook を書いてみました。
cli_parse モジュールは、パーサーとして以下のものを選べるようです。
native
ntc-templates
pyats
textfsm
ttp
xml
今回は ntc-templates
と pyats
に挑戦しました。
やったことや、わかったことをふりかえります。
- 環境
- ansible-base 2.10.0
[2020/12/14 追記] ansible.utils colleciton に移動するという動きがありました
動画
■ やったこと
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
に、生の結果は stdout
や stdout_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"}
genie
と pyats
のインストール
ということで、genie
と pyats
をインストール。
# 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 interface
を show interfaces
(末尾sあり)にしたら無事に実行できました。
外出中であまり見れてませんが!
— うさぎエンジニア (@usagi_automate) 2020年9月13日
Paserのエラーっぽいですね、
そんなPaserないよって言われてるっぽい??
show interfacesにしたらいくとかないっすかね pic.twitter.com/w458dEZvLz
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 追記] 上記のページが、最新安定版のドキュメントとして公開されました。
Part16 にむけて
以下のネタを検討中です。気が向いたものをやります。
- connection: local ななにか
- Ansible Toewr / AWX をコマンドがら操作する
- ansible.cfg
- Jinja2、フィルター
- Windows
- when、assert など