python textfsm(part3) - ラッパー関数で整理
textfsmの整理
ciscoのconfigやlogといった解析対象は雑多なコマンド出力が一緒にまとめられたファイルを扱うことが多いため、以下のtextfsm_wrapper.pyを書いてみた。
- concat_target() glob形式で対象ログを指定し、コマンド開始・終了を判定する正規表現を与えると、解析用のtextデータを返す関数
- parse() textfsmの定義ファイル(テンプレート)読み込み・解析およびcsv出力を行う関数
textfsm_wrapper.py
#!/usr/bin/env python3 import glob import re import textfsm import csv def concat_target(target_file, target_start, target_end,): target_start = re.compile(target_start) target_end = re.compile(target_end) target_text = '' for fname in glob.glob(target_file): in_target = False with open(fname, 'r') as f: for line in f: if in_target == False: if target_start.search(line): target_text += line in_target = True else: target_text += line if target_end.search(line): break return target_text def parse(template_file, output_file, target_text): with open(template_file, 'r') as f: table = textfsm.TextFSM(f) with open(output_file, 'w', newline = '') as f: writer = csv.writer(f, delimiter = ',', quoting = csv.QUOTE_ALL) writer.writerow(table.header) writer.writerows(table.ParseText(target_text)) return
利用例
sample.py
#!/usr/bin/env python3 from textfsm_wrapper import concat_target, parse # show running-config sample for IOS and NX-OS target = concat_target( target_file = r"./log/*.*", target_start = r"sh(?:ow?)? (?:run|conf|start)", target_end = r"^end$", ) parse( target_text = target, template_file = r"./template_interface.txt", output_file = r"./result_interface.csv", ) # show inventory sample for IOS and NX-OS target = concat_target( target_file = r"./log/*.*", target_start = r"sh(?:ow?)? inv", target_end = r"^[\w\-\.]+[#>]|^-{10,} show ", ) parse( target_text = target, template_file = r"./template_inventory.txt", output_file = r"./result_inventory.csv", ) # show interface transceiver sample for NX-OS(Ethernet) target = concat_target( target_file = r"./log/*.*", target_start = r"sh(?:ow?)? int(?:.*) trans", target_end = r"^[\w\-\.]+[#>]|^-{10,} show ", ) parse( target_text = target, template_file = r"./template_transceiver.txt", output_file = r"./result_transceiver.csv", )
template_interface.txt
多分、これでios、nx-osとも対応出来るはず・・・
# parse interface settings from configuration.
Value Filldown hostname (\S+)
Value Required interface (\S+)
Value status ((?:no )?shutdown)
Value description (.*)
Value channel_group (\d+)
Value speed (\w+)
Value duplex (\w+)
Value mdix_auto (no mdix auto)
Value untagged_vlan (\d+)
Value List tagged_vlan ([\d\,\-]+)
Value primary_ip ((?:\d{1,3}\.){3}\d{1,3} (?:\d{1,3}\.){3}\d{1,3}|(?:\d{1,3}\.){3}\d{1,3}/\d{1,2})
Value secondary_ip ((?:\d{1,3}\.){3}\d{1,3} (?:\d{1,3}\.){3}\d{1,3}|(?:\d{1,3}\.){3}\d{1,3}/\d{1,2})
Value standby_group (\d+)
Value standby_ip ((?:\d{1,3}\.){3}\d{1,3})
Value standby_priority (\d+)
Value List standby_option (preempt.*|track.*|auth.*|timers.*)
Start
^hostname ${hostname}
^interface ${interface}
^ +${status}
^ +description ${description}
^ +channel-group ${channel_group}
^ +speed ${speed}
^ +duplex ${duplex}
^ +${mdix_auto}
^ +switchport access vlan ${untagged_vlan}
^ +switchport trunk allowed vlan (?:add )?${tagged_vlan}
^ +encapsulation dot1Q ${tagged_vlan}
^ +ip address ${primary_ip}(?! secondary)
^ +ip address ${secondary_ip} secondary
^ +standby ${standby_group} ip ${standby_ip}
^ +standby \d+ priority ${standby_priority}
^ +standby \d+ ${standby_option}
^ +hsrp ${standby_group}
^ +ip ${standby_ip}
^ +priority ${standby_priority}
^ +${standby_option}
^!?$$|\w -> Recordtemplate_inventory.txt
# parse show inventory outputs
Value Filldown hostname (\S+)
Value NAME ([^"]+)
Value DESCR ([^"]+)
Value PID (\S*)
Value VID (\S*)
Value Required SN (\S+)
Start
^${hostname}[>#]\s*sh(?:ow?)? inv
^NAME: "${NAME}" *, +DESCR: "${DESCR}"
^PID: ${PID} *, +VID: ${VID} *, +SN: ${SN} -> Recordtemplate_transceiver.txt
# parse show interface transceiver outputs
Value Filldown hostname (\S+)
Value interface (Ethernet.*)
Value type (\S*)
Value name (\S*)
Value part (\S*)
Value revision (\S*)
Value Required serial (\S+)
Start
^${hostname}[>#]\s*sh(?:ow?)? int(?:.*) tran
^${interface}
^ +type is ${type}
^ +name is ${name}
^ +part number is ${part}
^ +revision is ${revision}
^ +serial number is ${serial}\s*$$ -> Record