はじめに
Python 製自動化フレームワーク nornir は、接続方法として netmikoや、NAPALM の他に、NETCONF にも対応しています。
この記事では NETCONF 経由で、Cisco IOS XE 機器の runnin-config、インターフェース、ルーティングテーブを取得するサンプルをご紹介します。
環境
- Cisco IOS-XE (16.11)
- Python 3.6.7
- nornir 2.4.0 (
pip install nornir
でインストール)
■ 準備
Python スクリプト本体を作成する前の準備として、以下の2つのファイルを作成します。
config.yml # 設定ファイル(インベントリの形式、ファイルのパスなどを定義) inventory/ hosts.yaml # インベントリファイル(対象機器の情報を定義)
インベントリ
対象機器の情報を定義するインベントリファイルを作成します。
インベントリに利用できる形式は、Ansible や NetBox などがあるようですが、ここでは一番シンプルなインベントリである Simple を利用します。
inventory/hosts.yaml
--- ios01: hostname: ios-xe-mgmt-latest.cisco.com port: 10000 # netconf 利用時のデフォルトは 830 username: developer password: dummy platform: ios # netconf の場合はなんでも良い模様 connection_options: netconf: extras: allow_agent: False hostkey_verify: False
コンフィグファイル
インベントリの形式やファイルのパスを指定します。
config.yaml
--- inventory: plugin: nornir.plugins.inventory.simple.SimpleInventory options: host_file: "inventory/hosts.yaml" # ホストインベントリファイルのパス
■ サンプル1: running-config の取得と表示
netconf_get_config
を利用して、running-confg を取得します。
コード
from nornir import InitNornir from nornir.plugins.tasks.networking import netconf_get_config from xml.dom import minidom # 表示用 nr = InitNornir(config_file="config.yaml") # 初期化 result = nr.run(task=netconf_get_config, source="running") # source は running result_xml = minidom.parseString(result["ios01"].result) print(result_xml.toprettyxml())
実行結果
$ python get_confg.py <?xml version="1.0" ?> <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native"> <version>16.11</version> <!-- 略 --> <hostname>csr1000v-1</hostname> <!-- 略 --> <interface> <GigabitEthernet> <name>1</name> <description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description> <ip> <address> <primary> <address>10.10.20.48</address> <mask>255.255.255.0</mask> </primary> </address> </ip> <mop> <enabled>false</enabled> <sysid>false</sysid> </mop> <negotiation xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-ethernet"> <auto>true</auto> </negotiation> </GigabitEthernet> <!-- 略 --> </interface> <!-- 略 --> </data> $
■ サンプル2: インターフェース情報の取得と表示
netconf_get
を利用して、インターフェース情報を取得します。
コード
from nornir import InitNornir from nornir.plugins.tasks.networking import netconf_get # netconf_get_config ではなく from xml.dom import minidom # 表示用 nr = InitNornir(config_file="config.yaml") # 初期化 result = nr.run(task=netconf_get, path="/interfaces-state") # ポイント result_xml = minidom.parseString(result["ios01"].result) print(result_xml.toprettyxml())
実行結果
$ python get_if_state.py <?xml version="1.0" ?> <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface> <name>GigabitEthernet1</name> <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type> <admin-status>up</admin-status> <oper-status>up</oper-status> <last-change>2020-06-12T23:57:32.000772+00:00</last-change> <if-index>1</if-index> <phys-address>00:50:56:bb:e9:9c</phys-address> <speed>1024000000</speed> <statistics> <discontinuity-time>2020-06-12T23:56:13.000936+00:00</discontinuity-time> <in-octets>24546855591</in-octets> <in-unicast-pkts>39304700</in-unicast-pkts> <in-broadcast-pkts>0</in-broadcast-pkts> <in-multicast-pkts>0</in-multicast-pkts> <in-discards>0</in-discards> <in-errors>0</in-errors> <in-unknown-protos>0</in-unknown-protos> <out-octets>172071875</out-octets> <out-unicast-pkts>532219</out-unicast-pkts> <out-broadcast-pkts>0</out-broadcast-pkts> <out-multicast-pkts>0</out-multicast-pkts> <out-discards>0</out-discards> <out-errors>0</out-errors> </statistics> </interface> <!-- 略 --> </interfaces-state> </data> $
subtree でも指定可能
path
は、上記サンプルのような xpath の他にも subtree でも指定できます。
filter_type="subtree"
を指定するのがポイントです。デフォルトは xpath
です。
# 抜粋 query = """ <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> </interfaces-state> """ result = nr.run(task=netconf_get, path=query, filter_type="subtree")
■ サンプル3: ルーティングテーブルの情報の取得と表示
サンプル2と同じく、netconf_get
を利用して、ルーティングテーブルの情報を取得します。
違いは path
のみです。
コード
from nornir import InitNornir from nornir.plugins.tasks.networking import netconf_get # netconf_get_config ではなく from xml.dom import minidom # 表示用 nr = InitNornir(config_file="config.yaml") # 初期化 result = nr.run(task=netconf_get, path="/routing-state") # サンプル2との違い result_xml = minidom.parseString(result["ios01"].result) print(result_xml.toprettyxml())
実行結果
$ python get_rouging.py <?xml version="1.0" ?> <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <routing-state xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"> <routing-instance> <name>default</name> <type>default-routing-instance</type> <router-id>0.0.0.0</router-id> <routing-protocols> <routing-protocol> <type>direct</type> <name>0</name> </routing-protocol> <routing-protocol> <type>static</type> <name>0</name> </routing-protocol> </routing-protocols> <ribs> <rib> <name>ipv4-default</name> <address-family>ipv4</address-family> <default-rib>false</default-rib> <routes> <route> <destination-prefix>0.0.0.0/0</destination-prefix> <route-preference>1</route-preference> <metric>1</metric> <next-hop> <outgoing-interface>GigabitEthernet1</outgoing-interface> <next-hop-address>10.10.20.254</next-hop-address> </next-hop> <!-- 略 --> </routing-state> </data> $
subtree
指定する場合は以下のようなかたちです。
# 抜粋 query = """ <routing-state xmlns="urn:ietf:params:xml:ns:yang:ietf-routing"> </routing-state> """ result = nr.run(task=netconf_get, path=query, filter_type="subtree")
おわりに
nornir で NETCONF 経由で情報取得するサンプルをご紹介しました。
今回はざっくりとした情報を取得しました。XML で返ってくるので、必要な情報を抽出しやすいと思います。
もちろアクセスが頻繁にならずに済むのであれば、あらかじめ path や filter で絞っても良いと思います。