前言
銀狐DevNet系列會(huì)持續(xù)將網(wǎng)絡(luò)運(yùn)維工作中python的應(yīng)用進(jìn)行場(chǎng)景化的分享,因?yàn)槊總€(gè)單獨(dú)的模塊網(wǎng)上都有詳細(xì)的教學(xué)煎饼,這里就不深入講解模塊基礎(chǔ)了,內(nèi)容主要以思路和示例為主,并將碰到的問(wèn)題匯總提出注意事項(xiàng)辅柴。
主要是因?yàn)榫W(wǎng)絡(luò)工程師和網(wǎng)絡(luò)運(yùn)維工作者編程基礎(chǔ)不強(qiáng),加上網(wǎng)上對(duì)于這個(gè)領(lǐng)域的python資料又少瞭吃,傳統(tǒng)的分享方式(每個(gè)章節(jié)僅單純分享一個(gè)知識(shí)點(diǎn))對(duì)于很多網(wǎng)工來(lái)說(shuō)各個(gè)知識(shí)點(diǎn)相對(duì)獨(dú)立且割裂的碌嘀,很難進(jìn)行一個(gè)知識(shí)的融合,現(xiàn)實(shí)工作中也很難直接應(yīng)用歪架,大家學(xué)習(xí)的難度就會(huì)很大股冗,也會(huì)導(dǎo)致大部分人剛?cè)腴T(mén)就放棄。所以我將這些內(nèi)容進(jìn)行場(chǎng)景化和蚪,根據(jù)特定場(chǎng)景由淺入深不斷優(yōu)化止状,從而帶出更多知識(shí)點(diǎn),希望對(duì)大家有所幫助攒霹。
這些分享都是我本人真實(shí)的學(xué)習(xí)路徑怯疤,一方面是幫助自己梳理網(wǎng)絡(luò)自動(dòng)化相關(guān)知識(shí),另一方面也希望可以通過(guò)分享我微不足道的學(xué)習(xí)過(guò)程和實(shí)戰(zhàn)經(jīng)驗(yàn)催束,幫助更多想要了解NetDevOps而苦于沒(méi)有資料和環(huán)境被勸退的人集峦,進(jìn)而找到同行之人互相交流、互相提升泣崩。
1少梁、場(chǎng)景分析:
NETCONF協(xié)議對(duì)于傳統(tǒng)網(wǎng)工來(lái)說(shuō)是噩夢(mèng),看到XML編碼就直接勸退了矫付,但對(duì)于普通網(wǎng)工來(lái)說(shuō)依然有適用的場(chǎng)景凯沪。平時(shí)我們批量操作無(wú)非就是增刪改查,針對(duì)設(shè)備增刪改买优,個(gè)人建議直接使用python的netmiko模塊妨马,非常方便挺举,也符合傳統(tǒng)網(wǎng)工輸入CLI的習(xí)慣。但對(duì)于查就需要區(qū)分場(chǎng)景了烘跺。
當(dāng)我們需要查詢?cè)O(shè)備某些配置或者狀態(tài)時(shí)湘纵,常規(guī)做法就是輸入CLI,然后在返回結(jié)果中查看想要的內(nèi)容滤淳。使用python進(jìn)行跑批操作時(shí)也是通過(guò)paramiko梧喷、netmiko這類(lèi)模塊直接SSH上設(shè)備,然后輸入CLI命令脖咐,在根據(jù)回顯內(nèi)容獲取想要的數(shù)據(jù)铺敌。這里分幾種情況,如果我們想獲取設(shè)備配置文件屁擅,直接通過(guò)netmiko傳遞show config命令偿凭,其實(shí)是沒(méi)什么問(wèn)題的,因?yàn)檫@個(gè)回顯的內(nèi)容是不需要做任何處理的派歌。
那我們換一個(gè)場(chǎng)景弯囊,1000臺(tái)網(wǎng)絡(luò)設(shè)備,需要批量獲取所有設(shè)備的設(shè)備名稱(chēng)胶果、型號(hào)匾嘱、版本號(hào)、補(bǔ)丁稽物,并將內(nèi)容存儲(chǔ)起來(lái)時(shí)該怎么辦呢奄毡?這里有3中方法折欠。
方法一:
使用paramiko或者netmiko批量登錄網(wǎng)絡(luò)設(shè)備贝或,并輸入CLI(disp ver),將如下回顯內(nèi)容自行處理锐秦。
Huawei Versatile Routing Platform Software
VRP (R) software, Version 8.180 (CE6855HI V200R005C10SPC800)
Copyright (C) 2012-2018 Huawei Technologies Co., Ltd.
HUAWEI CE6855-48S6Q-HI uptime is 421 days, 13 hours, 24 minutes
Patch Version: V200R005SPH016
CE6855-48S6Q-HI(Master) 1 : uptime is 421 days, 13 hours, 22 minutes
StartupTime 2020/03/24 18:35:47+08:00
Memory Size : 2048 M bytes
Flash Size : 1024 M bytes
CE6855-48S6Q-HI version information
1\. PCB Version : CEM48S6QP05 VER B
2\. MAB Version : 1
3\. Board Type : CE6855-48S6Q-HI
4\. CPLD1 Version : 102
5\. BIOS Version : 433
顯然咪奖,處理以上數(shù)據(jù)會(huì)非常麻煩
方法二:
使用netmiko這類(lèi)SSH模塊配合textFSM模板(結(jié)合ntc-template)進(jìn)行操作(方法以后講解),直接回顯如下列表內(nèi)容酱床。
[{'model': 'CE6855-48S6Q-HI',
'product_version': 'CE6855HI V200R005C10SPC800',
'uptime': '421 days, 9 hours, 24 minutes ',
'vrp_version': '8.180'}]
可以看到羊赵,非常方便。
但問(wèn)題就是這方面的模板cisco和juniper等國(guó)外廠商比較充足扇谣,基本涵蓋了常見(jiàn)需求昧捷,國(guó)內(nèi)華為只有4個(gè)模板,如下所示。
-rw-rw-r-- 1 yydd yydd 483 May 8 10:21 huawei_vrp_display_interface_brief.textfsm
-rw-rw-r-- 1 yydd yydd 1811 May 8 10:21 huawei_vrp_display_lldp_neighbor.textfsm
-rw-rw-r-- 1 yydd yydd 390 May 8 10:21 huawei_vrp_display_temperature.textfsm
-rw-rw-r-- 1 yydd yydd 217 May 8 10:21 huawei_vrp_display_version.textfsm
也就是只有4個(gè)命令回顯可以直接返回處理好的列表罐寨,顯然是不夠用的靡挥。(模板可自己編寫(xiě),難度比較大)
方法三:
使用NETCONF協(xié)議鸯绿,結(jié)合標(biāo)準(zhǔn)的XML編碼格式跋破,返回標(biāo)準(zhǔn)化格式的內(nèi)容簸淀。而ncclient就是一個(gè)用于NETCONF客戶端的Python庫(kù)。
2毒返、操作環(huán)境:
操作系統(tǒng):Linux CentOS 7.4
python版本:python 3.8
網(wǎng)絡(luò)設(shè)備:華為CloudEngine 6865
編輯器:vscode
安裝ncclient:
pip3 install ncclient
3租幕、代碼示例
#!/usr/bin/env python
#coding: utf-8
from pprint import pprint
import xmltodict
from ncclient import manager
from ncclient import operations
from ncclient.transport.errors import SSHError
from ncclient.transport.errors import AuthenticationError
#構(gòu)造待配置的YANG內(nèi)容,此處為系統(tǒng)信息拧簸。
#具體可參考華為官網(wǎng)二次開(kāi)發(fā)文檔《CloudEngine 8800, 7800, 6800HI, 6880EI, 6875EI, 6870EI, 6865EI, 6860EI, 6857EI, 5880EI V200R005C10 NETCONF Schema API參考》
devinfo_FILTER = '''
<system xmlns="<http://www.huawei.com/netconf/vrp>" content-version="1.0" format-version="1.0">
<systemInfo>
</systemInfo>
</system>
'''
# Fill the device information and establish a NETCONF session
def huawei_connect(host, port, user, password):
return manager.connect(host=host,
port=port,
username=user,
password=password,
hostkey_verify = False,
device_params={'name': "huawei"},
allow_agent = False,
look_for_keys = False)
def nc_get(host, port, user, password):
with huawei_connect(host, port=port, user=user, password=password) as m:
return m.get(("subtree", devinfo_FILTER))
def main():
nc_res = nc_get("172.26.32.7",22,"user","pass")
xml_rep = nc_res.data_xml
print(xml_rep)
if __name__ == '__main__':
main()
執(zhí)行結(jié)果
<?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<system xmlns="<http://www.huawei.com/netconf/vrp>" format-version="1.0" content-version="1.0">
<systemInfo>
<sysName>SZTL-POD2-Leaf-H6865-1</sysName>
<sysContact>R&D Beijing, Huawei Technologies co.,Ltd.</sysContact>
<sysLocation>Beijing China</sysLocation>
<sysDesc>Huawei Versatile Routing Platform Software
VRP (R) software, Version 8.191 (CE6865EI V200R019C10SPC800)
Copyright (C) 2012-2020 Huawei Technologies Co., Ltd.
HUAWEI CE6865-48S8CQ-EI </sysDesc>
<sysObjectId>1.3.6.1.4.1.2011.2.239.49</sysObjectId>
<sysGmtTime>1621568735</sysGmtTime>
<sysUpTime>4125375</sysUpTime>
<sysService>78</sysService>
<platformName>VRP</platformName>
<platformVer>V800R019C16SPC599</platformVer>
<productName>CE6865EI</productName>
<productVer>V200R019C10SPC800</productVer>
<patchVer>V200R019SPH007</patchVer>
<esn>2102351RFD10MC111521</esn>
<mac>9017-3FF0-1CB1</mac>
<lsRole>admin</lsRole>
<authenFlag>false</authenFlag>
<softwareName/>
</systemInfo>
</system>
</data>
可以看到回顯內(nèi)容結(jié)構(gòu)非常清晰劲绪,需要什么數(shù)據(jù)直接從XML中獲取即可。后面就以示例為基礎(chǔ)盆赤,完成開(kāi)頭提到的需求珠叔。
4、ncclient實(shí)驗(yàn)
4.1 需求
獲取設(shè)備的設(shè)備名稱(chēng)弟劲、型號(hào)祷安、版本號(hào)、補(bǔ)丁兔乞、SN
4.2 代碼
#!/usr/bin/env python
#coding: utf-8
from pprint import pprint
import xmltodict
from ncclient import manager
from ncclient import operations
from ncclient.transport.errors import SSHError
from ncclient.transport.errors import AuthenticationError
#構(gòu)造YANG
devinfo_FILTER = '''
<system xmlns="<http://www.huawei.com/netconf/vrp>" content-version="1.0" format-version="1.0">
<systemInfo>
<sysName></sysName>
<productName></productName>
<productVer></productVer>
<patchVer></patchVer>
<esn></esn>
</systemInfo>
</system>
'''
#建立NETCONF會(huì)話
def huawei_connect(host, port, user, password):
return manager.connect(host=host,
port=port,
username=user,
password=password,
hostkey_verify = False,
device_params={'name': "huawei"},
allow_agent = False,
look_for_keys = False)
#構(gòu)造<get>報(bào)文
def nc_get(host, port, user, password):
with huawei_connect(host, port=port, user=user, password=password) as m:
return m.get(("subtree", devinfo_FILTER))
#主函數(shù)
def main():
nc_res = nc_get("172.26.32.7",22,"user","pass")
xml_rep = nc_res.data_xml
print(xml_rep)
xml_dict = xmltodict.parse(xml_rep)
for k,y in xml_dict.items():
print(k,y)
print("="*70)
for k,y in xml_dict['data']['system']['systemInfo'].items():
print(k,":",y)
if __name__ == '__main__':
main()
執(zhí)行結(jié)果
<?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<system xmlns="<http://www.huawei.com/netconf/vrp>" format-version="1.0" content-version="1.0">
<systemInfo>
<sysName>SZTL-POD2-Leaf-H6865-1</sysName>
<productName>CE6865EI</productName>
<productVer>V200R019C10SPC800</productVer>
<patchVer>V200R019SPH007</patchVer>
<esn>2102351RFD10MC111521</esn>
</systemInfo>
</system>
</data>
data OrderedDict([('@xmlns', 'urn:ietf:params:xml:ns:netconf:base:1.0'), ('system', OrderedDict([('@xmlns', '<http://www.huawei.com/netconf/vrp>'), ('@format-version', '1.0'), ('@content-version', '1.0'), ('systemInfo', OrderedDict([('sysName', 'SZTL-POD2-Leaf-H6865-1'), ('productName', 'CE6865EI'), ('productVer', 'V200R019C10SPC800'), ('patchVer', 'V200R019SPH007'), ('esn', '2102351RFD10MC111521')]))]))])
======================================================================
sysName : SZTL-POD2-Leaf-H6865-1
productName : CE6865EI
productVer : V200R019C10SPC800
patchVer : V200R019SPH007
esn : 2102351RFD10MC111521
4.3 詳解
from pprint import pprint
#有縮進(jìn)的打印汇鞭,回顯更直觀,建議使用
import xmltodict
#用于xml轉(zhuǎn)換為dict
#導(dǎo)入ncclient常用模塊
from ncclient import manager
from ncclient import operations
from ncclient.transport.errors import SSHError
from ncclient.transport.errors import AuthenticationError
devinfo_FILTER = '''
<system xmlns="<http://www.huawei.com/netconf/vrp>" content-version="1.0" format-version="1.0">
<systemInfo>
<sysName></sysName>
<productName></productName>
<productVer></productVer>
<patchVer></patchVer>
<esn></esn>
</systemInfo>
</system>
'''
構(gòu)造待配置的YANG內(nèi)容,此處為系統(tǒng)信息庸追。 具體可參考華為官網(wǎng)二次開(kāi)發(fā)文檔《CloudEngine 8800, 7800, 6800HI, 6880EI, 6875EI, 6870EI, 6865EI, 6860EI, 6857EI, 5880EI V200R005C10 NETCONF Schema API參考》霍骄。
如果我們只需要systemInfo下的部分信息,直接在<systemInfo></systemInfo>中間加入明細(xì)內(nèi)容即可淡溯,可參考官方文檔读整。
關(guān)于XML基礎(chǔ)知識(shí),可以訪問(wèn)https://www.w3school.com.cn/xml/xml_intro.asp查看咱娶。
def huawei_connect(host, port, user, password):
return manager.connect(host=host,
port=port,
username=user,
password=password,
hostkey_verify = False,
device_params={'name': "huawei"},
allow_agent = False,
look_for_keys = False)
定義NETCONF session的函數(shù)米间,調(diào)用manager.connect建立連接。
def nc_get(host, port, user, password):
with huawei_connect(host, port=port, user=user, password=password) as m:
return m.get(("subtree", devinfo_FILTER))
定義get函數(shù)膘侮,構(gòu)造<get>報(bào)文屈糊,并返回rpc-reply的結(jié)果。
因?yàn)槲覀儾幌M鹓et過(guò)多內(nèi)容琼了,所以要加入filter功能逻锐,devinfo_FILTER就是我們自己構(gòu)建的XML,<filter>元素可以包含“type”屬性雕薪,NETCONF中的默認(rèn)過(guò)濾機(jī)制被稱(chēng)為子樹(shù)過(guò)濾(“type”屬性值為“subtree”)昧诱。
打印結(jié)果一:
#主函數(shù)
def main():
nc_res = nc_get("172.26.32.7",22,"user","pass")
xml_rep = nc_res.data_xml #返回XML標(biāo)準(zhǔn)格式的字符串
print(xml_rep)
#執(zhí)行結(jié)果
<?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<system xmlns="<http://www.huawei.com/netconf/vrp>" format-version="1.0" content-version="1.0">
<systemInfo>
<sysName>SZTL-POD2-Leaf-H6865-1</sysName>
<productName>CE6865EI</productName>
<productVer>V200R019C10SPC800</productVer>
<patchVer>V200R019SPH007</patchVer>
<esn>2102351RFD10MC111521</esn>
</systemInfo>
</system>
</data>
打印結(jié)果二:
xml_dict = xmltodict.parse(xml_rep)
#此方法會(huì)將xml_rep解析為orderdict,和傳統(tǒng)dict區(qū)別就是orderdict是有順序的
for k,y in xml_dict.items():
#遍歷字典所袁,items() 方法讓字典以列表形式返回可遍歷的(鍵, 值) 元組數(shù)組
print(k,y)
#執(zhí)行結(jié)果
data OrderedDict([('@xmlns', 'urn:ietf:params:xml:ns:netconf:base:1.0'), ('system', OrderedDict([('@xmlns', '<http://www.huawei.com/netconf/vrp>'), ('@format-version', '1.0'), ('@content-version', '1.0'), ('systemInfo', OrderedDict([('sysName', 'SZTL-POD2-Leaf-H6865-1'), ('productName', 'CE6865EI'), ('productVer', 'V200R019C10SPC800'), ('patchVer', 'V200R019SPH007'), ('esn', '2102351RFD10MC111521')]))]))])
打印結(jié)果三:
#訪問(wèn)xml_dict['data']['system']['systemInfo']的value
#OrderedDict([('sysName', 'SZTL-POD2-Leaf-H6865-1'),
# ('productName', 'CE6865EI'),
# ('productVer', 'V200R019C10SPC800'),
# ('patchVer', 'V200R019SPH007'),
# ('esn', '2102351RFD10MC111521')])
#在進(jìn)行遍歷操作
for k,y in xml_dict['data']['system']['systemInfo'].items():
print(k,":",y)
#打印結(jié)果
sysName : SZTL-POD2-Leaf-H6865-1
productName : CE6865EI
productVer : V200R019C10SPC800
patchVer : V200R019SPH007
esn : 2102351RFD10MC111521
上面的逐步打印盏档,是為了讓大家更清晰的看到每一步數(shù)據(jù)處理的區(qū)別。
核心還是提供思路纲熏,詳細(xì)的基礎(chǔ)知識(shí)如果有不懂的妆丘,直接在Google或者baidu搜索锄俄,有很多資料。