统计和查找交换机模块是件很费时费力的事情,特别是需要掌握库存数量时,成百上千块模块一块一块统计没有两天的时间是不行的,且统计出的数据需要一定的格式化才能便捷的录入数据库
(资料图片)
为此可以用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 Counterfrom netmiko import ConnectHandlerimport getpass,json,sysdef 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,ModuleStatusif __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("") print("options:") print(" host: ") print(" username: ") print(" port: ") print(" verbose: ") 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 verboseor# ./cent.py 10.0.0.1 admin
以上脚本打包后运行也需要运行机器上安装ntc_templates适配性不是很好,我们可以改动下,手动加载textfsm文件,如下
#!/usr/bin/env python#-*-coding:utf-8-*-from collections import Counterfrom netmiko import ConnectHandlerimport getpass,json,sys,textfsm,osdef 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,ModuleStatusif __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("") print("options:") print(" host: ") print(" username: ") print(" verbose: ") 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" ]}