网络运维python之NETCONF--协程gevent+ncclient,2分钟巡检几千台华为CE交换机

本文主要是介绍网络运维python之NETCONF--协程gevent+ncclient,2分钟巡检几千台华为CE交换机,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:科技银狐
原文连接:https://zhuanlan.zhihu.com/p/378012466

01 场景介绍

本章节介绍大规模数据中心巡检任务跑批策略,之前的章节介绍过NETCONF这类API接口相比SSH登录取返回结果的优势,除了返回结果是标准化XML编码以外,其实NETCONF在速度上也有很大的优势。所以在大规模数据中心(几千、几万台网络设备)进行网络巡检时,推荐使用NETCONF,结合协程gevent异步的特性,进行大并发跑批,几千台设备仅需几分钟就可结束任务。

国外主流厂商Cisco和Juniper的API类示例在Google、github上有大量文章可以借鉴,而国内华为这类技术分享比较少,所以我这边主要介绍下华为网络设备的实现思路和实现方式,目前华为CE系列的交换机基本都支持NETCONF协议,如果数据中心大批量采用华为CE设备,那下面的内容应该对你有所帮助。

02 需求分析

需要针对数据中心内部华为CE交换机进行跑批操作,获取上千台设备hostname、型号、版本、补丁、SN号,我们先列出这个任务的逻辑:

根据需求创建YANG模板,可直接查阅华为官网NETCONF Schema API参考,非常齐全;
读取CMDB资产信息(txt、excel、系统API),获得需要跑批设备的IP地址列表;本章节用excel的方式举例,格式如下图所示:
在这里插入图片描述

  1. 使用协程gevent调用IP列表,实现大并发的跑批任务;
  2. 筛选response内容中需要的数据,写入excel中,并进行保存。

03 代码示例

#!/usr/bin/env python
#coding: utf-8import time
import sys
import os
from datetime import datetime
from gevent import monkey;monkey.patch_all()
from gevent import monkey,spawn
import gevent
from gevent.pool import Pool
from collections import OrderedDict
from openpyxl import Workbook
from openpyxl import load_workbook
import xmltodict
from ncclient import manager
from ncclient import operations
from ncclient.transport.errors import SSHError
from ncclient.transport.errors import AuthenticationErrordevinfo_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>
'''class ReadDeviceInfo(object):def __init__(self):      self.devices_filename = ('/pipenv_projects/py3/01-devnet/01-netpy/info02.xlsx')self.wb1 = load_workbook(self.devices_filename)self.ws1 = self.wb1.get_sheet_by_name("device list")def read_device_excel(self):ip_list = []for cow_num in range(2,self.ws1.max_row+1):ipaddr = self.ws1["b"+str(cow_num)].valueip_list.append(ipaddr)return ip_listdef write_to_excel(self,device_ip,nc_list):new_cow_num = devices_list.index(device_ip) + 2print("--------writing to excel------------{}: {}".format(new_cow_num,device_ip))self.ws1["d"+str(new_cow_num)] = nc_list[0]["sysName"]self.ws1["e"+str(new_cow_num)] = nc_list[0]["productName"]self.ws1["f"+str(new_cow_num)] = nc_list[0]["productVer"]self.ws1["g"+str(new_cow_num)] = nc_list[0]["patchVer"]self.ws1["h"+str(new_cow_num)] = nc_list[0]["esn"]return# 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 hw_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(hostip):print("---get information of device: {}".format(hostip))xml_rep = hw_nc_get(hostip,830,"user","pass").data_xmlxml_dict = xmltodict.parse(xml_rep)nc_list = []nc_dict = (dict((x,y) for x,y in xml_dict['data']['system']['systemInfo'].items()))nc_list.append(nc_dict)devices.write_to_excel(hostip,nc_list)#===================================================================
#ncclient抓取华为设备信息,并存入excel中
#===================================================================
if __name__ == '__main__':starting_time = time.time()devices = ReadDeviceInfo()devices_list = devices.read_device_excel()pool = Pool(5)pool.map(main,devices_list)                                 #map(func, iterable)pool.join()devices.wb1.save('info02.xlsx')print ('\\n---- End get config threading, elapsed time=', time.time() - starting_time)

04 代码详解

为了更好的理解,本次不按照从上至下的顺序分解,而是按照代码逻辑的顺序讲解。

import time
import sys
import os
from datetime import datetime
from gevent import monkey;monkey.patch_all()
from gevent import monkey,spawn
import gevent
from gevent.pool import Pool
from collections import OrderedDict
from openpyxl import Workbook
from openpyxl import load_workbook
import xmltodict
from ncclient import manager
from ncclient import operations
from ncclient.transport.errors import SSHError
from ncclient.transport.errors import AuthenticationError

常规步骤,先导入需要使用的模块,gevent是协程模块,openpyxl是处理excel使用的模块,协程推荐使用gevent,因为不需要重构代码,导入monkey.patch_all()就能使用,非常友好。

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>
'''

构建YANG模板,华为不像Cisco和juniper那样可以登录设备通过CLI(比如show version | display xml)直接解析XML输出格式,只能通过官方文档获取。登录华为官方网站,在文档的二次开发中搜索《CloudEngine 8800, 7800, 6800HI, 6880EI, 6875EI, 6870EI, 6865EI, 6860EI, 6857EI, 5880EI V200R005C10 NETCONF Schema API参考》就好,里面YANG模板非常详细。

如下图所示,需求是获取设备信息,找到系统信息,get方法里的请求示例,直接使用system命名空间内容即可。

在这里插入图片描述

#===================================================================
#ncclient抓取华为设备信息,并存入excel中
#===================================================================
if __name__ == '__main__':starting_time = time.time()#为了任务执行时间,需要在程序首位2个地方打点,最后相减得到代码执行时间。devices = ReadDeviceInfo()#对象实例化devices_list = devices.read_device_excel()#获取设备IP地址的listpool = Pool(5)#定义pool数量,这种方式的好处是能控制并发数量,根据CPU情况调节pool.map(main,devices_list)                                 #map方法需要传递2个参数,第一个是整个跑批任务的主函数,第二个是可迭代参数,一般使用IP地址listpool.join()#等待协程结束,确保所有任务终止devices.wb1.save('info02.xlsx')#主函数运行完成,保存excel内容print ('\\n---- End get config threading, elapsed time=', time.time() - starting_time)

以上为主程序详解,用注释的方式进行说明,主要是为了让协程gevent调用我们主要的任务(主函数main)。

def main(hostip):print("---get information of device: {}".format(hostip))#打印这行内容,主要是判断传入的IP地址是否正确xml_rep = hw_nc_get(hostip,830,"user","pass").data_xml#调用函数hw_nc_get,得到的结果是<class 'ncclient.operations.retrieve.GetReply'>,#所以需要data.xml方法将内容转为字符串,最终得到的是xml编码格式的字符串。xml_dict = xmltodict.parse(xml_rep)#直接将xml内容解析为dict,所有数据就很方便处理了,xmltodict方法得到的是orderdict,#简单来说就是一种有顺序的dict,所以可以直接迭代。nc_list = []#定义一个list,方便后面把hostname,sn,version等信息存储,#以下内容在前面的文章讲解过,可以先查阅先前的内容。nc_dict = (dict((x,y) for x,y in xml_dict['data']['system']['systemInfo'].items()))#每台设备的所有信息存储为字典,如下所示:#{'sysName': 'xxxx', 'productName': 'CE6855HI', 'productVer': 'xxxx', 'patchVer': 'xxxx', 'esn': 'xxxx'}nc_list.append(nc_dict)#因为本人很多方法都是标准化直接传参即可,所以我这边将结果存储为list,传递给下一个方法,这块不强求,直接传递dict也是可以的。devices.write_to_excel(hostip,nc_list)#设备IP地址和get获取的设备信息(list、dict都可以),传入write_to_excel方法,我传递的是list。
上面的主函数有个代码简写了,这里说明一下:for k,y in xml_dict['data']['system']['systemInfo'].items():#将systeminfo的value元组化,并用k,y去for循环,得到的数据类似下面的样式:# ('productName', 'xxx'),# ('productVer', 'xxxx'), # ('patchVer', 'xxxx'),# ('esn', 'xxxx')])nc_dict = (dict((x,y) for x,y in xml_dict['data']['system']['systemInfo'].items()))#其实就是将上面的结果存为dict

面向对象内容====================================================

class ReadDeviceInfo(object):def __init__(self):  #初始化属性    self.devices_filename = ('D:/pipenv_projects/py3/01-devnet/01-netpy/info02.xlsx')self.wb1 = load_workbook(self.devices_filename)self.ws1 = self.wb1.get_sheet_by_name("device list")def read_device_excel(self):#读取excel中的IP列表ip_list = []for cow_num in range(2,self.ws1.max_row+1):ipaddr = self.ws1["b"+str(cow_num)].valueip_list.append(ipaddr)return ip_listdef write_to_excel(self,device_ip,nc_list):#获取的设备信息写入excelnew_cow_num = devices_list.index(device_ip) + 2print("--------writing to excel------------{}: {}".format(new_cow_num,device_ip))self.ws1["d"+str(new_cow_num)] = nc_list[0]["sysName"]self.ws1["e"+str(new_cow_num)] = nc_list[0]["productName"]self.ws1["f"+str(new_cow_num)] = nc_list[0]["productVer"]self.ws1["g"+str(new_cow_num)] = nc_list[0]["patchVer"]self.ws1["h"+str(new_cow_num)] = nc_list[0]["esn"]return

这里使用了class类,这块内容之前没讲解过,为了方便我把excel的内容定义成一个类,然后进行实例化操作。这里不是本章重点,所以我就简单介绍下类的意思。

python的优势是面向对象,有三个特性,封装、继承、多态,主要是较少重复代码的问题,这其中的灵魂就是定义类,比如你设计飞机,class类就是你的图纸,造飞机需要知道飞机的属性,比如是红色还是黄色的,这个就是属性,还要知道怎么造这个飞机,比如机翼接到机身上,这个就是方法(类似于平时我们的def函数),平时见到的类属性和类方法大概是这个意思。

这里我把excel内容定义为初始化属性,每次调用类方法的时候都会加载这个excel内容,然后进行excel的读写操作。

如果确实对面向对象不太理解也无妨,上面的代码直接把class删除,把所有def函数前面的缩进取消,把所有self内容删除,直接当函数用。然后把属性放在主程序上当全局参数,变成下面的样子是不是就容易理解了,也可以看下class类和不用class的区别。

def read_device_excel():#读取excel中的IP列表,因为我的IP地址在B列,所以下面获取的是B列的valueip_list = []for cow_num in range(2,ws1.max_row+1):#遍历B列IP地址,因为第一行内容不需要,所以我们range(2,最大行),这里有个需要注意的点,#比如有10行数据,range(2,10)其实只遍历到第9行,所以我们需要最大行+1ipaddr = ws1["b"+str(cow_num)].valueip_list.append(ipaddr)return ip_listdef write_to_excel(device_ip,nc_list):
#获取的设备信息写入excelnew_cow_num = devices_list.index(device_ip) + 2
#我们获取到设备信息要写入excel,但是这个信息写入到第几行呢?
#我们读取excel设备信息时,用for循环获取列表是有顺序的,这个顺序是从上至下的,
#正常情况下获取的信息写入excel时,第1台设备信息写入第2行,第2台设备信息写入第3行可以的,
#但是协程大并发场景下,这个顺序是随机的。
#我先给A1发get请求,然后不等待直接给A2发送请求,这个时候很可能A2先进行response,如果我把得到的
#信息按照从上至下的顺序写入excel,内容就乱了。
#所以我们需要根据IP地址使用index方法找到索引位置,然后写入相应的位置。print("--------writing to excel------------{}: {}".format(new_cow_num,device_ip))ws1["d"+str(new_cow_num)] = nc_list[0]["sysName"]#比如sheet1,D2内容 = 传入nc_list参数的sysName,因为我传入的是list,所以要加个索引[0]#D2这个行数就是靠index定位的ws1["e"+str(new_cow_num)] = nc_list[0]["productName"]ws1["f"+str(new_cow_num)] = nc_list[0]["productVer"]ws1["g"+str(new_cow_num)] = nc_list[0]["patchVer"]ws1["h"+str(new_cow_num)] = nc_list[0]["esn"]#returnif __name__ == '__main__':starting_time = time.time()devices_filename = ('/pipenv_projects/py3/01-devnet/01-netpy/info02.xlsx')wb1 = load_workbook(devices_filename)#定义wb1加载工作簿ws1 = self.wb1.get_sheet_by_name("device list")#定义工作表ws1,就是加载我们的sheet1(device list是sheet名称)pool = Pool(1)pool.map(main,devices_list)                                 #map(func, iterable)pool.join()devices.wb1.save('info02.xlsx')#注意保持,不然excel没变化。print ('\\n---- End get config threading, elapsed time=', time.time() - starting_time)

如下内容前两章讲过,就不重复了。

# 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 hw_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 information of device: 10.7.1.1
---get information of device: 10.7.1.2
---get information of device: 10.7.1.3
---get information of device: 10.7.1.4
--------writing to excel------------3: 10.7.1.1
--------writing to excel------------2: 10.7.1.2
--------writing to excel------------4: 10.7.1.3
--------writing to excel------------5: 10.7.1.4---- End get config threading, elapsed time= 5.876776933670044

还没了解面向对象的不用关注,只用主程序+函数的方式写代码也可满足大部分工作,随着我们代码量的增加,需要考虑如何减少重复代码提高效率的时候在去关注面向对象就好。

这篇关于网络运维python之NETCONF--协程gevent+ncclient,2分钟巡检几千台华为CE交换机的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/940840

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

poj 3181 网络流,建图。

题意: 农夫约翰为他的牛准备了F种食物和D种饮料。 每头牛都有各自喜欢的食物和饮料,而每种食物和饮料都只能分配给一头牛。 问最多能有多少头牛可以同时得到喜欢的食物和饮料。 解析: 由于要同时得到喜欢的食物和饮料,所以网络流建图的时候要把牛拆点了。 如下建图: s -> 食物 -> 牛1 -> 牛2 -> 饮料 -> t 所以分配一下点: s  =  0, 牛1= 1~

nudepy,一个有趣的 Python 库!

更多资料获取 📚 个人网站:ipengtao.com 大家好,今天为大家分享一个有趣的 Python 库 - nudepy。 Github地址:https://github.com/hhatto/nude.py 在图像处理和计算机视觉应用中,检测图像中的不适当内容(例如裸露图像)是一个重要的任务。nudepy 是一个基于 Python 的库,专门用于检测图像中的不适当内容。该

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了

poj 2112 网络流+二分

题意: k台挤奶机,c头牛,每台挤奶机可以挤m头牛。 现在给出每只牛到挤奶机的距离矩阵,求最小化牛的最大路程。 解析: 最大值最小化,最小值最大化,用二分来做。 先求出两点之间的最短距离。 然后二分匹配牛到挤奶机的最大路程,匹配中的判断是在这个最大路程下,是否牛的数量达到c只。 如何求牛的数量呢,用网络流来做。 从源点到牛引一条容量为1的边,然后挤奶机到汇点引一条容量为m的边