やること
Cisco機器の型番/シリアル番号を整理することが多いので、show inventoryの結果をcsvに出力するコードを書きました。
使うのはPythonモジュールのTextFSMと、そのテンプレート集であるntc-templatesです。
#環境
Python 3.7.3
Anaconda 4.8.1
Windows10
#フォルダ構成
入力フォルダ、出力フォルダ、templateフォルダを.pyと同ディレクトリに用意します。
.
│ get_inventory.py
│
├─input
│ catalyst.cfg
│ nexus.cfg
│
├─output
│
└─template
cisco_ios_show_inventory.template
cisco_nxos_show_inventory.template
cisco_nxos_show_inventory_r2.template
#入力ファイル
WS-C2960X-24TS-L の『show inventory raw』と、N3K-C3172PQ-10GE の『show inventory all』の出力結果を入力用に用意しました。
Catalystのコマンド結果(入力用)
catalyst#sh inv raw
NAME: "C29xx Stacking", DESCR: "Catalyst C29xx Switch Stack"
PID: , VID: , SN:
NAME: "1", DESCR: "WS-C2960X-24TS-L"
PID: WS-C2960X-24TS-L , VID: V05 , SN: FCW2115BXXX
NAME: "Switch 1 - Fan Container", DESCR: "Fan Container"
PID: , VID: , SN:
NAME: "Switch 1 - Power Supply Container", DESCR: "Power Supply Container"
PID: , VID: , SN:
NAME: "Switch 1 - RPS Container", DESCR: "RPS Container"
PID: , VID: , SN:
NAME: "Switch 1 - WS-C2960X-24TS-L - Power Supply 0", DESCR: "Switch 1 - WS-C2960X-24TS-L - Power Supply 0"
PID: , VID: , SN: LIT21123XXX
NAME: "Switch 1 - WS-C2960X-24TS-L - Fan 0", DESCR: "Switch 1 - WS-C2960X-24TS-L - Fan 0"
PID: , VID: , SN:
NAME: "Switch 1 - WS-C2960X-24TS-L - Sensor 0", DESCR: "Switch 1 - WS-C2960X-24TS-L - Sensor 0"
PID: , VID: , SN:
NAME: "Switch 1 - WS-C2960X-24TS-L - Fixed Module 0", DESCR: "Switch 1 - WS-C2960X-24TS-L - Fixed Module 0"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/25 Container", DESCR: "GigabitEthernet Container"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/26 Container", DESCR: "GigabitEthernet Container"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/27 Container", DESCR: "GigabitEthernet Container"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/27", DESCR: "1000BaseSX SFP"
PID: GLC-SX-MMD , VID: V01 , SN: FNS17070XXX
NAME: "Gi1/0/27 Module Temperature Sensor", DESCR: "GigabitEthernet1/0/27 Module Temperature Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/27 Supply Voltage Sensor", DESCR: "GigabitEthernet1/0/27 Supply Voltage Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/27 Bias Current Sensor", DESCR: "GigabitEthernet1/0/27 Bias Current Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/27 Transmit Power Sensor", DESCR: "GigabitEthernet1/0/27 Transmit Power Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/27 Receive Power Sensor", DESCR: "GigabitEthernet1/0/27 Receive Power Sensor"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/28 Container", DESCR: "GigabitEthernet Container"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/28", DESCR: "1000BaseSX SFP"
PID: GLC-SX-MMD , VID: V01 , SN: FNS17070XXX
NAME: "Gi1/0/28 Module Temperature Sensor", DESCR: "GigabitEthernet1/0/28 Module Temperature Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/28 Supply Voltage Sensor", DESCR: "GigabitEthernet1/0/28 Supply Voltage Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/28 Bias Current Sensor", DESCR: "GigabitEthernet1/0/28 Bias Current Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/28 Transmit Power Sensor", DESCR: "GigabitEthernet1/0/28 Transmit Power Sensor"
PID: , VID: , SN:
NAME: "Gi1/0/28 Receive Power Sensor", DESCR: "GigabitEthernet1/0/28 Receive Power Sensor"
PID: , VID: , SN:
NAME: "StackPort1", DESCR: "StackPort1"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/1", DESCR: "GigabitEthernet1/0/1"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/2", DESCR: "GigabitEthernet1/0/2"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/3", DESCR: "GigabitEthernet1/0/3"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/4", DESCR: "GigabitEthernet1/0/4"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/5", DESCR: "GigabitEthernet1/0/5"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/6", DESCR: "GigabitEthernet1/0/6"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/7", DESCR: "GigabitEthernet1/0/7"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/8", DESCR: "GigabitEthernet1/0/8"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/9", DESCR: "GigabitEthernet1/0/9"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/10", DESCR: "GigabitEthernet1/0/10"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/11", DESCR: "GigabitEthernet1/0/11"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/12", DESCR: "GigabitEthernet1/0/12"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/13", DESCR: "GigabitEthernet1/0/13"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/14", DESCR: "GigabitEthernet1/0/14"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/15", DESCR: "GigabitEthernet1/0/15"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/16", DESCR: "GigabitEthernet1/0/16"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/17", DESCR: "GigabitEthernet1/0/17"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/18", DESCR: "GigabitEthernet1/0/18"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/19", DESCR: "GigabitEthernet1/0/19"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/20", DESCR: "GigabitEthernet1/0/20"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/21", DESCR: "GigabitEthernet1/0/21"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/22", DESCR: "GigabitEthernet1/0/22"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/23", DESCR: "GigabitEthernet1/0/23"
PID: , VID: , SN:
NAME: "GigabitEthernet1/0/24", DESCR: "GigabitEthernet1/0/24"
PID: , VID: , SN:
catalyst#
Nexusのコマンド結果(入力用)
nexus# sh inv all
NAME: "Chassis", DESCR: "Nexus 3172 Chassis"
PID: N3K-C3172PQ-10GE , VID: V02 , SN: FOC2325RXXX
NAME: "Slot 1", DESCR: "48x10GE + 6x40G Supervisor"
PID: N3K-C3172PQ-10GE , VID: V02 , SN: FOC23248XXX
NAME: "Power Supply 1", DESCR: "Nexus 3172 Chassis Power Supply"
PID: N2200-PAC-400W-B , VID: V03 , SN: LIT23192XXX
NAME: "Power Supply 2", DESCR: "Nexus 3172 Chassis Power Supply"
PID: N2200-PAC-400W-B , VID: V03 , SN: LIT23193XXX
NAME: "Fan 1", DESCR: "Nexus 3172 Chassis Fan Module"
PID: NXA-FAN-30CFM-B , VID: V00 , SN: N/A
NAME: "Fan 2", DESCR: "Nexus 3172 Chassis Fan Module"
PID: NXA-FAN-30CFM-B , VID: V00 , SN: N/A
NAME: "Fan 3", DESCR: "Nexus 3172 Chassis Fan Module"
PID: NXA-FAN-30CFM-B , VID: V00 , SN: N/A
NAME: "Fan 4", DESCR: "Nexus 3172 Chassis Fan Module"
PID: NXA-FAN-30CFM-B , VID: V00 , SN: N/A
NAME: Ethernet1/47, DESCR: CISCO-AVAGO
PID: 10Gbase-SR , VID: SFBR-709SMZ-CS1 , SN: AVD23059XXX
NAME: Ethernet1/48, DESCR: CISCO-OPLINK
PID: 10Gbase-SR , VID: TPP4XGDS0CCISE2G, SN: OPM23050XXX
nexus#
#Templatesファイル
Catalyst、Nexusともに『show inventory』のTemplatesを使用。1
Catalystはそのままで問題なさそうでしたが、Nexusは少し編集しました。
編集後のTemplatesは末尾『_r2』としています。
cisco_ios_show_inventory.template
Value NAME (.*)
Value DESCR (.*)
Value PID (([\S+]+|.*))
Value VID (.*)
Value SN ([\w+\d+]+)
Start
^NAME:\s+"${NAME}",\s+DESCR:\s+"${DESCR}"
^PID:\s+${PID}.*,.*VID:\s+${VID},.*SN:\s+${SN} -> Record
^PID:\s+,.*VID:\s+${VID},.*SN: -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID},.*SN: -> Record
^PID:\s+,.*VID:\s+${VID},.*SN:\s+${SN} -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID}.*
^PID:\s+,.*VID:\s+${VID}.*
^.*SN:\s+${SN} -> Record
^.*SN: -> Record
cisco_nxos_show_inventory_r2.template
Value NAME (.*)
Value DESCR (.*)
Value PID ([^,]\S+)
Value VID ((V\d+)|[^,]\S+) #変更:Vから始まらない場合を考慮 ex.SFBR-709SMZ-CS1
Value SN ([\d+\w+/]+)
Start
^NAME:\s+"${NAME}",\s+DESCR:\s+"${DESCR}"
^NAME:\s+${NAME},\s+DESCR:\s+${DESCR} # 追加:""で囲まれない場合を考慮 ex.Ethernet1/47
^PID:\s+${PID}\s+,.*VID:\s+${VID}\s*,.*SN:\s+${SN} -> Record # 追加:VID直後に,が入る場合を考慮 ex.TPP4XGDS0CCISE2G,
^PID:\s+${PID}.*,.*VID:\s+${VID}.*SN:\s+${SN} -> Record
^PID:\s+,.*VID:\s+${VID}.*SN: -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID}.*SN: -> Record
^PID:\s+,.*VID:\s+${VID}.*SN:\s+${SN} -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID}.*
^PID:\s+,.*VID:\s+${VID}.*
^.*SN:\s+${SN} -> Record
^.*SN: -> Record
Templateを使用する場合は#コメントを削除してください。(Templatesのコメントアウト方法が分かりませんでした。)
cisco_nxos_show_inventory.template(参考)
Value NAME (.*)
Value DESCR (.*)
Value PID ([^,]\S+)
Value VID (V\d+)
Value SN ([\d+\w+/]+)
Start
^NAME:\s+"${NAME}",\s+DESCR:\s+"${DESCR}"
^PID:\s+${PID}.*,.*VID:\s+${VID}.*SN:\s+${SN} -> Record
^PID:\s+,.*VID:\s+${VID}.*SN: -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID}.*SN: -> Record
^PID:\s+,.*VID:\s+${VID}.*SN:\s+${SN} -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID}.*
^PID:\s+,.*VID:\s+${VID}.*
^.*SN:\s+${SN} -> Record
^.*SN: -> Record
実装
import os
from datetime import datetime
import pandas as pd
import textfsm
import pathlib
import re
# outputフォルダ作成
def make_output_folder(out_path):
# outputフォルダ作成
date_str = datetime.now().strftime("%Y%m%d_%H-%M-%S")
output_f = os.path.join(out_path, "output_" + date_str)
os.mkdir(output_f)
return output_f
if __name__ == '__main__':
# カレントディレクトリを.pyフォルダに移動
current_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(current_path)
# inputフォルダ、ouputフォルダを指定
input_folder = os.path.join(current_path, "input")
output_folder = make_output_folder(os.path.join(current_path, "output"))
# inputフォルダを読み込む 拡張子はtxt,cfg,log
input_cfg_file_list = [str(p) for p in pathlib.Path(input_folder).glob("**/*")
if re.search(".*\.(txt|cfg|log)$", str(p))]
# merge用DataFrame
merge_result_df = pd.DataFrame()
# inputファイルを一つずつ処理
for cfg_path in input_cfg_file_list:
cfg_base_name = os.path.basename(cfg_path)
with open(cfg_path) as f:
cfg_text = f.read()
# TextFSMのテンプレートを決定する処理
tmp_cfg_list = cfg_text.split("\n")
for line in tmp_cfg_list:
# showコマンドの出力1行目までスキップ
if line in "#" or line in ">" or line == "":
continue
# showコマンドの出力からテンプレートを決定
# NX-OSのテンプレート
if re.search("Nexus ", line) is not None:
template_path = r'./template/cisco_nxos_show_inventory_r2.template'
break
# IOSのテンプレート
elif re.search("(WS-|Cisco|Catalyst)", line) is not None:
template_path = r'./template/cisco_ios_show_inventory.template'
break
# fsmで結果を解析、抽出
with open(template_path) as f:
fsm = textfsm.TextFSM(f)
output = fsm.ParseText(cfg_text)
# 解析結果をDataFrameに変換
df = pd.DataFrame(output, columns=fsm.header)
# ファイルをcsvに保存
out_name = os.path.splitext(cfg_base_name)[0] + ".csv"
df.to_csv(os.path.join(output_folder, out_name), index=False, header=fsm.header)
# 各出力結果を集積
df["HOST"] = cfg_base_name
merge_result_df = merge_result_df.append(df, sort=False)
# 集積した出力結果をcsvに保存(HOSTを1列目に移動)
cols = ['HOST'] + [col for col in df if col != 'HOST']
merge_result_df = merge_result_df[cols]
merge_result_df.to_csv(os.path.join(output_folder, "merge_output_file.csv"), index=False, header=True)
出力結果
outputフォルダにホストごとのcsvファイルとすべての結果をマージしたcsvファイルが作成されます。
マージ版のcsvファイルは以下の通りです(一部抜粋)。『show inventory』の結果に加え、1列目にファイル名が追加されています。
HOST | NAME | DESCR | PID | VID | SN |
---|---|---|---|---|---|
catalyst.cfg | C29xx Stacking | Catalyst C29xx Switch Stack | |||
catalyst.cfg | 1 | WS-C2960X-24TS-L | WS-C2960X-24TS-L | V05 | FCW2115BXXX |
catalyst.cfg | Switch 1 - Fan Container | Fan Container | |||
catalyst.cfg | Switch 1 - Power Supply Container | Power Supply Container | |||
catalyst.cfg | Switch 1 - RPS Container | RPS Container | |||
catalyst.cfg | Switch 1 - WS-C2960X-24TS-L - Power Supply 0 | Switch 1 - WS-C2960X-24TS-L - Power Supply 0 | LIT21123XXX | ||
catalyst.cfg | Switch 1 - WS-C2960X-24TS-L - Fan 0 | Switch 1 - WS-C2960X-24TS-L - Fan 0 | |||
catalyst.cfg | Switch 1 - WS-C2960X-24TS-L - Sensor 0 | Switch 1 - WS-C2960X-24TS-L - Sensor 0 | |||
catalyst.cfg | Switch 1 - WS-C2960X-24TS-L - Fixed Module 0 | Switch 1 - WS-C2960X-24TS-L - Fixed Module 0 | |||
catalyst.cfg | GigabitEthernet1/0/25 Container | GigabitEthernet Container | |||
catalyst.cfg | GigabitEthernet1/0/26 Container | GigabitEthernet Container | |||
catalyst.cfg | GigabitEthernet1/0/27 Container | GigabitEthernet Container | |||
catalyst.cfg | GigabitEthernet1/0/27 | 1000BaseSX SFP | GLC-SX-MMD | V01 | FNS17070XXX |
catalyst.cfg | GigabitEthernet1/0/28 | 1000BaseSX SFP | GLC-SX-MMD | V01 | FNS17070XXX |
nexus.cfg | Chassis | Nexus 3172 Chassis | N3K-C3172PQ-10GE | V02 | FOC2325RXXX |
nexus.cfg | Slot 1 | 48x10GE + 6x40G Supervisor | N3K-C3172PQ-10GE | V02 | FOC23248XXX |
nexus.cfg | Power Supply 1 | Nexus 3172 Chassis Power Supply | N2200-PAC-400W-B | V03 | LIT23192XXX |
nexus.cfg | Power Supply 2 | Nexus 3172 Chassis Power Supply | N2200-PAC-400W-B | V03 | LIT23193XXX |
nexus.cfg | Fan 1 | Nexus 3172 Chassis Fan Module | NXA-FAN-30CFM-B | V00 | N/A |
nexus.cfg | Fan 2 | Nexus 3172 Chassis Fan Module | NXA-FAN-30CFM-B | V00 | N/A |
nexus.cfg | Fan 3 | Nexus 3172 Chassis Fan Module | NXA-FAN-30CFM-B | V00 | N/A |
nexus.cfg | Fan 4 | Nexus 3172 Chassis Fan Module | NXA-FAN-30CFM-B | V00 | N/A |
nexus.cfg | Ethernet1/47 | CISCO-AVAGO | 10Gbase-SR | SFBR-709SMZ-CS1 | AVD23059XXX |
nexus.cfg | Ethernet1/48 | CISCO-OPLINK | 10Gbase-SR | TPP4XGDS0CCISE2G | OPM23050XXX |
参照
-
2020年5月時点では、show inventory "all"、show inventory "raw"のTemplatesは無い模様(https://github.com/networktocode/ntc-templates/tree/master/templates) ↩