Edited at

Genie Parser/OpsによるCisco機器のログ取得・構文解析


はじめに

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をパースする例です。


genie8-1.py

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を指定することで、関連情報を取得できます。


genie8-2.py

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 interfacesshow 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関連情報を取得できます。


genie8-4.py

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の組み合わせもあります。以下記事にも記載した通り、それぞれ良い所があるので、今後使い分けて行きたいです。

Ansibleのparse_genieフィルターと通信確認表を使ったNWテスト