统计和查找交换机模块是件很费时费力的事情,特别是需要掌握库存数量时,成百上千块模块一块一块统计没有两天的时间是不行的,且统计出的数据需要一定的格式化才能便捷的录入数据库
为此可以用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" ] }
标签:verbose,netmiko,db,模块,print,eth,textfsm,1000BASE,port From: https://www.cnblogs.com/darkchen/p/16969427.html