pyATS を使ってルーティング情報の更新を確認する
pyATS とは
pyATS は Cisco が開発している、テストフレームワークです。python で書かれており、ネットワークのテストに必要な機能が実装されています。今回は、コードを書かずに pyATS に用意されている CLI ツールを使用し、ネットワーク機器の状態が変化した際の差分を確認していきます。
pyATS のインストール
Cisco DevNet: APIs, SDKs, Sandbox, and Community for Cisco Developers
公式ドキュメントの手順に従い、venv の環境に、pyats のパッケージをインストールします。
[root@localhost ~]# mkdir pyats [root@localhost ~]# cd pyats [root@localhost pyats]# python3.6 --version Python 3.6.8 [root@localhost pyats]# python3.6 -m venv . [root@localhost pyats]# ls bin include lib lib64 pyvenv.cfg [root@localhost pyats]# source bin/activate (pyats) [root@localhost pyats]# pip install --upgrade pip setuptools (pyats) [root@localhost pyats]# pip install pyats[full]
構成
以下のようなマルチOSな環境で RT2 に変更を加えます。前後でどのように状態が変化するのか pyATS を使って確認します。
testbed の準備
ネットワーク機器の情報を yaml ファイルに記載しておきます。
testbed: name: My topology credentials: default: username: admin password: password enable: password: password devices: csr1kv-1: type: 'router' os: 'iosxe' platform: asr1k alias: 'RT1' connections: cli: protocol: ssh ip: "172.16.0.11" n9kv-1: type: 'router' os: 'nxos' platform: n9kv alias: 'RT2' connections: cli: protocol: ssh ip: "172.16.0.12" n9kv-2: type: 'router' os: 'nxos' platform: n9kv alias: 'RT3' connections: cli: protocol: ssh ip: "172.16.0.13" iosv-1: type: 'router' os: 'ios' platform: ios alias: 'RT4' connections: cli: protocol: ssh ip: "172.16.0.14"
pyATS learn
の実行 【変更前】
ospf
と routing
の状態を pyATS を使って収集します。output1
ディレクトリに収集した情報が保存されます。
(pyats) [root@localhost pyATS_diff]# genie learn "ospf" "routing" --testbed-file testbed.yaml --output output1 Learning '['ospf', 'routing']' on devices '['csr1kv-1', 'n9kv-1', 'n9kv-2', 'iosv-1']' 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:14<00:00, 7.15s/it] +==============================================================================+ | Genie Learn Summary for device csr1kv-1 | +==============================================================================+ | Connected to csr1kv-1 | | - Log: output1/connection_csr1kv-1.txt | |------------------------------------------------------------------------------| | Learnt feature 'ospf' | | - Ops structure: output1/ospf_iosxe_csr1kv-1_ops.txt | | - Device Console: output1/ospf_iosxe_csr1kv-1_console.txt | |------------------------------------------------------------------------------| | Learnt feature 'routing' | | - Ops structure: output1/routing_iosxe_csr1kv-1_ops.txt | | - Device Console: output1/routing_iosxe_csr1kv-1_console.txt | |==============================================================================| +==============================================================================+ | Genie Learn Summary for device n9kv-1 | +==============================================================================+ | Connected to n9kv-1 | | - Log: output1/connection_n9kv-1.txt | |------------------------------------------------------------------------------| | Learnt feature 'ospf' | | - Ops structure: output1/ospf_nxos_n9kv-1_ops.txt | | - Device Console: output1/ospf_nxos_n9kv-1_console.txt | |------------------------------------------------------------------------------| | Learnt feature 'routing' | | - Ops structure: output1/routing_nxos_n9kv-1_ops.txt | | - Device Console: output1/routing_nxos_n9kv-1_console.txt | |==============================================================================| +==============================================================================+ | Genie Learn Summary for device n9kv-2 | +==============================================================================+ | Connected to n9kv-2 | | - Log: output1/connection_n9kv-2.txt | |------------------------------------------------------------------------------| | Learnt feature 'ospf' | | - Ops structure: output1/ospf_nxos_n9kv-2_ops.txt | | - Device Console: output1/ospf_nxos_n9kv-2_console.txt | |------------------------------------------------------------------------------| | Learnt feature 'routing' | | - Ops structure: output1/routing_nxos_n9kv-2_ops.txt | | - Device Console: output1/routing_nxos_n9kv-2_console.txt | |==============================================================================| +==============================================================================+ | Genie Learn Summary for device iosv-1 | +==============================================================================+ | Connected to iosv-1 | | - Log: output1/connection_iosv-1.txt | |------------------------------------------------------------------------------| | Learnt feature 'ospf' | | - Ops structure: output1/ospf_ios_iosv-1_ops.txt | | - Device Console: output1/ospf_ios_iosv-1_console.txt | |------------------------------------------------------------------------------| | Learnt feature 'routing' | | - Ops structure: output1/routing_ios_iosv-1_ops.txt | | - Device Console: output1/routing_ios_iosv-1_console.txt | |==============================================================================| (pyats) [root@localhost pyATS_diff]# ls -1 output1/ connection_csr1kv-1.txt connection_iosv-1.txt connection_n9kv-1.txt connection_n9kv-2.txt ospf_ios_iosv-1_console.txt ospf_ios_iosv-1_ops.txt ospf_iosxe_csr1kv-1_console.txt ospf_iosxe_csr1kv-1_ops.txt ospf_nxos_n9kv-1_console.txt ospf_nxos_n9kv-1_ops.txt ospf_nxos_n9kv-2_console.txt ospf_nxos_n9kv-2_ops.txt routing_ios_iosv-1_console.txt routing_ios_iosv-1_ops.txt routing_iosxe_csr1kv-1_console.txt routing_iosxe_csr1kv-1_ops.txt routing_nxos_n9kv-1_console.txt routing_nxos_n9kv-1_ops.txt routing_nxos_n9kv-2_console.txt routing_nxos_n9kv-2_ops.txt (pyats) [root@localhost pyATS_diff]#
_console.txt
にはコンソール出力、_ops.txt
には pyATS がコンソール出力を解析した結果を key-value 形式(json)で保存してくれます。
routing_iosxe_csr1kv-1_ops.txt
(pyats) [root@localhost pyATS_diff]# cat output1/routing_iosxe_csr1kv-1_ops.txt { "_exclude": [], "attributes": null, "commands": null, "connections": null, "context_manager": {}, "info": { "vrf": { "default": { "address_family": { "ipv4": { "routes": { "1.1.1.1/32": { "active": true, "next_hop": { "outgoing_interface": { "Loopback0": { "outgoing_interface": "Loopback0" } } }, "route": "1.1.1.1/32", "source_protocol": "connected", "source_protocol_codes": "C" }, "1.1.1.2/32": { "active": true, "metric": 2, "next_hop": { "next_hop_list": { "1": { "index": 1, "next_hop": "10.0.0.1", "outgoing_interface": "GigabitEthernet2", "updated": "02:10:21" } } }, --- snip ---
routing_iosxe_csr1kv-1_console.txt
+++ csr1kv-1: executing command 'show vrf detail' +++ show vrf detail --- snip --- +++ csr1kv-1: executing command 'show ip route' +++ show 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 1.0.0.0/32 is subnetted, 4 subnets C 1.1.1.1 is directly connected, Loopback0 O 1.1.1.2 [110/2] via 10.0.0.1, 02:10:21, GigabitEthernet2 O 1.1.1.3 [110/2] via 10.0.0.3, 02:10:21, GigabitEthernet3 O 1.1.1.4 [110/42] via 10.0.0.3, 02:10:21, GigabitEthernet3 [110/42] via 10.0.0.1, 02:10:21, GigabitEthernet2 10.0.0.0/8 is variably subnetted, 6 subnets, 2 masks C 10.0.0.0/31 is directly connected, GigabitEthernet2 L 10.0.0.0/32 is directly connected, GigabitEthernet2 C 10.0.0.2/31 is directly connected, GigabitEthernet3 L 10.0.0.2/32 is directly connected, GigabitEthernet3 O 10.0.0.4/31 [110/41] via 10.0.0.1, 02:10:21, GigabitEthernet2 O 10.0.0.6/31 [110/41] via 10.0.0.3, 02:10:21, GigabitEthernet3 csr1kv-1# +++ csr1kv-1: executing command 'show ipv6 route vrf mgmt updated' +++ show ipv6 route vrf mgmt updated % IPv6 routing table mgmt does not exist csr1kv-1# --- snip ---
RT2 の設定変更
RT2 (n9kv-1v) の Eth 1/3 に IP を設定して、OSPF でアドレスを広告させます。
n9kv-1(config)# int eth 1/3 n9kv-1(config-if)# no switchport n9kv-1(config-if)# ip address 192.168.0.254/24 n9kv-1(config-if)# ip router ospf 1 area 0 n9kv-1(config-if)# no shut
pyATS learn
の実行 【変更後】
再度 genie learn
を実行します。出力結果を output2
ディレクトリに保存するように指定しています。
(pyats) [root@localhost pyATS_diff]# genie learn "ospf" "routing" --testbed-file testbed.yaml --output output2
pyATS を使って差分を確認
genine diff
コマンドを使うことで、pyATS で得られた2つの状態の差分を比較することができます。OSPF は新しくインターフェースを設定した、RT2(n9kv-1)のみに変更があったことがわかります。一方でルーティング情報に関しては、全てのデバイスで変更があったことがわかります。
(pyats) [root@localhost pyATS_diff]# genie diff output1 output2 1it [00:00, 65.76it/s] +==============================================================================+ | Genie Diff Summary between directories output1/ and output2/ | +==============================================================================+ | File: ospf_nxos_n9kv-1_ops.txt | | - Diff can be found at ./diff_ospf_nxos_n9kv-1_ops.txt | |------------------------------------------------------------------------------| | File: ospf_nxos_n9kv-2_ops.txt | | - Identical | |------------------------------------------------------------------------------| | File: ospf_iosxe_csr1kv-1_ops.txt | | - Identical | |------------------------------------------------------------------------------| | File: ospf_ios_iosv-1_ops.txt | | - Identical | |------------------------------------------------------------------------------| | File: routing_nxos_n9kv-1_ops.txt | | - Diff can be found at ./diff_routing_nxos_n9kv-1_ops.txt | |------------------------------------------------------------------------------| | File: routing_nxos_n9kv-2_ops.txt | | - Diff can be found at ./diff_routing_nxos_n9kv-2_ops.txt | |------------------------------------------------------------------------------| | File: routing_ios_iosv-1_ops.txt | | - Diff can be found at ./diff_routing_ios_iosv-1_ops.txt | |------------------------------------------------------------------------------| | File: routing_iosxe_csr1kv-1_ops.txt | | - Diff can be found at ./diff_routing_iosxe_csr1kv-1_ops.txt | |------------------------------------------------------------------------------|
変更の詳細は各ファイルに出力されています。
(pyats) [root@localhost pyATS_diff]# ls -1 diff_ospf_nxos_n9kv-1_ops.txt diff_routing_ios_iosv-1_ops.txt diff_routing_iosxe_csr1kv-1_ops.txt diff_routing_nxos_n9kv-1_ops.txt diff_routing_nxos_n9kv-2_ops.txt output1 output2 testbed.yaml (pyats) [root@localhost pyATS_diff]#
RT1(csr1kv-1) のルーティング情報の差分を確認すると、新しいルートが追加されていることが確認できます。その他、何時間前にOSPF でルート受け取っているのかを確認することができます。
(pyats) [root@localhost diff12]# cat diff_routing_iosxe_csr1kv-1_ops.txt --- output1/routing_iosxe_csr1kv-1_ops.txt +++ output2/routing_iosxe_csr1kv-1_ops.txt info: vrf: default: address_family: ipv4: routes: + 192.168.0.0/24: + active: True + metric: 41 + next_hop: + next_hop_list: + 1: + index: 1 + next_hop: 10.0.0.1 + outgoing_interface: GigabitEthernet2 + updated: 00:01:55 + route: 192.168.0.0/24 + route_preference: 110 + source_protocol: ospf + source_protocol_codes: O 1.1.1.2/32: next_hop: next_hop_list: 1: + updated: 02:13:59 - updated: 02:10:21 1.1.1.3/32: next_hop: next_hop_list: 1: + updated: 02:13:59 - updated: 02:10:21 1.1.1.4/32: next_hop: next_hop_list: 1: + updated: 02:13:59 - updated: 02:10:21 2: + updated: 02:13:59 - updated: 02:10:21 10.0.0.4/31: next_hop: next_hop_list: 1: + updated: 02:13:59 - updated: 02:10:21 10.0.0.6/31: next_hop: next_hop_list: 1: + updated: 02:13:59 - updated: 02:10:21
まとめ
pyATS を使って、ネットワーク機器の状態の差分を確認しました。pyATS の一番のメリットは show コマンドの情報を機械が読みやすい key-value 形式で出力してくれることだと思います。pyATS と Ansible を組み合わせれば、かなり実用的な自動化環境が構築できそうな印象を受けました。