华为交换机配置自动化备份实践 华为交换机备份配置)
在上一篇文章中,我實(shí)踐了通過(guò)Python的paramiko模塊來(lái)SSH登錄到華為交換機(jī)上批量備份配置文件到FTP服務(wù)器上。最后總結(jié)存在兩個(gè)問(wèn)題,一個(gè)是在腳本運(yùn)行過(guò)程中,如果中間某臺(tái)設(shè)備因用戶名密碼錯(cuò)誤或者網(wǎng)絡(luò)不可達(dá)的情況,會(huì)導(dǎo)致腳本中斷運(yùn)行無(wú)法繼續(xù)執(zhí)行下去,后面設(shè)備的備份也無(wú)法完成。第二個(gè)就是由于python默認(rèn)是單線程串行執(zhí)行的,在設(shè)備量大的時(shí)候效率可能不高,腳本需要運(yùn)行的時(shí)間比較長(zhǎng)。
本篇文章將會(huì)通過(guò)try...except來(lái)實(shí)現(xiàn)異常處理,以及通過(guò)threading模塊來(lái)解決多線程問(wèn)題,并發(fā)執(zhí)行多臺(tái)設(shè)備同時(shí)進(jìn)行備份操作。
本實(shí)驗(yàn)通過(guò)學(xué)習(xí)@弈心大佬的《網(wǎng)絡(luò)工程師的Python之路》后結(jié)合自己的理解和思路形成。
實(shí)驗(yàn)環(huán)境及拓?fù)淙匀桓洗我粯樱琾ython實(shí)驗(yàn)平臺(tái)與5臺(tái)交換機(jī)橋接在一起。
異常處理try...except
異常是一個(gè)事件,在程序執(zhí)行過(guò)程中python無(wú)法正常處理的程序發(fā)生的話,就會(huì)影響程序的正常執(zhí)行。Python可以通過(guò)try...except語(yǔ)句來(lái)檢測(cè)try語(yǔ)句塊中的錯(cuò)誤,并且讓except語(yǔ)句來(lái)捕獲異常信息并進(jìn)行處理。
首先基于上一次的實(shí)驗(yàn)的基礎(chǔ)上,加入異常處理的機(jī)制,以下是加入異常處理機(jī)制后完整的代碼。
下面我們來(lái)對(duì)代碼進(jìn)行分析。
第一部分
for line in f.readlines():
try:
line_s = line.split( )
device_ip = line_s[0]
device_name = line_s[1]
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=device_ip, username=username, password=password)
print('成功連接上 ', device_ip)
command = ssh_client.invoke_shell()
command.send('save\n')
command.send('y\n')
time.sleep(1)
command.send('ftp 192.168.134.1\n')
command.send('ftpuser\n')
command.send('ftpuser\n')
command.send('put vrpcfg.zip ' + date + '_' + device_name + '_vrpcfg.zip\n')
command.send('bye\n')
time.sleep(1)
output = command.recv(65535)
print(output.decode('UTF-8'))
except paramiko.ssh_exception.AuthenticationException:
print(device_ip + ' 用戶認(rèn)證失敗..')
device_authentication_failed_list.append(device_ip)
except socket.error:
print(device_ip + ' 網(wǎng)絡(luò)不可達(dá)..')
device_not_reachable_list.append(device_ip)主代碼跟上一次實(shí)驗(yàn)是一樣的,只是在主代碼前面加入try,并在主代碼后加入except捕獲具體的異常信息。如果try后的語(yǔ)句執(zhí)行時(shí)發(fā)生異常,python就會(huì)跳到except來(lái)判斷異常信息,并執(zhí)行響應(yīng)動(dòng)作。如果try后的語(yǔ)句執(zhí)行正常,則會(huì)跳過(guò)except,就跟if...else條件判斷語(yǔ)句是一個(gè)意思。
主代碼跟上一次實(shí)驗(yàn)是一樣的,只是在主代碼前面加入try,并在主代碼后加入except捕獲具體的異常信息。如果try后的語(yǔ)句執(zhí)行時(shí)發(fā)生異常,python就會(huì)跳到except來(lái)判斷異常信息,并執(zhí)行相應(yīng)的動(dòng)作。如果try后的語(yǔ)句執(zhí)行正常,則會(huì)跳過(guò)except,就跟if...else條件判斷語(yǔ)句是一個(gè)意思。
網(wǎng)絡(luò)設(shè)備登錄異常通常有2個(gè)場(chǎng)景,一個(gè)就是用戶名密碼錯(cuò)誤,即認(rèn)證失敗無(wú)法登錄上設(shè)備,第二個(gè)就是這臺(tái)網(wǎng)絡(luò)設(shè)備斷網(wǎng)了無(wú)法連接上。
通過(guò)paramiko登錄設(shè)備認(rèn)證失敗的話,python會(huì)拋出異常信息 paramiko.ssh_exception.AuthenticationException,因此我們通過(guò)except來(lái)捕獲這個(gè)異常報(bào)錯(cuò)信息來(lái)執(zhí)行下面的動(dòng)作,這里我們會(huì)先打印一個(gè)信息提示這個(gè)IP認(rèn)證失敗的原因,并且將該異常設(shè)備的IP地址添加進(jìn)先前定義好的空列表device_authentication_failed_list里。網(wǎng)絡(luò)不可達(dá)的異常需要引入socket模塊來(lái)處理,當(dāng)設(shè)備連接不上時(shí)會(huì)報(bào)socket.error,同樣的把這個(gè)異常情況打印出來(lái)并放到定義好的空列表device_not_reachable_list里。
第二部分
print('\n以下設(shè)備認(rèn)證失敗無(wú)法登錄: ')
if device_authentication_failed_list == []: #判斷是否為空列表
print('無(wú)')
else:
for i in device_authentication_failed_list:
print(i)
print('\n以下設(shè)備網(wǎng)絡(luò)不可達(dá): ')
if device_not_reachable_list == []:
print('無(wú)')
else:
for i in device_not_reachable_list:
print(i)
最后,當(dāng)程序執(zhí)行完把所有出現(xiàn)登錄異常的設(shè)備的打印出來(lái),后期人工再做后續(xù)處理。判斷如果列表為空,則打印“無(wú)”,否則非空則分別打印出列表里的異常設(shè)備IP。
異常處理實(shí)驗(yàn)驗(yàn)證
把SW2的登錄密碼修改為Cisco@123(模擬認(rèn)證失敗),把SW4連HUB的接口G0/0/1 shutdown掉(模擬網(wǎng)絡(luò)不可達(dá)),再運(yùn)行腳本。
可以看到,在腳本執(zhí)行過(guò)程中對(duì)于無(wú)法登錄的設(shè)備會(huì)打印出異常信息,并繼續(xù)執(zhí)行下一臺(tái)設(shè)備的備份操作而不會(huì)中途中斷。在所有設(shè)備備份執(zhí)行完之后,會(huì)統(tǒng)計(jì)出所有異常設(shè)備的IP并打印出來(lái)。
多線程 threading
Python默認(rèn)是單線程的,在執(zhí)行備份腳本的時(shí)候通過(guò)輸出可以看到是在備份完一臺(tái)設(shè)備后再備份另外一臺(tái)這樣串行執(zhí)行的。由于本次實(shí)驗(yàn)總共就5臺(tái)設(shè)備,所以整個(gè)備份時(shí)間都可以接受,那如果現(xiàn)網(wǎng)中有幾十上百臺(tái)設(shè)備的話,單線程執(zhí)行的過(guò)程會(huì)是比較慢的,下面就介紹通過(guò)python自帶的threading模塊來(lái)實(shí)現(xiàn)多線程并發(fā)執(zhí)行多臺(tái)設(shè)備同時(shí)備份,加快程序執(zhí)行效率。據(jù)說(shuō)有更好用的多線程模塊,后面我也會(huì)繼續(xù)研究學(xué)習(xí)一下。
本次實(shí)驗(yàn)我會(huì)對(duì)代碼稍微改造一下,將SSH登錄及命令執(zhí)行封裝成函數(shù)ssh_f,然后用后面代碼調(diào)用ssh_f函數(shù)。全部代碼如下。
代碼解析
第一部分
def ssh_f(ip, username, password, device_name, date): #封裝成函數(shù)ssh_f
try:
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=ip, username=username, password=password)
print('成功連接上: ', ip)
time.sleep(2)
command = ssh_client.invoke_shell()
command.send('save\n')
command.send('y\n')
time.sleep(1)
command.send('ftp 192.168.134.1\n')
command.send('ftpuser\n')
command.send('ftpuser\n')
command.send('put vrpcfg.zip ' + date + '_' + device_name + '_vrpcfg.zip\n')
command.send('bye\n')
time.sleep(1)
print('已完成備份... ', ip)
except paramiko.ssh_exception.AuthenticationException:
print('用戶認(rèn)證失敗 ' + ip + '.')
device_authentication_failed_list.append(ip)
except socket.error:
print(ip + ' 網(wǎng)絡(luò)不可達(dá)')
device_not_reachable_list.append(ip)
ssh_client.close()
此部分只是把先前的代碼封裝成了函數(shù),定義了函數(shù)名為ssh_f,函數(shù)內(nèi)的代碼跟先前是一樣的,只是把ssh登錄跟下發(fā)命令的代碼單獨(dú)抽取了出來(lái)放到函數(shù)里,這樣能夠方便后面代碼的調(diào)用。并對(duì)ssh_f函數(shù)定義了這幾個(gè)參數(shù),ip, username, password, device_name, date,后面調(diào)用時(shí)會(huì)傳參進(jìn)去。
第二部分
username = 'python'
password = 'Python@123'
date = time.strftime('%Y-%m-%d')
threads = [10]
device_authentication_failed_list = []
device_not_reachable_list = []
print('開(kāi)始執(zhí)行備份操作...')
f = open('devices_list.txt', 'r')
for line in f.readlines():
line_s = line.split( )
ip_address = line_s[0]
device_name = line_s[1]
#使用threading的Thread()函數(shù)為ssh_2函數(shù)創(chuàng)建一個(gè)線程并將它賦值給變量a,注意Thread()函數(shù)的target參數(shù)對(duì)應(yīng)的是函數(shù)名稱(即ssh_2)
#args對(duì)應(yīng)的是該ssh_f函數(shù)的參數(shù)
a = threading.Thread(target=ssh_f, args=(ip_address, username, password, device_name, date))
a.start()
f.close()
time.sleep(5) #先等待所有操作執(zhí)行完,再打印異常列表
print('\n以下設(shè)備認(rèn)證失敗無(wú)法登錄: ')
if device_authentication_failed_list == []: # 判斷是否為空列表
print('無(wú)')
else:
for i in device_authentication_failed_list:
print(i)
print('\n以下設(shè)備網(wǎng)絡(luò)不可達(dá): ')
if device_not_reachable_list == []:
print('無(wú)')
else:
for i in device_not_reachable_list:
print(i)
接下來(lái)的代碼其實(shí)跟之前的主代碼基本差不多,不再一一解釋。增加的點(diǎn)就是在for循環(huán)里增加了threading的代碼,并且在threading里調(diào)用剛才定義的ssh_f函數(shù)用于ssh連接及命令執(zhí)行。
使用threading的Thread()函數(shù)為ssh_2函數(shù)創(chuàng)建一個(gè)線程并將它賦值給變量a,Thread()函數(shù)的target參數(shù)對(duì)應(yīng)的是函數(shù)名稱ssh_2,args對(duì)應(yīng)的是該ssh_f函數(shù)的參數(shù),相關(guān)參數(shù)都已經(jīng)定義并傳參進(jìn)來(lái)。
然后a.start() 啟動(dòng)線程。使用threading多線程,這樣下一個(gè)操作就不需要等上一個(gè)操作執(zhí)行完后再開(kāi)始執(zhí)行,實(shí)現(xiàn)了并行執(zhí)行。
實(shí)驗(yàn)驗(yàn)證
下面我們就對(duì)這個(gè)腳本運(yùn)行一下,再來(lái)看看這5臺(tái)設(shè)備的備份效果。特意制作了以下的GIF動(dòng)圖,可以看到5臺(tái)設(shè)備的備份過(guò)程基本上是同時(shí)連接上,并且是幾乎同時(shí)完成的,不再是前面實(shí)驗(yàn)一樣先完成一臺(tái)后再執(zhí)行下一臺(tái),這樣,這個(gè)腳本的執(zhí)行效率就會(huì)大大的提升,如果設(shè)備多的話將會(huì)腳本運(yùn)行的效率就會(huì)有量級(jí)的提升。
可以看到服務(wù)器文件目錄里已經(jīng)能夠正常獲取到5臺(tái)交換機(jī)的配置文件。
總結(jié)
通過(guò)以上兩個(gè)實(shí)驗(yàn)案例,通過(guò)異常處理及多線程,就可以優(yōu)化上一個(gè)實(shí)驗(yàn)遺留下來(lái)的2個(gè)問(wèn)題了。以上的實(shí)踐尤其是多線程并發(fā)處理,肯定還有很多方式可以實(shí)現(xiàn),接下來(lái)我也會(huì)繼續(xù)探索更多Netdevops的內(nèi)容。由于目前還處于小白的階段,以上編寫的代碼和解讀肯定還有很多不足和理解不夠深入之處,如有任何錯(cuò)誤的地方還請(qǐng)各位朋友指出,共同學(xué)習(xí)!
總結(jié)
以上是生活随笔為你收集整理的华为交换机配置自动化备份实践 华为交换机备份配置)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Request.Form的用法
- 下一篇: 安全管理数据库