銀狐NetDevOps-網絡運維Python初篇(五)結合異常處理,批量抓取華爲網絡設備配置

銀狐DevNet系列會持續將網絡運維工作中python的應用進行場景化的分享,因爲每個單獨的模塊網上都有詳細的教學,這裏就不深入講解模塊基礎了,內容主要以思路和示例爲主,並將碰到的問題彙總提出注意事項。

主要是因爲網絡工程師和網絡運維工作者編程基礎不強,加上網上對於這個領域的python資料又少,傳統的分享方式(每個章節僅單純分享一個知識點)對於很多網工來說各個知識點相對獨立且割裂的,很難進行一個知識的融合,現實工作中也很難直接應用,大家學習的難度就會很大,也會導致大部分人剛入門就放棄。所以我將這些內容進行場景化,根據特定場景由淺入深不斷優化,從而帶出更多知識點,希望對大家有所幫助。

以下分享都是個人學習路徑和記錄,因爲不是專業編程人員,難免會出現問題,歡迎大家隨時指正。最後,希望可以通過分享我微不足道的學習過程和實戰經驗,幫助更多想要學習python提升工作效率的人。另一方面也是爲了可以找到更多同行之人,互相交流互相提升,祝願DEVNET行業發展的越來越好。


1、訓練場景:

讀取excel中設備IP地址,通過Netmiko抓取設備配置,並存入本地。代碼加入異常處理,出現異常不影響正常執行,並將異常內容輸出到本地文件內,方便後續查看。

2、實驗環境:

操作系統:Linux CentOS 7.4

python版本:python 3.8

網絡設備:華爲CE 6865

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

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

3、思路分析

沿用上一章節代碼,加入異常處理try.....except,這裏需要注意,異常處理是有傳遞性的,就是當我們執行代碼並報錯時,這個異常信息會持續跟隨,所以當我們有多個函數或者方法時,不需要在每個函數內部使用異常處理try.....except,這樣會很麻煩,最推薦的方式就是在主函數上統一使用異常處理。

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 + ': 認證錯誤 ')
            issue_device.append(issue_message)

        except NetMikoTimeoutException:
            issue_message = (ipaddr + ': 網絡不可達 ')
            issue_device.append(issue_message)

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

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

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

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

執行結果


5、代碼詳解

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

銀狐NetDevOps-網絡運維Python初篇(四)netmiko抓取華爲網絡配置並存入本地

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 + ': 認證錯誤 ')
            issue_device.append(issue_message)

        except NetMikoTimeoutException:
            issue_message = (ipaddr + ': 網絡不可達 ')
            issue_device.append(issue_message)

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

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

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

1、try後面跟正常的代碼,因爲異常是有傳遞性的,就算代碼中有多個函數,也不需要每個函數裏面使用異常處理,而是直接在主函數統一使用。

2、如果主函數有for循環,注意異常處理要放在for循環裏面,因爲try....except異常處理模塊的邏輯是,當我們執行代碼報錯時直接跳向except進行異常處理,處理完except之後會去執行finally後面的代碼,也就是說不會返回try繼續執行我們後續代碼。

比如我們for循環4臺設備,第一臺設備SSH登錄就報錯了,直接進入except異常處理,後面3臺相當於直接跳過了。

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

        except NetMikoTimeoutException:
            issue_message = (ipaddr + ': 網絡不可達 ')
            issue_device.append(issue_message)

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

使用netmiko連接網絡設備異常經常出現三種情況,設備不可達,認證錯誤,SSH端口異常,所以我把這些異常處理進行分類並寫入文件,這樣批量操作以後我就知道哪些設備有哪些問題進行批量處理。

那麼如何捕捉異常信息呢?比如我netmiko登錄設備時密碼錯誤,會提示我認證錯誤。

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

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

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

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

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

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內
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章