はじめに
Ciscoが公開しているPythonベースのテストフレームワーク/フィーチャーライブラリー「pyATS/Genie」の内、Genie ParserとOpsを使ってみた結果をメモしておきます。
1-1. Genie Parserとは
NW機器のshowコマンド結果を構文解析し、テキストデータを「xの値はy」のようにプログラムが扱いやすい形式に変換します。2019年7月時点で1000を超えるパーサーが存在し、Cisco IOS、IOS-XE、IOS-XR、NX-OS、ASA、Junosの各種showコマンドに対応しています。
参考URL:
Parser一覧
GitHub - genieparser
1-2. Pythonコード例
Python環境のセットアップは前回の記事を参照願います。(Testbedも用意する必要あり。)
以下はCisco CSR1000Vのshow interfaces GigabitEthernet1
をパースする例です。
from genie.conf import Genie
from pprint import pprint
testbed = Genie.init('testbed_devnet3.yaml') # Testbedを指定
device = testbed.devices['csr1000v-1'] # ホスト名を指定
device.connect()
output = device.parse('show interfaces GigabitEthernet1')
pprint(output)
1-3. 実行結果
$ python genie8-1.py
# 途中の実行ログは省略
{'GigabitEthernet1': {'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': 3984819,
'in_overrun': 0,
'in_pkts': 41999,
'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': 0,
'out_late_collision': 0,
'out_lost_carrier': 0,
'out_mac_pause_frames': 0,
'out_no_carrier': 0,
'out_octets': 414844,
'out_pkts': 2545,
'out_underruns': 0,
'out_unknown_protocl_drops': 168,
'rate': {'in_rate': 3000,
'in_rate_pkts': 5,
'load_interval': 300,
'out_rate': 0,
'out_rate_pkts': 0}},
'delay': 10,
'description': "MANAGEMENT INTERFACE - DON'T TOUCH ME",
'duplex_mode': 'full',
'enabled': True,
'encapsulations': {'encapsulation': 'arpa'},
'flow_control': {'receive': False, 'send': False},
'ipv4': {'10.10.20.48/24': {'ip': '10.10.20.48',
'prefix_length': '24'}},
'keepalive': 10,
'last_input': '00:00:00',
'last_output': '00:00:00',
'line_protocol': 'up',
'link_type': 'auto',
'mac_address': '0050.56ac.6cb1',
'media_type': 'Virtual',
'mtu': 1500,
'oper_status': 'up',
'output_hang': 'never',
'phys_address': '0050.56ac.6cb1',
'port_channel': {'port_channel_member': False},
'port_speed': '1000',
'queues': {'input_queue_drops': 0,
'input_queue_flushes': 0,
'input_queue_max': 375,
'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': 'CSR vNIC'}}
2-1. Genie Opsとは
デバイスの設定情報やオペレーション状態をフィーチャー単位(1つのshowコマンドではなく、例えばinterfaceに関連する複数のshowコマンド)で取得するPythonオブジェクトです。
以前ご紹介したGenie Confと同様、OSによるコマンドの違いを意識することなく、情報の取得が可能です。例えば、IOS-XEでinterface関連の情報を取得する場合、Genie Opsのlearnメソッドにて、以下のCLIコマンドが実行されます。
- show interfaces
- show vrf
- show interfaces accounting
- show ip interface
- show ipv6 interface
他にも、routing、bgp、ospf、mcast、acl、vlan、stp、platform等のフィーチャーをサポートしています(詳細は下記GitHubを参照)。
出力結果(info)は、Parserでパースしたものが出力されます。
参考URL:
Ops User Guide
DevNet Workshop (DEVWKS-2601)- pyATS Genie Ops and Parsers
GitHub - Genie Ops
2-2. Pythonコード例①(interface)
interface関連のフィーチャーを取得する例です。learnメソッド内の引数で、interface
を指定することで、関連情報を取得できます。
from genie.conf import Genie
from pprint import pprint
testbed = Genie.init('testbed_devnet3.yaml')
device = testbed.devices['csr1000v-1']
device.connect()
interface = device.learn('interface')
pprint(interface.info)
2-3. 実行結果①(interface)
Genie Parserの結果と比較すると、accounting関連の情報が追加されています。また、interfaceのステータス情報は、エラーカウント内訳などが表示されずコンパクトになっています。
$ python genie8-2.py
# 途中の実行ログは省略
{'': {'accounting': {'arp': {'chars_in': 480,
'chars_out': 540,
'pkts_in': 8,
'pkts_out': 9},
'ip': {'chars_in': 4689480,
'chars_out': 566379,
'pkts_in': 50575,
'pkts_out': 3530},
'other': {'chars_in': 32820,
'chars_out': 634,
'pkts_in': 428,
'pkts_out': 10}},
'switchport_enable': False},
'GigabitEthernet1': {'auto_negotiate': True,
'bandwidth': 1000000,
'counters': {'in_broadcast_pkts': 0,
'in_crc_errors': 0,
'in_errors': 0,
'in_mac_pause_frames': 0,
'in_multicast_pkts': 0,
'in_octets': 4873797,
'in_pkts': 51634,
'last_clear': 'never',
'out_errors': 0,
'out_mac_pause_frames': 0,
'out_octets': 561534,
'out_pkts': 3504,
'rate': {'in_rate': 3000,
'in_rate_pkts': 4,
'load_interval': 300,
'out_rate': 0,
'out_rate_pkts': 0}},
'delay': 10,
'description': "MANAGEMENT INTERFACE - DON'T TOUCH ME",
'duplex_mode': 'full',
'enabled': True,
'encapsulation': {'encapsulation': 'arpa'},
'flow_control': {'receive': False, 'send': False},
'ipv4': {'10.10.20.48/24': {'ip': '10.10.20.48',
'prefix_length': '24',
'secondary': False}},
'mac_address': '0050.56ac.6cb1',
'mtu': 1500,
'oper_status': 'up',
'phys_address': '0050.56ac.6cb1',
'port_channel': {'port_channel_member': False},
'port_speed': '1000',
'switchport_enable': False,
'type': 'CSR vNIC'},
# GigabitEthernet2,3の結果は省略
}
#2-4. Pythonコード例②(interface一部表示)
出力結果は辞書形式のため、特定のキーの値のみを表示できます。例えば、コード例①を以下の通り書き換えることで、GigabitEthernet1のオペレーション状態(up/down)のみ表示できます。
pprint(interface.info['GigabitEthernet1']['oper_status'])
#2-5. 実行結果②(interface一部表示)
'up'
2-6. Pythonコード例③(interface一部取得)
コード例②は情報を一式取得した後、表示の段階で絞っていましたが、取得段階で対象を絞ることも可能です。例えば、各IFのBandwidthだけ取得できれば良い場合、learnメソッドの引数に、以下の通りattributes
を指定します。
interface = device.learn('interface', attributes=['info[(.*)][bandwidth]'])
2-7. 実行結果③(interface一部取得)
実行中のログは省略していますが、取得コマンドはshow interfaces
とshow vrf
の2つに絞られていました。実行時間を短くしたい場合は、こちらの方が良いかも知れません。
{'GigabitEthernet1': {'bandwidth': 1000000, 'switchport_enable': False},
'GigabitEthernet2': {'bandwidth': 1000000, 'switchport_enable': False},
'GigabitEthernet3': {'bandwidth': 1000000, 'switchport_enable': False}}
2-8. Pythonコード例④(routing)
learnメソッド内の引数を、routing
を変更することでrouting関連情報を取得できます。
from genie.conf import Genie
from pprint import pprint
testbed = Genie.init('testbed_devnet3.yaml')
device = testbed.devices['csr1000v-1']
device.connect()
routing = device.learn('routing')
pprint(routing.info)
2-9. 実行結果④(routing)
$ python genie8-4.py
# 途中の実行ログは省略
{'vrf': {'default': {'address_family': {'ipv4': {'routes': {'0.0.0.0/0': {'active': True,
'metric': 0,
'next_hop': {'next_hop_list': {1: {'index': 1,
'next_hop': '10.10.20.254',
'outgoing_interface': 'GigabitEthernet1'}}},
'route': '0.0.0.0/0',
'route_preference': 1,
'source_protocol': 'static',
'source_protocol_codes': 'S*'},
'10.10.20.0/24': {'active': True,
'next_hop': {'outgoing_interface': {'GigabitEthernet1': {'outgoing_interface': 'GigabitEthernet1'}}},
'route': '10.10.20.0/24',
'source_protocol': 'connected',
'source_protocol_codes': 'C'},
'10.10.20.48/32': {'active': True,
'next_hop': {'outgoing_interface': {'GigabitEthernet1': {'outgoing_interface': 'GigabitEthernet1'}}},
'route': '10.10.20.48/32',
'source_protocol': 'local',
'source_protocol_codes': 'L'}}}}}}}
所感
他のパーサーとして、textFSMとNTC-templateの組み合わせもあります。以下記事にも記載した通り、それぞれ良い所があるので、今後使い分けて行きたいです。