银狐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地址

image.png

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登录设备时密码错误,会提示我认证错误。

image

最后一行会提示我们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内
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容