美文网首页银狐NetDevOps
银狐NetDevOps-网络运维python篇之NETCONF(

银狐NetDevOps-网络运维python篇之NETCONF(

作者: 科技银狐 | 来源:发表于2021-05-20 21:19 被阅读0次
    科技银狐

    前言

    银狐DevNet系列会持续将网络运维工作中python的应用进行场景化的分享,因为每个单独的模块网上都有详细的教学,这里就不深入讲解模块基础了,内容主要以思路和示例为主,并将碰到的问题汇总提出注意事项。

    主要是因为网络工程师和网络运维工作者编程基础不强,加上网上对于这个领域的python资料又少,传统的分享方式(每个章节仅单纯分享一个知识点)对于很多网工来说各个知识点相对独立且割裂的,很难进行一个知识的融合,现实工作中也很难直接应用,大家学习的难度就会很大,也会导致大部分人刚入门就放弃。所以我将这些内容进行场景化,根据特定场景由浅入深不断优化,从而带出更多知识点,希望对大家有所帮助。

    这些分享都是我本人真实的学习路径,一方面是帮助自己梳理网络自动化相关知识,另一方面也希望可以通过分享我微不足道的学习过程和实战经验,帮助更多想要了解NetDevOps而苦于没有资料和环境被劝退的人,进而找到同行之人互相交流、互相提升。

    1、场景分析:

    NETCONF协议对于传统网工来说是噩梦,看到XML编码就直接劝退了,但对于普通网工来说依然有适用的场景。平时我们批量操作无非就是增删改查,针对设备增删改,个人建议直接使用python的netmiko模块,非常方便,也符合传统网工输入CLI的习惯。但对于查就需要区分场景了。

    当我们需要查询设备某些配置或者状态时,常规做法就是输入CLI,然后在返回结果中查看想要的内容。使用python进行跑批操作时也是通过paramiko、netmiko这类模块直接SSH上设备,然后输入CLI命令,在根据回显内容获取想要的数据。这里分几种情况,如果我们想获取设备配置文件,直接通过netmiko传递show config命令,其实是没什么问题的,因为这个回显的内容是不需要做任何处理的。

    那我们换一个场景,1000台网络设备,需要批量获取所有设备的设备名称、型号、版本号、补丁,并将内容存储起来时该怎么办呢?这里有3中方法。

    方法一:

    使用paramiko或者netmiko批量登录网络设备,并输入CLI(disp ver),将如下回显内容自行处理。

    Huawei Versatile Routing Platform Software
    VRP (R) software, Version 8.180 (CE6855HI V200R005C10SPC800)
    Copyright (C) 2012-2018 Huawei Technologies Co., Ltd.
    HUAWEI CE6855-48S6Q-HI uptime is 421 days, 13 hours, 24 minutes 
    Patch Version: V200R005SPH016
    
    CE6855-48S6Q-HI(Master) 1 : uptime is  421 days, 13 hours, 22 minutes
            StartupTime 2020/03/24   18:35:47+08:00
    Memory    Size    : 2048 M bytes
    Flash     Size    : 1024 M bytes
    CE6855-48S6Q-HI version information                               
    1\. PCB    Version : CEM48S6QP05    VER B
    2\. MAB    Version : 1
    3\. Board  Type    : CE6855-48S6Q-HI
    4\. CPLD1  Version : 102
    5\. BIOS   Version : 433
    
    

    显然,处理以上数据会非常麻烦

    方法二:

    使用netmiko这类SSH模块配合textFSM模板(结合ntc-template)进行操作(方法以后讲解),直接回显如下列表内容。

    [{'model': 'CE6855-48S6Q-HI',
      'product_version': 'CE6855HI V200R005C10SPC800',
      'uptime': '421 days, 9 hours, 24 minutes ',
      'vrp_version': '8.180'}]
    
    

    可以看到,非常方便。

    但问题就是这方面的模板cisco和juniper等国外厂商比较充足,基本涵盖了常见需求,国内华为只有4个模板,如下所示。

    -rw-rw-r-- 1 yydd   yydd   483 May  8 10:21 huawei_vrp_display_interface_brief.textfsm
    -rw-rw-r-- 1 yydd   yydd   1811 May  8 10:21 huawei_vrp_display_lldp_neighbor.textfsm
    -rw-rw-r-- 1 yydd   yydd   390 May  8 10:21 huawei_vrp_display_temperature.textfsm
    -rw-rw-r-- 1 yydd   yydd   217 May  8 10:21 huawei_vrp_display_version.textfsm
    
    

    也就是只有4个命令回显可以直接返回处理好的列表,显然是不够用的。(模板可自己编写,难度比较大)

    方法三:

    使用NETCONF协议,结合标准的XML编码格式,返回标准化格式的内容。而ncclient就是一个用于NETCONF客户端的Python库。

    2、操作环境:

    操作系统:Linux CentOS 7.4

    python版本:python 3.8

    网络设备:华为CloudEngine 6865

    编辑器:vscode

    安装ncclient:

    pip3 install ncclient
    
    

    3、代码示例

    #!/usr/bin/env python
    #coding: utf-8
    
    from pprint import pprint
    import xmltodict
    from ncclient import manager
    from ncclient import operations
    from ncclient.transport.errors import SSHError
    from ncclient.transport.errors import AuthenticationError
    
    #构造待配置的YANG内容,此处为系统信息。
    #具体可参考华为官网二次开发文档《CloudEngine 8800, 7800, 6800HI, 6880EI, 6875EI, 6870EI, 6865EI, 6860EI, 6857EI, 5880EI V200R005C10 NETCONF Schema API参考》
    
    devinfo_FILTER = '''
          <system xmlns="<http://www.huawei.com/netconf/vrp>" content-version="1.0" format-version="1.0">
          <systemInfo>
          </systemInfo>
        </system>
    '''
    
    # 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 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():
        nc_res = nc_get("172.26.32.7",22,"user","pass")
        xml_rep = nc_res.data_xml
        print(xml_rep)
    
    if __name__ == '__main__':
        main()
    
    

    执行结果

    <?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
        <system xmlns="<http://www.huawei.com/netconf/vrp>" format-version="1.0" content-version="1.0">
          <systemInfo>
            <sysName>SZTL-POD2-Leaf-H6865-1</sysName>
            <sysContact>R&amp;D Beijing, Huawei Technologies co.,Ltd.</sysContact>
            <sysLocation>Beijing China</sysLocation>
            <sysDesc>Huawei Versatile Routing Platform Software &#13;
    VRP (R) software, Version 8.191 (CE6865EI V200R019C10SPC800) &#13;
    Copyright (C) 2012-2020 Huawei Technologies Co., Ltd. &#13;
    HUAWEI CE6865-48S8CQ-EI &#13;</sysDesc>
            <sysObjectId>1.3.6.1.4.1.2011.2.239.49</sysObjectId>
            <sysGmtTime>1621568735</sysGmtTime>
            <sysUpTime>4125375</sysUpTime>
            <sysService>78</sysService>
            <platformName>VRP</platformName>
            <platformVer>V800R019C16SPC599</platformVer>
            <productName>CE6865EI</productName>
            <productVer>V200R019C10SPC800</productVer>
            <patchVer>V200R019SPH007</patchVer>
            <esn>2102351RFD10MC111521</esn>
            <mac>9017-3FF0-1CB1</mac>
            <lsRole>admin</lsRole>
            <authenFlag>false</authenFlag>
            <softwareName/>
          </systemInfo>
        </system>
      </data>
    
    

    可以看到回显内容结构非常清晰,需要什么数据直接从XML中获取即可。后面就以示例为基础,完成开头提到的需求。

    4、ncclient实验

    4.1 需求

    获取设备的设备名称、型号、版本号、补丁、SN

    4.2 代码

    #!/usr/bin/env python
    #coding: utf-8
    
    from pprint import pprint
    import xmltodict
    from ncclient import manager
    from ncclient import operations
    from ncclient.transport.errors import SSHError
    from ncclient.transport.errors import AuthenticationError
    
    #构造YANG
    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>
    '''
    
    #建立NETCONF会话
    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)
    
    #构造<get>报文
    def 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():
        nc_res = nc_get("172.26.32.7",22,"user","pass")
        xml_rep = nc_res.data_xml
        print(xml_rep)
    
        xml_dict = xmltodict.parse(xml_rep)
        for k,y in xml_dict.items():
            print(k,y)
        print("="*70)
    
            for k,y in xml_dict['data']['system']['systemInfo'].items():
                print(k,":",y)
    
    if __name__ == '__main__':
        main()
    
    

    执行结果

    <?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
        <system xmlns="<http://www.huawei.com/netconf/vrp>" format-version="1.0" content-version="1.0">
          <systemInfo>
            <sysName>SZTL-POD2-Leaf-H6865-1</sysName>
            <productName>CE6865EI</productName>
            <productVer>V200R019C10SPC800</productVer>
            <patchVer>V200R019SPH007</patchVer>
            <esn>2102351RFD10MC111521</esn>
          </systemInfo>
        </system>
      </data>
    
    data OrderedDict([('@xmlns', 'urn:ietf:params:xml:ns:netconf:base:1.0'), ('system', OrderedDict([('@xmlns', '<http://www.huawei.com/netconf/vrp>'), ('@format-version', '1.0'), ('@content-version', '1.0'), ('systemInfo', OrderedDict([('sysName', 'SZTL-POD2-Leaf-H6865-1'), ('productName', 'CE6865EI'), ('productVer', 'V200R019C10SPC800'), ('patchVer', 'V200R019SPH007'), ('esn', '2102351RFD10MC111521')]))]))])
    ======================================================================
    sysName : SZTL-POD2-Leaf-H6865-1
    productName : CE6865EI
    productVer : V200R019C10SPC800
    patchVer : V200R019SPH007
    esn : 2102351RFD10MC111521
    
    

    4.3 详解

    from pprint import pprint                 
    #有缩进的打印,回显更直观,建议使用
    
    import xmltodict                          
    #用于xml转换为dict
    
    #导入ncclient常用模块
    from ncclient import manager
    from ncclient import operations
    from ncclient.transport.errors import SSHError
    from ncclient.transport.errors import AuthenticationError
    
    
    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内容,此处为系统信息。 具体可参考华为官网二次开发文档《CloudEngine 8800, 7800, 6800HI, 6880EI, 6875EI, 6870EI, 6865EI, 6860EI, 6857EI, 5880EI V200R005C10 NETCONF Schema API参考》。

    如果我们只需要systemInfo下的部分信息,直接在<systemInfo></systemInfo>中间加入明细内容即可,可参考官方文档。

    关于XML基础知识,可以访问https://www.w3school.com.cn/xml/xml_intro.asp查看。

    
    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)
    
    

    定义NETCONF session的函数,调用manager.connect建立连接。

    def 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函数,构造<get>报文,并返回rpc-reply的结果。

    因为我们不希望get过多内容,所以要加入filter功能,devinfo_FILTER就是我们自己构建的XML,<filter>元素可以包含“type”属性,NETCONF中的默认过滤机制被称为子树过滤(“type”属性值为“subtree”)。

    打印结果一:

    #主函数
    def main():
        nc_res = nc_get("172.26.32.7",22,"user","pass")
        xml_rep = nc_res.data_xml   #返回XML标准格式的字符串
        print(xml_rep)
    
    #执行结果
    <?xml version="1.0" encoding="UTF-8"?><data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
        <system xmlns="<http://www.huawei.com/netconf/vrp>" format-version="1.0" content-version="1.0">
          <systemInfo>
            <sysName>SZTL-POD2-Leaf-H6865-1</sysName>
            <productName>CE6865EI</productName>
            <productVer>V200R019C10SPC800</productVer>
            <patchVer>V200R019SPH007</patchVer>
            <esn>2102351RFD10MC111521</esn>
          </systemInfo>
        </system>
      </data>
    
    

    打印结果二:

        xml_dict = xmltodict.parse(xml_rep)   
        #此方法会将xml_rep解析为orderdict,和传统dict区别就是orderdict是有顺序的
            for k,y in xml_dict.items():
            #遍历字典,items() 方法让字典以列表形式返回可遍历的(键, 值) 元组数组
           print(k,y)
    
    #执行结果
    data OrderedDict([('@xmlns', 'urn:ietf:params:xml:ns:netconf:base:1.0'), ('system', OrderedDict([('@xmlns', '<http://www.huawei.com/netconf/vrp>'), ('@format-version', '1.0'), ('@content-version', '1.0'), ('systemInfo', OrderedDict([('sysName', 'SZTL-POD2-Leaf-H6865-1'), ('productName', 'CE6865EI'), ('productVer', 'V200R019C10SPC800'), ('patchVer', 'V200R019SPH007'), ('esn', '2102351RFD10MC111521')]))]))])
    
    

    打印结果三:

    #访问xml_dict['data']['system']['systemInfo']的value
    #OrderedDict([('sysName', 'SZTL-POD2-Leaf-H6865-1'),
    # ('productName', 'CE6865EI'),
    # ('productVer', 'V200R019C10SPC800'), 
    # ('patchVer', 'V200R019SPH007'),
    # ('esn', '2102351RFD10MC111521')])
    #在进行遍历操作
    
    for k,y in xml_dict['data']['system']['systemInfo'].items():
        print(k,":",y)
    
    #打印结果
    sysName : SZTL-POD2-Leaf-H6865-1
    productName : CE6865EI
    productVer : V200R019C10SPC800
    patchVer : V200R019SPH007
    esn : 2102351RFD10MC111521
    
    

    上面的逐步打印,是为了让大家更清晰的看到每一步数据处理的区别。

    核心还是提供思路,详细的基础知识如果有不懂的,直接在Google或者baidu搜索,有很多资料。

    相关文章

      网友评论

        本文标题:银狐NetDevOps-网络运维python篇之NETCONF(

        本文链接:https://www.haomeiwen.com/subject/cynbjltx.html