netmiko+textfsm自動統計交換機埠模組,型號數量與閒置模組
阿新 • • 發佈:2022-12-09
統計和查詢交換機模組是件很費時費力的事情,特別是需要掌握庫存數量時,成百上千塊模組一塊一塊統計沒有兩天的時間是不行的,且統計出的資料需要一定的格式化才能便捷的錄入資料庫
為此可以用netmiko模組自動執行命令,返回結果用textfsm來解析格式話,基於這兩個模組以盛科交換機為物件做出了以下指令碼
指令碼執行環境
python 3.7 以上
netmiko 4.1.2
盛科交換機
第一步安裝netmiko,4.1.2版本會自動安裝textfsm,ntc_templates
ntc_templates路徑 /usr/local/lib/python3.8/dist-packages/ntc_templates 後面會用到
指令碼如下
#!/usr/bin/env python #-*-coding:utf-8-*- from collections import Counter from netmiko import ConnectHandler import getpass,json,sys def Module(host,username,port=22,verbose=False): passwd = getpass.getpass() ModuleCount = [] ModuleStatus = {'free':[],'line':[]} portstatus = {} dev= {'device_type': 'centec_os', 'host': host, 'username': username, 'password': passwd, 'port': 22} with ConnectHandler(**dev) as conn: PortTran = conn.send_command('show transceiver detail',use_textfsm=True) ret = json.dumps(PortTran,indent=2) PortStatus= conn.send_command('show interface status',use_textfsm=True) for x in PortStatus: portstatus[x['port']]=x['status'] if verbose : print(ret) for port in PortTran: flag = True if portstatus[port['port']] == 'up' else False info = ' '.join([port['moduletype'],port['wavelength'],port['linklength']]) ModuleCount.append(info) db = port['db'] if flag or(db and db!='-40.00'): ModuleStatus['line'].append(port['port']+' '+port['moduletype']) else: ModuleStatus['free'].append(port['port']+' '+port['moduletype']) ModuleCount = json.dumps(Counter(ModuleCount),indent=2) ModuleStatus = json.dumps(ModuleStatus,indent=2) return ModuleCount,ModuleStatus if __name__ == '__main__': try: host,username = sys.argv[1],sys.argv[2] try: verbose = sys.argv[3] verbose = True if verbose =='verbose' else False except: verbose = False except: print('usage:') print(' <host> <username> <port> <verbose>') print('options:') print(' host: <device_ip>') print(' username: <ssh user>') print(' port: <default 22>') print(' verbose: <default False>') print('examples:') print(' ./centec 10.0.0.1 dark verbose') try: ModuleCount,ModuleStatus=Module(host,username,verbose=verbose) print('------------------模組數量統計-----------------') print(ModuleCount) print('------------------模組狀態統計-----------------') print(ModuleStatus) except Exception as e: print(e)
其中兩個自定義textfsm檔案如下,需要放進ntc_templates目錄
Value port (eth\S+) Value status (\S+) Start ^${port}\s+${status} -> Recordinterfaces.textfsm
Value port (\S+) Value moduletype (\S+\s?\S+) Value sn (\S+) Value wavelength (\S+\s?\S+) Value linklength (\S+\s?\S+) Value db (\S+) Start ^Port ${port} transceiver info: ^Transceiver Type: ${moduletype} ^\s+Transceiver S/N :\s${sn} ^Transceiver Output Wavelength: ${wavelength} ^ Link Length.*:\s+${linklength} ^eth\S+\s+${db} ^$$ -> RecordModuleInfo.textfsm
指令碼使用方法
# ./cent.py 10.0.0.1 admin verbose or # ./cent.py 10.0.0.1 admin
以上指令碼打包後執行也需要執行機器上安裝ntc_templates適配性不是很好,我們可以改動下,手動載入textfsm檔案,如下
#!/usr/bin/env python #-*-coding:utf-8-*- from collections import Counter from netmiko import ConnectHandler import getpass,json,sys,textfsm,os def Module(host,username,verbose=False,port=22): BasePath = os.path.dirname(sys.argv[0]) InterFaceFsm=BasePath+'/interfaces.textfsm' TranFsm=BasePath+'/ModuleInfo.textfsm' passwd = getpass.getpass() ModuleCount = [] ModuleStatus = {'free':[],'line':[]} portstatus = {} dev = {'device_type': 'centec_os', 'host': host, 'username': username, 'password': passwd, 'port': 22} with ConnectHandler(**dev) as conn: PortTran = conn.send_command('show transceiver detail') PortStatus = conn.send_command('show interface status') with open(InterFaceFsm) as tem: fsm = textfsm.TextFSM(template=tem) PortStatus = fsm.ParseTextToDicts(PortStatus) with open(TranFsm) as tem: fsm = textfsm.TextFSM(template=tem) PortTran = fsm.ParseTextToDicts(PortTran) for x in PortStatus: portstatus[x['port']]=x['status'] if verbose : print(json.dumps(PortTran,indent=2)) for port in PortTran: flag = True if portstatus[port['port']] == 'up' else False info = ' '.join([port['moduletype'],port['wavelength'],port['linklength']]) ModuleCount.append(info) db = port['db'] if flag or(db and db!='-40.00'): ModuleStatus['line'].append(port['port']+' '+port['moduletype']) else: ModuleStatus['free'].append(port['port']+' '+port['moduletype']) ModuleCount = json.dumps(Counter(ModuleCount),indent=2) ModuleStatus = json.dumps(ModuleStatus,indent=2) return ModuleCount,ModuleStatus if __name__ == '__main__': try: host,username = sys.argv[1],sys.argv[2] try: verbose = sys.argv[3] verbose = True if verbose =='verbose' else False print(verbose) except: verbose = False try: ModuleCount,ModuleStatus=Module(host,username,verbose=verbose) print('------------------模組數量統計-----------------') print(ModuleCount) print('------------------模組狀態統計-----------------') print(ModuleStatus) except Exception as e: print(e) except: print('usage:') print(' <host> <username> <verbose>') print('options:') print(' host: <device_ip>') print(' username: <ssh user>') print(' verbose: <default False>') print('examples:') print(' ./centec 10.0.0.1 dark verbose')
執行效果,sn資訊已遮擋
[ { "port": "eth-0-1", "moduletype": "1000BASE-LX", "sn": "XXXXXX", "wavelength": "1310 nm", "linklength": "10 km", "db": "-10.57" }, { "port": "eth-0-2", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-3", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-7", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-8", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-9", "moduletype": "1000BASE-LX", "sn": "XXXXXX", "wavelength": "1310 nm", "linklength": "10 km", "db": "-40.00" }, { "port": "eth-0-10", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-18", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-31", "moduletype": "1000BASE-LX", "sn": "XXXXXX", "wavelength": "1310 nm", "linklength": "20 km", "db": "-5.13" }, { "port": "eth-0-35", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" }, { "port": "eth-0-47", "moduletype": "1000BASE-T_SFP", "sn": "XXXXXX", "wavelength": "N/A", "linklength": "100 m", "db": "" } ] ------------------模組數量統計----------------- { "1000BASE-LX 1310 nm 10 km": 2, "1000BASE-T_SFP N/A 100 m": 8, "1000BASE-LX 1310 nm 20 km": 1 } ------------------模組狀態統計----------------- { "free": [ "eth-0-9 1000BASE-LX", "eth-0-18 1000BASE-T_SFP", "eth-0-47 1000BASE-T_SFP" ], "line": [ "eth-0-1 1000BASE-LX", "eth-0-2 1000BASE-T_SFP", "eth-0-3 1000BASE-T_SFP", "eth-0-7 1000BASE-T_SFP", "eth-0-8 1000BASE-T_SFP", "eth-0-10 1000BASE-T_SFP", "eth-0-31 1000BASE-LX", "eth-0-35 1000BASE-T_SFP" ] }