簡明Python開發教程(4):網絡自動化運維的曙光

寫在前面

本打算自動登陸一臺路由器,執行查詢配置指令,然后用正則表達式分析,獲取該路由器的接口連接關系。
現在由于網絡問題,導致無法直接telnet路由器,只能通過其他方式獲取配置文件,如讀取本地文件等。
由于時間關系,本教程修改如下:
第一部分通過telnet模塊測試登陸、執行指令,登陸設備改為MME;
第二部分還是之前的配置文件分析,只是配置文件來源于本地已下載的配置文件。
同時大家也可以研究其他登陸網元等自動獲取信息的方法,如指令平臺等。


Python在自動運維方面也有很多第三方庫,可以幫助我們自動ssh/telent設備、執行指令,分析結果等。
通常情況下Python自動運維在互聯網公司應用更多,因為他們維護設備主要都是類似的linux服務器,操作統一。
而我們所面臨的不同廠家不同設備的CT設備,Python自動運維相對較少,不過現在已經是ICT融合,目前引入的NFV技術有大量IT設備,Python自動運維可以發揮更多作用。
本教程還是想通過解決一個實際問題,分享Python自動運維的簡單知識,更多的我也在學習中。

問題需求

日常我們維護著大量的設備,每個設備都有賬號密碼,賬號密碼是否過期?設備能否正常登陸?同時我們還需要執行大量指令并進行分析,判斷設備是否正常。
今天我們的任務是,給定某設備IP地址,用戶名和密碼,完成以下任務:

  • 模擬telnet/ssh設備,可以測試賬號可用性,設備連通性
  • 執行指令,返回結果,如查詢配置文件
  • 分析配置文件,比如關注拓撲信息,可以學習Python正則表達式的基本知識;

代碼實現

模擬telnet/ssh

Python有很多第三方庫,實現ssh、ftp、telnet等命令交互,如pexpectparamiko等,不過這些我都還沒時間認真研究,就用Python自帶的telnetlib實現最簡單的telnet功能,后續如果有需求再進一步學習。
模擬telnet的代碼如下:

import telnetlib
host = "x.x.x.x"    #設備IP,將來可以從一個地址池中讀取
user =b 'x'     #用戶名密碼
password =b 'x'
finsh = b"#"     #結束符號
tn = telnetlib.Telnet(host) #創建telnet連接
tn.read_until(b"login: ") #讀取到給定字符串
tn.write(user + b"\n")  #輸入用戶名
tn.read_until(b"Password: ")
tn.write(password + b"\n")
tn.read_until(finsh)

注意在網管網換成可以IP測試,可以看到,python正在模擬人工登陸,我認為:

  • telnetlib.Telnet(host) 沒有報錯,說明設備網絡通的,也開放了telnet端口;
  • tn.read_until(finsh) 執行完畢,說明賬號密碼正常,可以正常登陸

執行指令并返回結果

正常telnet設備后,我們準備執行指令,我們查詢愛立信MME attach相關指標,指令如下:
attach | tail -10
我們使用Python執行指令,代碼如下:

command =b "attach | tail -10" #待執行指令
tn.write(command + b"\n") #Python執行指令,模擬人工輸入、回車
res = tn.read_until(finsh)  #python讀取指令結果

tn.read_until(finsh) 可以理解為從執行上條指令開始,一直讀取到finsh(這里是#,不同平臺可能不一樣,如~)結束。
我們可以查看res結果如下,說明已經正確完成指令結果讀取。

image.png

分析本地配置文件

由于路由器暫時無法直接telnet,只能通過分析本地配置文件。其實對于上述MME的指令結果也可以繼續分析,只是以下內容很早已經完成,實現思路都是一樣的。

分析指令結果

配置文件可以分析很多東西,這里我們只分析路由器的接口數據,也就是配置了哪些接口?對端分別是哪些網元,接口IP是多少?
我們看下接口配置樣例。

interface GigabitEthernet2/0/8.1055
 vlan-type dot1q 1055
 description To-[HZMxx]-[MHRD|2|4|11|B|1]-1G
 ip binding vpn-instance xx_xx_Media
 ip address x.x.x.149 255.255.255.252
 statistic enable

我們可以通過正則表達式匹配這段內容,并提取相應信息。

Python正則表達式re

關于Python正則表達式的知識非常多,可以寫一本書,顯然我寫不出來。
我曾經看過一份不錯的教程Python正則表達式指南,轉自# AstralWind,可以研究下。
所謂正則表達式,就是給定一個模式字符串表達式patten,然后逐一匹配字符串,正如我們熟悉的*表示任何東西一樣。
Python正則表達式示例,我想在一句英文中匹配是否存在hello。

import re  
# 將正則表達式編譯成Pattern對象 
pattern = re.compile(r'hello')
s = pattern.search('hello world!') #調用search函數,查找
if s: #匹配成功為真
    print(s.group())
#以上是輸出    
hello

Pattern對象是一個編譯好的正則表達式,提供了很多方法使用,如match()、search()、findall()。
今天我們用findall()匹配設備接口信息,會以列表形式返回全部匹配的字串代碼如下:

In[227]: import pandas as pd 
f = open(u'XXXCE06-HWNE40E_配置備份文件保存.txt','r')
conf = f.read() 
p_int= re.compile(r"interface GigabitEthernet(.*?)\n.*?description (.*?)\n")
ints = p_int.findall(conf)
#轉換為DataFrame,以便后續輸出報錯
ints = pd.DataFrame(ints,columns = ['interface','description'])
ints['interface'] = ['GigabitEthernet'+i for i in list(ints['interface'])]
In[228]: ints.head()
Out[228]: 
               interface                             description
0  GigabitEthernet1/0/10          TO-[xxx]-[LSW01-GE0/0/13]_1G
1  GigabitEthernet1/0/23                     TO-xxx-1G-WANGGUAN
2   GigabitEthernet2/0/1  TO-[GDHIZ-xxx-HWNE40E]-GE2/0/1-1G
3   GigabitEthernet2/0/2  TO-[GDHIZ-xxx-HWNE40E]-GE2/0/2-1G
4   GigabitEthernet2/0/3         To-[HZMxx]-[MHRD|1|2|11|B|1]-1G

其中正則表達式"interface GigabitEthernet(.?)\n.?description (.*?)\n",
表示以interface GigabitEthernet開頭,先匹配任意字符,直到換行\n;第一個括號內就是接口號interface;然后再忽略一些字符. *?,找到description ,后面對應對端名稱,以換行符\n結束匹配。
這個寫法直接返回()中匹配上的內容,如端口號、desc等,但是對于沒有desc的端口則無法匹配命中。
整個配置文件findall()后可以全部匹配想要的接口號及對端信息。

更多接口信息

上面只匹配了有對端的GigabitEthernet接口信息,其實路由有很多接口類型,如vlan,還有子接口等,下面嘗試寫一個更全面的功能,能夠分析所有接口信息。

#給定配置文件conf,返回全部接口信息
def get_intferaces(conf):
    p_int = re.compile(r'#\n(interface .*?)\n#',re.S)
    ints = p_int.findall(conf)
    cols = ['interface','is_shutdown','description','ipaddress','vpn-instance','vlan']
    rows = []
    for i in ints:
        name = i.split('interface ')[1].split('\n')[0]
        if ('NULL' not in name) & ('Virtual' not in name):
            if 'description ' in i:
                desc = i.split('description ')[1].split('\n')[0]
            else:
                desc = ''
            if 'ip address ' in i:
                ipaddress = i.split('ip address ')[1].split('\n')[0]
            else:
                ipaddress = ''     
            if 'ip binding vpn-instance ' in i:
                vpn = i.split('ip binding vpn-instance ')[1].split('\n')[0]
            else:
                vpn = ''  
            if 'port default vlan ' in i:
                vlan = i.split('port default vlan ')[1].split('\n')[0]
            else:
                vlan = ''
            if 'undo shutdown' in i:
                is_shutdow = 'undo shutdown'
            elif 'shutdown' in i:
                is_shutdow = 'shutdown'
            else:
                is_shutdow = '' #為空表示沒有這個字段    
            row = [name,is_shutdow,desc,ipaddress,vpn,vlan]
            rows.append(row)
    interfaces = pd.DataFrame(rows,columns = cols)
    return interfaces

由于接口類型很多,不好用統一的正則表達式匹配,大家有興趣可以用正則寫,這里傻瓜式的if判斷。


通過get_intferaces(conf)可以獲取到全部接口信息。然后可以對這些接口信息進行處理,比如只保留在用端口,IP地址用子網表示等。

#只保留在用端口
interfaces = interfaces[~interfaces['is_shutdown'].isin(['shutdown'])]

由于對端描述不是特別規范,提取真實網元名稱需要一些判斷邏輯,不麻煩,同時如果知道全部IP地址信息,可以用子網進行匹配,更準確。


最終代碼

整理上面代碼,匯總如下,大家可以新建automain_demo.py,復制以下代碼,測試是否正常。(需要內網環境,能夠連上網元,目前也只能連上部分網元)

import telnetlib
import re
import pandas as pd

#在指定網元上執行指令,并返回指令結果
def doComd(host,user,password,finsh,commands):
    tn = telnetlib.Telnet(host)
    tn.read_until(b"login: ")
    tn.write(user +b "\n")
    tn.read_until(b"Password: ")
    tn.write(password + b"\n")    
    tn.read_until(finsh)   
    print(host+"登陸成功!")
    res = []
    #可以執行多條指令
    for command in commands:
        tn.write(command +b "\n")    
        res.append(tn.read_until(finsh))
    tn.close()
    return res
#給定配置文件conf,返回全部接口信息
def get_intferaces(conf):
    p_int = re.compile(r'#\n(interface .*?)\n#',re.S)
    ints = p_int.findall(conf)
    cols = ['interface','is_shutdown','description','ipaddress','vpn-instance','vlan']
    rows = []
    for i in ints:
        name = i.split('interface ')[1].split('\n')[0]
        if ('NULL' not in name) & ('Virtual' not in name):
            if 'description ' in i:
                desc = i.split('description ')[1].split('\n')[0]
            else:
                desc = ''
            if 'ip address ' in i:
                ipaddress = i.split('ip address ')[1].split('\n')[0]
            else:
                ipaddress = ''     
            if 'ip binding vpn-instance ' in i:
                vpn = i.split('ip binding vpn-instance ')[1].split('\n')[0]
            else:
                vpn = ''  
            if 'port default vlan ' in i:
                vlan = i.split('port default vlan ')[1].split('\n')[0]
            else:
                vlan = ''
            if 'undo shutdown' in i:
                is_shutdow = 'undo shutdown'
            elif 'shutdown' in i:
                is_shutdow = 'shutdown'
            else:
                is_shutdow = '' #為空表示沒有這個字段    
            row = [name,is_shutdow,desc,ipaddress,vpn,vlan]
            rows.append(row)
    interfaces = pd.DataFrame(rows,columns = cols)
    interfaces = interfaces[~interfaces['is_shutdown'].isin(['shutdown'])]
    return interfaces
if __name__ == "__main__":  
    host = "x.x.x.x"    #設備IP,將來可以從一個地址池中讀取
    user = b'x'     #用戶名密碼
    password =b 'x'
    finsh = b"#"     #結束符號
    command = ["hostname","dispaly current-config"]
    #result = doComd(host,user,password,finsh,command)
    f = open(u'GDHIZ-NGN-CE06-HWNE40E_配置備份文件保存.txt','r')
    result = f.read()
    #hostname = result[0]
    hostname = "test"
    conf = result[1]
    interface = get_intferaces(conf)
    interface.to_csv(hostname+'.csv',encoding = 'utf8',index = False)

注意換成真實的IP、用戶名和密碼既可,然后在命令行中運行測試。

image.png

可以發現,運行腳本后,新增test.csv文件:


image.png

上面這個腳本只是基礎,還可以擴展出很多功能,如稍微修改了,就可以遍歷一個IP地址池,大家可以試試。
通過配置文件分析的信息更全更準確,可以有效幫助提升工作效率,同時還可以執行其他指令,并借助Python強大的分析能力進行處理。
Python也可以實現網絡自動運維,而且非常簡單易學,讓我們能夠便捷維護海量設備。

這篇寫的很趕,這方面內容以前掌握比較少,今天在這里只是拋磚引玉,說與神器Python是可以幫我們自動運維的,希望和大家一起學習進步。
下一篇,我想分享下Python在網絡爬蟲方面的簡單應用——簡明Python開發教程(5):用爬蟲實現個性化搜索引擎

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容