銀狐NetDevOps-網(wǎng)絡(luò)運維Python初篇(五)結(jié)合異常處理,批量抓取華為網(wǎng)絡(luò)設(shè)備配置

科技銀狐

銀狐DevNet系列會持續(xù)將網(wǎng)絡(luò)運維工作中python的應(yīng)用進行場景化的分享,因為每個單獨的模塊網(wǎng)上都有詳細(xì)的教學(xué),這里就不深入講解模塊基礎(chǔ)了,內(nèi)容主要以思路和示例為主,并將碰到的問題匯總提出注意事項。

主要是因為網(wǎng)絡(luò)工程師和網(wǎng)絡(luò)運維工作者編程基礎(chǔ)不強,加上網(wǎng)上對于這個領(lǐng)域的python資料又少,傳統(tǒng)的分享方式(每個章節(jié)僅單純分享一個知識點)對于很多網(wǎng)工來說各個知識點相對獨立且割裂的,很難進行一個知識的融合,現(xiàn)實工作中也很難直接應(yīng)用,大家學(xué)習(xí)的難度就會很大,也會導(dǎo)致大部分人剛?cè)腴T就放棄。所以我將這些內(nèi)容進行場景化,根據(jù)特定場景由淺入深不斷優(yōu)化,從而帶出更多知識點,希望對大家有所幫助。

以下分享都是個人學(xué)習(xí)路徑和記錄,因為不是專業(yè)編程人員,難免會出現(xiàn)問題,歡迎大家隨時指正。最后,希望可以通過分享我微不足道的學(xué)習(xí)過程和實戰(zhàn)經(jīng)驗,幫助更多想要學(xué)習(xí)python提升工作效率的人。另一方面也是為了可以找到更多同行之人,互相交流互相提升,祝愿DEVNET行業(yè)發(fā)展的越來越好。


1、訓(xùn)練場景:

讀取excel中設(shè)備IP地址,通過Netmiko抓取設(shè)備配置,并存入本地。代碼加入異常處理,出現(xiàn)異常不影響正常執(zhí)行,并將異常內(nèi)容輸出到本地文件內(nèi),方便后續(xù)查看。

2、實驗環(huán)境:

操作系統(tǒng):Linux CentOS 7.4

python版本:python 3.8

網(wǎng)絡(luò)設(shè)備:華為CE 6865

編輯器:vscode(pycharm、sublime均可,推薦vscode)

excel格式:初次使用簡單一些,excel中只加入IP地址

image.png

3、思路分析

沿用上一章節(jié)代碼,加入異常處理try.....except,這里需要注意,異常處理是有傳遞性的,就是當(dāng)我們執(zhí)行代碼并報錯時,這個異常信息會持續(xù)跟隨,所以當(dāng)我們有多個函數(shù)或者方法時,不需要在每個函數(shù)內(nèi)部使用異常處理try.....except,這樣會很麻煩,最推薦的方式就是在主函數(shù)上統(tǒng)一使用異常處理。

4、整體代碼

#!/usr/bin/env python
#coding: utf-8

import os
from time import time
from datetime import datetime
from netmiko import ConnectHandler
from openpyxl import Workbook
from openpyxl import load_workbook
import gevent
from gevent import spawn
from gevent import monkey;monkey.patch_all()
from gevent.pool import Pool
from netmiko.ssh_exception import NetMikoTimeoutException
from netmiko.ssh_exception import AuthenticationException
from paramiko.ssh_exception import SSHException

def read_device_excel( ):

    ip_list = []

    wb1 = load_workbook('/home/netops/venv/cs_lab.xlsx')
    ws1 = wb1.get_sheet_by_name("Sheet1")

    for cow_num in range(2,ws1.max_row+1):

        ipaddr = ws1["a"+str(cow_num)].value
        ip_list.append(ipaddr)

    return ip_list

def get_config(ipaddr):

    session = ConnectHandler(device_type="huawei",
                            ip=ipaddr,
                            username="libb112",
                            password="3333labcs",
                            banner_timeout=300)

    print("connecting to "+ ipaddr)
    print ("---- Getting HUAWEI configuration from {}-----------".format(ipaddr))

    # config_data = session.send_command('screen-length 0 temporary')
    # config_data = session.send_command('dis cu | no-more ')
    config_data = session.send_command("dis cu")

    session.disconnect()

    return config_data

def write_config_to_file(config_data,ipaddr):
    now = datetime.now()
    date= "%s-%s-%s"%(now.year,now.month,now.day)
    time_now = "%s-%s"%(now.hour,now.minute)

    #---- Write out configuration information to file
    config_path = '/home/netops/linsy_env/devconfig/' +date
    verify_path = os.path.exists(config_path)
    if not verify_path:
        os.makedirs(config_path)

    config_filename = config_path+"/"+'config_' + ipaddr +"_"+date+"_" + time_now # Important - create unique configuration file name

    print ('---- Writing configuration: ', config_filename)
    with open( config_filename, "w",encoding='utf-8' ) as config_out:  
        config_out.write( config_data )

    return

def write_issue_device(issue_device):
    now = datetime.now()
    date= "%s-%s-%s"%(now.year,now.month,now.day)
    time_now = "%s-%s"%(now.hour,now.minute)

    config_path = '/home/netops/linsy_env/' + "issue_" + date
    verify_path = os.path.exists(config_path)
    if not verify_path:
        os.makedirs(config_path)

    config_filename = config_path+"/"+'issue_'+date+"_" + time_now
    print ('---- Writing issue: ', config_filename)
    with open (config_filename, "w", encoding='utf-8') as issue_facts:
        issue_facts.write('\n'.join(issue_device))

def main():

    starting_time = time()   
    issue_device = []
    ip_list = read_device_excel()

    for ipaddr in ip_list:
        try:

            hwconfig = get_config(ipaddr)
            write_config_to_file(hwconfig,ipaddr)
            print ('\n---- End get config threading, elapsed time=', time() - starting_time)

        except (AuthenticationException):
            issue_message = (ipaddr + ': 認(rèn)證錯誤 ')
            issue_device.append(issue_message)

        except NetMikoTimeoutException:
            issue_message = (ipaddr + ': 網(wǎng)絡(luò)不可達 ')
            issue_device.append(issue_message)

        except (SSHException):
            issue_message = (ipaddr +': SSH端口異常 ')
            issue_device.append(issue_message)

        except Exception as unknown_error:
            issue_message = (ipaddr +': 發(fā)生未知錯誤: ')
            issue_device.append(issue_message+str(unknown_error))

        finally:
            write_issue_device(issue_device)                  #異常處理信息寫入文件

#========================================
# Get config of HUAWEI
#========================================
if __name__ == '__main__':
    main()

執(zhí)行結(jié)果


5、代碼詳解

read_device_excel、get_config、write_config_to_file三個函數(shù)的講解請直接參考上一個小節(jié),都有詳細(xì)說明。本小節(jié)主要講解新增的write_issue_device函數(shù),和對主函數(shù)main的修改。

銀狐NetDevOps-網(wǎng)絡(luò)運維Python初篇(四)netmiko抓取華為網(wǎng)絡(luò)配置并存入本地

def main():

    starting_time = time()   
    issue_device = []                           #定義一個list,收集異常處理信息
    ip_list = read_device_excel()

    for ipaddr in ip_list:
        try:                                    #try后面跟我們的代碼

            hwconfig = get_config(ipaddr)
            write_config_to_file(hwconfig,ipaddr)
            print ('\n---- End get config threading, elapsed time=', time() - starting_time)

        except (AuthenticationException):        #except為異常處理  
            issue_message = (ipaddr + ': 認(rèn)證錯誤 ')
            issue_device.append(issue_message)

        except NetMikoTimeoutException:
            issue_message = (ipaddr + ': 網(wǎng)絡(luò)不可達 ')
            issue_device.append(issue_message)

        except (SSHException):
            issue_message = (ipaddr +': SSH端口異常 ')
            issue_device.append(issue_message)

        except Exception as unknown_error:
            issue_message = (ipaddr +': 發(fā)生未知錯誤: ')
            issue_device.append(issue_message+str(unknown_error))

        finally:                             #無論是否有異常,都執(zhí)行
            write_issue_device(issue_device)                  #異常處理信息寫入文件

1、try后面跟正常的代碼,因為異常是有傳遞性的,就算代碼中有多個函數(shù),也不需要每個函數(shù)里面使用異常處理,而是直接在主函數(shù)統(tǒng)一使用。

2、如果主函數(shù)有for循環(huán),注意異常處理要放在for循環(huán)里面,因為try....except異常處理模塊的邏輯是,當(dāng)我們執(zhí)行代碼報錯時直接跳向except進行異常處理,處理完except之后會去執(zhí)行finally后面的代碼,也就是說不會返回try繼續(xù)執(zhí)行我們后續(xù)代碼。

比如我們for循環(huán)4臺設(shè)備,第一臺設(shè)備SSH登錄就報錯了,直接進入except異常處理,后面3臺相當(dāng)于直接跳過了。

        except (AuthenticationException):               #捕捉認(rèn)證錯誤異常
            issue_message = (ipaddr + ': 認(rèn)證錯誤 ')    #捕捉到異常后輸出提示信息,XXX設(shè)備認(rèn)證錯誤
            issue_device.append(issue_message)          #將提示信息加入前面定義好的list中

        except NetMikoTimeoutException:
            issue_message = (ipaddr + ': 網(wǎng)絡(luò)不可達 ')
            issue_device.append(issue_message)

        except (SSHException):
            issue_message = (ipaddr +': SSH端口異常 ')
            issue_device.append(issue_message)

使用netmiko連接網(wǎng)絡(luò)設(shè)備異常經(jīng)常出現(xiàn)三種情況,設(shè)備不可達,認(rèn)證錯誤,SSH端口異常,所以我把這些異常處理進行分類并寫入文件,這樣批量操作以后我就知道哪些設(shè)備有哪些問題進行批量處理。

那么如何捕捉異常信息呢?比如我netmiko登錄設(shè)備時密碼錯誤,會提示我認(rèn)證錯誤。

image

最后一行會提示我們AuthenticationException:Authentication Failed.我們捕捉冒號前的AuthenticationException就好。

        except Exception as unknown_error:
            issue_message = (ipaddr +': 發(fā)生未知錯誤: ')
            issue_device.append(issue_message+str(unknown_error))

        finally:
            write_issue_device(issue_device)                  #異常處理信息寫入文件

我們很難捕捉到所有已知的異常,所以需要一個兜底策略,就是 except Exception as unknown_error,定義一個提示信息(發(fā)生未知錯誤),并把報錯的原內(nèi)容加入上面定義的異常list中,需要注意第三行我把原錯誤信息轉(zhuǎn)化為str字符串,因為后面我們會把所有異常提示信息list的內(nèi)容用換行符\n進行拼接,便于我們觀看文本,所以要確保所有信息是字符串,否則無法拼接。

最后,無論是否有錯誤信息,都要把異常處理列表內(nèi)的信息寫入文件,函數(shù)write_issue_device和上一小節(jié)內(nèi)容一致,相信大家都能看懂。只需要注意,我們要使用換行符\n拼接list內(nèi)的內(nèi)容,確保每個設(shè)備的錯誤信息為一行,否則跑批1000臺設(shè)備,100臺設(shè)備報錯,而且所有錯誤信息串在一起根本無法查看。

def write_issue_device(issue_device):
    now = datetime.now()
    date= "%s-%s-%s"%(now.year,now.month,now.day)
    time_now = "%s-%s"%(now.hour,now.minute)

    config_path = '/home/netops/linsy_env/' + "issue_" + date    #定義路徑
    verify_path = os.path.exists(config_path)                    #驗證路徑
    if not verify_path:
        os.makedirs(config_path)

    config_filename = config_path+"/"+'issue_'+date+"_" + time_now
    print ('---- Writing issue: ', config_filename)
    with open (config_filename, "w", encoding='utf-8') as issue_facts:
        issue_facts.write('\n'.join(issue_device))               #使用換行符\n拼接list內(nèi)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容