1. 程式人生 > 其它 >netmiko+textfsm自動統計交換機埠模組,型號數量與閒置模組

netmiko+textfsm自動統計交換機埠模組,型號數量與閒置模組

統計和查詢交換機模組是件很費時費力的事情,特別是需要掌握庫存數量時,成百上千塊模組一塊一塊統計沒有兩天的時間是不行的,且統計出的資料需要一定的格式化才能便捷的錄入資料庫

為此可以用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} -> Record
interfaces.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}
  ^$$ -> Record
ModuleInfo.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"
  ]
}