Netmiko终极宝典

《从零开始NetDevOps》是本人8年多的NetDevOps实战总结的一本书(且称之为书,通过公众号连载的方式,集结成册,希望有天能以实体书的方式和大家相见)。

NetDevOps是指以网络工程师为主体,针对网络运维场景进行自动化开发的工作思路与模式,是2014年左右从国外刮起来的一股“网工学Python"的风潮,最近几年在国内逐渐兴起。本人在国内某大型金融机构的数据中心从事网络自动化开发8年之久,希望能通过自己的知识分享,给大家呈现出一个不同于其他人的实战为指导、普适性强、善于抠细节、知其然知其所以然风格、深入浅出的NetDevOps知识体系,给大家一个不同的视角,一个来自于实战中的视角。

由于时间比较仓促,文章中难免有所纰漏,敬请谅解,同时笔者也会在每个章节完成后进行修订再发布,欢迎大家持续关注

本系列文章会连载于“NetDevOps加油站”公众号,欢迎大家点赞关注
在这里插入图片描述

第三章 基于Netmiko的网络设备交互

3.1 Netmiko简介及安装

网工与网络设备最习惯的交互方式就是CLI,通过SSH或者Telnet登录到设备,执行命令,实现信息的获取和配置的推送,是网工最熟悉的工作方式。

所以基于CLI的网络自动化开发,也成为了网工入门NetDevOps的必经之路与最优之解。

Python基于CLI模式与网络设备进行交互的工具包有很多,而netmiko与paramiko无疑是这类工具包中的两颗璀璨明珠。

本章节我们将介绍一下netmiko,它是工程师Kirk Byers 于2015年发布的一个用于简化众多厂商网络设备CLI连接(ssh、telnet、serial)的工具类。实际2015年的版本只支持ssh,所以它最早是为了简化ssh通用工具类paramiko的连接和操作(后续netmiko已经支持了telnet和serial),所以它的名字从中取了"miko",又因其垂直于网络自动化领域,所以又添加了“net”,组成了netmiko的名称。

相较paramiko,netmiko有着更加简化的操作和更加针对网络设备的高阶封装。通过抽象一些底层的状态控制,消除查看配置和改变配置的在一众平台中的差异,目前支持的厂商平台覆盖了日常网络运维所需,所以笔者更建议新手使用netmiko,让我们更聚焦在网络业务逻辑层面,这些我们也会在后续的使用中都将体会到。

经过7年的迭代,netmiko进入到了4.0时代,增加了很多非常优秀的方法,支持非常灵活的参数配置。

由于netmiko4.0近期发布,针对国产设备有一些小的bug(比如执行成功,但是不返回回显),同时考虑到4.0版本添加的参数和方法对对新手而言使用成本偏高,且上个版本也可以通过其他方法达到类似效果,所以笔者选择比较稳定、使用比较广泛的3.4.0版本来进行netmiko的相关介绍,本章节介绍的netmiko3.4.0的主要方法在4.0及以上版本是兼容的。

我们先使用pip进行netmiko的安装,并指定版本3.4.0,指定版本的方式是在包名后面加上两个等号后接版本号。

 pip install netmiko==3.4.0

我们打开一个交互式的窗口,或者编写一个脚本,导入netmiko的对应函数没有报错,代表安装成功。

from netmiko import Netmiko

3.2 支持的网络设备平台

netmiko针对主流的网络设备平台进行了适配,编写了对应的驱动类,这些驱动类提供了很多便捷的方法,比如登录的时候帮我们检查一下是否登录完成,自动帮助我们输入用户名密码,自动帮我们取消分页,执行命令的时候自动帮我们判断回显是否结束,从文件中读取配置等等。

这些就是驱动类的作用,netmiko经过了7年的发展和沉淀从最初的不到10个驱动类,到今天已经壮大到了110个驱动类。适配了市面上主流的网络设备平台,且其高度的封装,也可以让用户比较方便的编写出自己的驱动类。

Netmiko支持的110个驱动类主要分为三大类:

Regularly tested(定期测试)

每次netmiko发版都会对相关设备平台进行完整的测试,在netmiko中有完整的测试脚本。

image-20220606164306855

这些平台有Arista vEOS、Cisco ASA、Cisco IOS、Cisco IOS、XE、Cisco IOS、XR、Cisco NX、OS、Cisco SG300、HP ProCurve、Juniper Junos、Linux。这里面的设备以国外的平台为主,思科居多。

Limited testing(有限测试)

不进行完整的测试,在某些时间点对特定配置与操作回显进行测试。作为开发者没有那么多的网络设备用于测试,所以在适配后,仅在某些时间点(特定版本)进行基础功能的测试。这些平台有6Wind、Adtran OS、Alcatel AOS6/AOS8、Apresia Systems AEOS、Broadcom ICOS、Calix B6、Centec Networks、Cisco AireOS (Wireless LAN Controllers)、CloudGenix ION、Dell OS9 (Force10)、Dell OS10、Dell PowerConnect、Ericsson IPOS、Extreme ERS (Avaya)、Extreme VSP (Avaya)、Extreme VDX (Brocade)、Extreme MLX/NetIron (Brocade/Foundry)、HPE Comware7、Huawei、Huawei OLT、Huawei SmartAX、IP Infusion OcNOS、Juniper ScreenOS、Mellanox、MikroTik RouterOS、MikroTik SwitchOS、NetApp cDOT、Netgear ProSafe、Nokia/Alcatel SR OS、OneAccess、Palo Alto PAN、OS、Pluribus、Ruckus ICX/FastIron、Ruijie Networks、Supermicro SMIS、TPLink JetStream、Ubiquiti EdgeSwitch、Vyatta VyOS、Yamaha、ZTE ZXROS

有限测试的设备平台中,会出现华为、华三、锐捷等主流国产品牌的众多系列,根据笔者在日常使用中的情况来看,基本满足配置的采集和推送,复杂一些的需求也可以通过netmiko提供的灵活的参数来实现。

Experimental(实验性质)

实验性能意味着只是对设备进行了基础的适配,没有相应的单元测试。这些设备平台有A10、Accedian、Allied Telesis AlliedWare Plus、Aruba、Brocade Fabric OS、C-DOT CROS、Ciena SAOS、Citrix Netscaler、Cisco Telepresence、Check Point GAiA、Coriant、Dell OS6、Dell EMC Isilon、Eltex、Enterasys、Endace、Extreme EXOS、Extreme Wing、Extreme SLX (Brocade)、F5 TMSH、F5 Linux、Fortinet、MRV Communications OptiSwitch、MRV LX、Nokia/Alcatel SR-OS、QuantaMesh、Rad ETX、Raisecom ROAP、Sophos SFOS、Ubiquiti Unifi Switch、Versa Networks FlexVNF、Watchguard Firebox、6WIND TurboRouter。

这类设备比较常见的可能是F5的两种模式的驱动。笔者日常接触不是很多,主要用于配置的信息收集也是问题不大。

以上就是netmiko支持的设备类型,覆盖了足足有110大类的驱动。基本覆盖了网工日常使用的常见网络设备,netmiko支持telnet、ssh协议的CLI,但是部分设备的telnet是不支持的,支持telnet的设备平台是36种,但也覆盖了思科、华为、华三、Juniper的主要设备平台。同时考虑到出于安全考虑,大部分网络设备已经以ssh协议为主,所以本章节讲解的CLI以ssh协议为主。对于不支持的,笔者后续也会补充一些paramiko和telnlib的内容。

3.3 创建连接

我们在对设备进行操作之前首先要登录到设备,这个时候我们需要借助于一个函数ConnectHandler,从命名风格而言是大驼峰命名法(单词间通过大小写区分,每个单词首字母大写,长得像驼峰),但它实打实的是一个函数,它返回的是到网络设备的一个长连接对象。

关于ConnectHandler函数的参数分为device_type和其他连接驱动类实例化所需参数。

device_type即我们之前所说的设备平台也可以翻译为设备类型,是由字符串表示。

连接驱动类实例化所需参数主要包括创建ssh连接所需的设备IP、用户名、密码、连接端口号等等。

代码示例如下:

from netmiko import ConnectHandler

conn = ConnectHandler(device_type='cisco_ios',
                      host='192.168.137.201',
                      username='netdevops',
                      password='admin123!',
                      port=22)

print(conn)
'''以上输出一个实际的连接对象
<netmiko.cisco.cisco_ios.CiscoIosSSH object at 0x000002DBC9F23F10>
'''
conn.disconnect()

这个代码相较于其他的ssh工具更符合网工的思维模式,在传参的时候,如果参数过多,挤在一行会影响可读性,通过适当的换行,对齐参数,可以有效提高代码可读性,我们使用了哪些参数,赋值了哪些值,都一目了然。

这段代码仍有优化的空间,由于是打开一个到设备的长连接,为了节省资源,我们应该在程序结束时关闭连接,这个时候又可以使用with上下文管理了,我们习惯将打开的连接通过as起一个别名conn,这个conn就是到这个网络设备的一个连接

with上下文管理器的本质是在创建对象后调用了对象的__enter__方法,代码块结束的时候自动帮助我们调用with管理的对象的__exit__方法,只要实现了此方法的类创建的对象,均可以使用with进行上下文管理。netmiko就实现了这两个方法,在使用with上下文管理创建netmiko连接对象后,调用__enter__方法将连接对象"自己"(回想在类与对象章节中的self)返回,在离开with上下文管理后,它对象的__exit__方法,这个方法又调用了“自己”的disconnect方法,实现了断开连接的效果。示例:

from netmiko import ConnectHandler

with ConnectHandler(device_type='cisco_ios',
                    host='192.168.137.201',
                    username='netdevops',
                    password='admin123!',
                    port=22) as conn:
    print(conn)

print(conn.is_alive())
'''以上代码会输出
<netmiko.cisco.cisco_ios.CiscoIosSSH object at 0x000002570EB84E50>
False
'''

我们通过is_alive这个方法进行了判断,结果显示连接已经断开,这可以有效防止因为程序导致的过多用户登录设备而未释放连接而引发其他问题。

关于这段参数我们还可以在调用ConnectHandler时将参数的赋值方式进行优化,其基本方法是先定义一个字典,包含了ConnectHandler所需的参数,这些参数作为key,然后value是我们期望赋的值,调用ConnectHandler函数的时候,将这个字典前加双星号**传入,等同于上面脚本的效果。示例:

from netmiko import ConnectHandler

dev = {
   'device_type': 'cisco_ios',
       'host': '192.168.137.201',
       'username': 'netdevops',
       'password': 'admin123!',
       'port': 22}

with ConnectHandler(**dev) as conn:
    print(conn)
'''以上代码会输出
<netmiko.cisco.cisco_ios.CiscoIosSSH object at 0x000002570EB84E50>
'''

这种双星展开赋值的方式,可以使代码的可读性进一步提高,参数赋值变的更简单。

“连接”背后的逻辑

那netmiko在ConnectHandler函数中究竟做了什么,让它可以创建众多设备的网络连接呢?

这段内容仅试图讲清楚netmiko背后的逻辑,方便我们在某些特定场合进行debug,或者是编写自己的驱动类,对于普通用户如果觉得过于费解,也可以直接跳过,或等能力足够的时候再回过头来看看。

示意图:

image-20220606233902532

用户创建连接网络设备传入众多参数,其中device_type用于判断该使用哪个驱动类(netmiko的110个驱动类)。

# netmiko/ssh_dispatcher.py 
def ConnectHandler(*args, **kwargs):
    """Factory function selects the proper class and creates object based on device_type."""
    device_type = kwargs["device_type"]
    if device_type not in platforms:
        if device_type is None:
            msg_str = platforms_str
        else:
            msg_str = telnet_platforms_str if "telnet" in device_type else platforms_str
        raise ValueError(
            "Unsupported 'device_type' "
            "currently supported platforms are: {}".format(msg_str)
        )
    # 根据device_type获取连接类
    ConnectionClass = ssh_dispatcher(device_type)
    # 透传所有参数,实例化连接类
    return ConnectionClass(*args, **kwargs)

在ssh_dispatcher函数中,有一个关键的名为CLASS_MAPPER的字典,将各类名称的字符串映射到了各个驱动类(我们之前在字典部分说过,dict的值可以是任意数据结构,包括类,甚至是方法)。

# netmiko/ssh_dispatcher.py 
def ssh_dispatcher(device_type):
    # 根据传入的设备类型映射到对应的连接类并返回
    """Select the class to be instantiated based on vendor/platform."""
    return CLASS_MAPPER[device_type]

CLASS_MAPPER是经过一系列加工,最终形如下的一个字典:

CLASS_MAPPER = {
   
    "cisco_asa": CiscoAsaSSH,
    "cisco_ftd": CiscoFtdSSH,
    "cisco_ios": CiscoIosSSH,
    "cisco_nxos": CiscoNxosSSH,
    "cisco_wlc": CiscoWlcSSH,
    "cisco_xe": CiscoIosSSH,
    "cisco_xr": CiscoXrSSH,
    "f5_ltm": F5TmshSSH,
    "f5_tmsh": F5TmshSSH,
    "f5_linux": F5LinuxSSH,
    "fortinet": FortinetSSH,
    "hp_comware": HPComwareSSH,
    "hp_procurve": HPProcurveSSH,
    "huawei": HuaweiSSH,
    "huawei_smartax": HuaweiSmartAXSSH,
    "huawei_olt": HuaweiSmartAXSSH,
    "huawei_vrpv8": HuaweiVrpv8SSH,
    "juniper": JuniperSSH,
    "juniper_junos": JuniperSSH,
    "juniper_screenos": JuniperScreenOsSSH,
    "linux": LinuxSSH,
    "ovs_linux": OvsLinuxSSH,
    "ruijie_os": RuijieOSSSH,
    "vyatta_vyos": VyOSSSH,
    "vyos": VyOSSSH,
    "zte_zxros": ZteZxrosSSH,
}

每个成员的value都是一个厂商系列的连接驱动类。然后netmiko将实例化连接所需的参数再透传给了具体的驱动类,实际device_type也会被传给驱动类,但是主要是用于判断使用ssh还是telnet协议,暂时不在我们讨论范围,先跳过。

各种驱动类通过构造函数(初始化方法)来进行一系列登录设备所需的操作及登录后的一些操作,这些操作调用了paramiko打开了一个ssh隧道,然后输入用户名密码实现登录,之后netmiko还会帮助我们做一些事情,比如读取banner,执行取消分页的操作,判断登录之后的提示符(一般多为设备名加#,>,]等),这些操作在不同的驱动中大同小异,会稍微有出入。执行完这些操作后,连接就创建了,返回了一个连接类对象。

如何赋值device_type?

实例化的时候,我们的device_type该如何赋值以便能使用准确的驱动呢?这其实是一个经验活儿。

首先关于device_type可以取的值,我们需要去看CLASS_MAPPER。CLASS_MAPPER实质为一个字典,key为device_type,value为对应的Connection驱动类,在这个文件中记录了各个device_type所对应的驱动类。限于篇幅做了上述代码中的映射关系删减,保留了大家可能遇到的。

比如笔者常用的是huawei、cisco_ios等。通过字面我们也可以大体判断出每个平台使用的哪个驱动,比如思科的nexus系列设备应该使用cisco_nxos作为device_type的值,而华为的大部分设备如CE系列交换机使用huawei作为device_type,Juniper的junos系列可以使用juniper,锐捷的使用ruijie_os作为device_type,诸如此类。同时我们也有一个netmiko的方法可以判断出此设备netmiko是否支持,该使用哪种驱动,这种方法我们在后续的netmiko的“疑难杂症”篇进行讲解。

如果相对应的厂商型号netmiko支持telnet协议,则在对应的device_type值后添加_telnet即可,比如华为CE交换机的驱动是“huawei”(当然我们也可以写作“huawei_ssh”),默认是走SSH协议,在device_type值后面我们可以追加协议类型,比如使用telnet,则device_type值应为“huawei_telnet”,netmiko则会调用对应的telnet连接类。

连接类初始化参数详解

创建连接的示例中我们还有很多其他参数,他们实际是用于创建连接的关键参数,对应了各个驱动类的__init__方法中的参数。

我们先看一段代码

# netmiko/base_connection.py     
class BaseConnection(object):
    """
    Defines vendor independent methods.

    Otherwise method left as a stub method.
    """

    def __init__(
        self,
        ip="",
        host="",
        username="",
        password=None,
        secret="",
        port=None,
        device_type="",
        verbose=False,
        global_delay_factor=1,
        global_cmd_verify=None,
        use_keys=False,
        key_file=None,
        pkey=None,
        passphrase=None,
        allow_agent=False,
        ssh_strict=False,
        system_host_keys=False,
        alt_host_keys=False,
        alt_key_file="",
        ssh_config_file=None,
        #
        # Connect timeouts
        # ssh-connect --> TCP conn (conn_timeout) --> SSH-banner (banner_timeout)
        #       --> Auth response (auth_timeout)
        conn_timeout=5,
        auth_timeout=None,  # Timeout to wait for authentication response
        banner_timeout=15,  # Timeout to wait for the banner to be presented (post TCP-connect)
        # Other timeouts
        blocking_timeout=20,  # Read blocking timeout
        timeout=100,  # TCP connect timeout | overloaded to read-loop timeout
        session_timeout=60,  # Used for locking/sharing the connection
        keepalive=0,
        default_enter=None,
        response_return=None,
        serial_settings=None,
        fast_cli=False,
        _legacy_mode=True,
        session_log=None,
        session_log_record_writes=False,
        session_log_file_mode="write",
        allow_auto_change=False,
        encoding="ascii",
        sock=None,
        auto_connect=True,
    ):
        ...

这个类就是netmiko的所有连接类的基类(可以理解为这个netmiko连接家族的老祖宗),它的构造方法中有着众多的参数,用于去创建一个连接对象,即登录到一台设备。笔者根据实际使用,认为需要重点关注的是以下参数:

说明 参数名
ip 设备IP地址
host 设备host名称,需要可以解析出IP地址
username 用户名
password 密码
secret enable密码,提权时需要输入的密码
port 端口,会根据device_type自动判断(如有“ssh”字符串是22,如有“telnet”是23),也可以用户指定
device_type 设备的驱动名称
conn_timeout 连接超时时间,默认为5秒,如果网络条件不好,建议适当增加,尤其是广域网或者国际网络
timeout 执行命令的超时时间,根据情况适当延长,默认为100秒
session_log 记录log的路径,如填写则会将与设备的所有操作记录
session_log_file_mode 记录log的模式,覆盖"write" ,追加 “append”,默认覆盖
global_delay_factor 默认的全局的延迟因子,值为1,结合后续篇章了解,在这里引出,在某些场景需要它参与计算,但是一般不修改。
fast_cli 快速模式,默认False,不开启,netmiko内部提供一种优化性能的方式,设置为True后,在与设备交互过程中读取隧道中信息的频率会加快(全局延迟因子与单个方法中的延迟因子取较小值)。

ip和host两个值最终会赋值给连接对象的host属性(self.host),ip或者host尽量写一个即可,如果两个都写self.host会采用ip的值。

port是对应连接协议的端口号,netmiko会根据device_type来判断,如果device_type中没有“telnet”,则端口号默认值为22,如果用户赋值了端口号,则采用用户传入的端口号。

用户名密码不用赘述,关于密码的保护,建议代码和密码配置文件分离,或者是在Python代码中使用getpass模块的getpass函数传入密码。

>>> import getpass
>>> x=getpass.getpass()
Password:

secret是类似enable密码的字段,用于给当前用户升权。默认空字符串,只有调用连接对象的enable方法时才会去读取这个字段。

创建连接的时候conn_timeout和timeout一定要根据实际情况进行适当延长:比如show running-config或者display current,当配置量比较大,设备回显会比较慢,有时候需要讲timeout设置为120(两分钟);当设备因为各种原因(比如在两个相隔很远的物理位置)导致登录时间比较长的时候,需要适当调整conn_timeout。

在后续执行信息收集和配置推送的时候,我们可以通过session_log进行完整的操作记录,以便debug,比如排查脚本为什么执行失败,我们推送的配置是否如预期下达等等,默认的记录模式是覆盖,是由session_log_file_mode控制的,它是一个字符串。

fast_cli与global_delay_factor在创建连接类的时候,很多场景下无需修改默认值,结合后续的讲解,大家能了解最好。对于这两个参数的调整可能会加快登录设备以及执行脚本的速度。

3.4 信息收集

进行信息收集在笔者看来是一件性价比非常高的事情,风险小,收益多,任何时刻都可以进行。

netmiko的很多入门也以show命令演示为主,主要用到了netmiko的send_command方法与send_commnad_timing方法。

笔者结合自己的使用以及对源代码的研读,将为大家认真讲解一下,这两种方法主的基本使用、二则差别以及在特定场景下二者使用场景的拓展。

首先二者的共同点要先说明一下,二者都是用于发送单条命令的方法,一般用于show命令,其实二者都可以完成配置推送,但笔者认为需要深刻了解二者的一些细节,才能比较好的实现这个配置推送的效果。

3.4.1 send_command基于pattern的命令执行

"""Execute command_string on the SSH channel using a pattern-based mechanism. Generally
used for show commands. By default this method will keep waiting to receive data until the
network device prompt is detected. The current network device prompt will be determined
automatically.

以上是send_command是代码doc_string中的描述,简单翻译下是:send_command在ssh隧道中执行命令,主要用于show命令。它是基于正则机制的,它执行命令后会持续收集回显,直至收到网络设备提示符,当前网络设备的提示符会由netmiko自动判定。

所谓提示符是指每次我执行命令结束后设备停住的那行,等待我们下一条命令而显示的文本,一般是设备名与#]>等的组合,有时候是提示我们输入密码等等。

image-20220620234013045

image-20220620234105012

image-20220620234248609

netmiko会自动决定提示符,它会在登录结束后输入一个回车,回显是什么提示符就是什么,netmiko会整理成一个正则。这样我们给netmiko一个cmd指令,netmiko执行后不断在ssh隧道中读取回显,直到通过正则断定指定的提示符出现,它认为回显已经结束,将所有回显组装后返回给我们。

以上是send_command方法的基本逻辑,也就是所谓的基于pattern的命令执行,让我们来执行一段代码感受一下:

from netmiko import ConnectHandler

dev = {
   'device_type': 'cisco_ios',
       'host': '192.168.137.201',
       'username': 'netdevops',
       'password': 'admin123!',
       'port': 22}

with ConnectHandler(**dev) as conn:
    output = conn.send_command(command_string='show running-configuration')
    print(output)

代码执行结束后会打印设备的show running-configuration回显 。

3.4.2 send_command_timing基于时间延迟的命令执行

"""Execute command_string on the SSH channel using a delay-based mechanism. Generally
used for show commands."""

netmiko中对于发送命令有两个非常重要的方法,一个是基于pattern的send_command,另一个则是基于时间策略的send_command_timing。从send_command_timing的描述中我们了解到两个信息:

  1. 它是一种基于延迟机制的方法。(一会我们会详解这种延迟机制)
  2. 它主要用于show命令。(实际在一些特殊的配置推送场景,它也会有奇效,前提是我们需要吃透这个方法和复杂场景的交互)

netmiko的send_command_timing是基于时间延迟的一个执行命令的方法。从它的名字我们就可以知道它与send_command最大的区别是“timing”,它是基于时间去自动判断执行命令是否结束。发送命令到ssh隧道后,它会进入一个循环,读取ssh隧道中的回显,如果发现回显则证明ssh隧道中还可能有回显在传输过程中,它会让程序暂定一定时间间隔,它调用了time模块的sleep函数来暂停程序,时间间隔比较短暂,是loop_delay乘以延迟因子,loop_delay是0.1秒,延迟因子默认是1,延迟之后进入下一次循环。结束循环的条件有两种:

  1. 超时,在创建netmiko连接的时候我们会传入一个timeout的参数,这个值除以每次延迟的实际时间,就是总循环的次数max_loops,当循环次数超出max_loops的时候,方法结束,将所有的回显返回给调用方。这种情况其实是一种非正常结束的情况,回显基本是不完整的,实际还可以再在ssh隧道里获取数据,只不过在send_command_timing判断已经超时了,就整理一下回显返回给用户,同时这个过程不会抛出错误。

  2. send_command_timing认为回显已经收集结束,它判断的依据是,如果发现没有回显,证明可能隧道中已经无回显或者是设备卡顿了一下,所以它选择停止延迟因子乘以2秒,延迟因子默认值为1 ,也就是说延迟2秒,2秒内还没有任何消息,那就认为回显结束了,退出把回显全部返回;如果还有回显则认为可能是设备卡顿导致刚才的回显是暂无的,所以它进入方法最初的大循环中,继续以小间隔尝试读取回显。

    image-20220630101814259

这就是send_command_timing的大体逻辑。它自动判断结束的机制是基于时间延迟的,当回显为空,延迟一个固定时间(默认两秒)仍然为空则认为回显结束。对于回显比较“干净利索”的网络设备而言,这个逻辑没问题,但在实际生产中我们发现用send_command_timing执行一些配置备份时遇到了配置备份不完整的现象,主要是生产环境中部分设备配置量偏大,比如执行show run之后,会在“building configuration”阶段卡了2秒以上导致的。现网中这种情况,笔者觉得还是有一定概率发生的,这个时候建议使用send_command,或者适当调大延迟因子delay_factor。

下面我们来看一下send_command_timing的代码

from netmiko import ConnectHandler

dev = {
   'device_type': 'huawei',
       'host': '192.168.137.201',
       'username': 'netdevops',
       'password': 'Admin123~',
       'port': 22}

with ConnectHandler(**dev) as conn:
    output = conn.send_command_timing(command_string='display current-configuration')
    print(output)

原本send_command方法,替换成了send_command_timing,其他未做任何变化。send_command_timing方法是基于时间延迟机制的,如果我们想适当扩大判断回显结束的停顿时间,我们该修改哪个参数呢?

在初始化连接不做任何变动的基础之上,我们只需在方法中给delay_factor(默认值为1)赋值即可,适当调整大一些,则此方法最后一次判断回显结束的时间会以延迟因子倍数级增长,从而避免回显不完整的情况发生。

with ConnectHandler(**dev) as conn:
    #判断回显为空停顿所需的时间是2秒*delay_factor,此处会是延迟6秒来判断回显是否完整
    output = conn.send_command_timing(command_string='display current-configuration',delay_factor=3)
    print(output)

这时我们将上述代码的send_command_timing重添加一个delay_factor参数,赋值为2,这个时候判断回显是否完成的时间就变为了4秒。我们可以通过代码打印时间,或者自行计时,两次代码时间相差4秒,正好是延迟因子的差值乘以2秒。

3.4.3 send_command与send_command_timing高级参数详解

以上我们讲解了发送命令(主要执行show命令)的两种方法:基于pattern正则机制的send_command与基于时间延迟机制的send_command_timing。这两个方法的参数极度相似,唯一的区别是send_command支持通过expect_string传入正则(不传入的时候以自动检测的为准,在show命令中此参数意义不大,我们后续会详解解读),send_command_timing支持通过delay_factor来控制判断回显是否结束的延迟时间(这个参数已经讲解过,但是它仍有很多变数在其中,后续我们也会详细解读)。除了这两个参数的区别以及围绕着这两个参数的一些其他参数,这两个方法的剩余参数基本一致,接下来我们会大家详细讲解这些基本的参数,这些平时用不到的参数,在某些特定场景下都会影响我们的程序是否能够如预想的执行。

3.4.3.1 send_command参数详解
expect_string

用于判断回显是否结束的正则表达式,如果不赋值或者传入为空,则由netmiko自动判断结束的提示符(含有设备名称的提示符)。

对于show命令而言,这个参数一般无需修改,官方也说过send_command主要用于show命令,但是基于此参数,send_command方法是可以实现配置推送的。

比如我们要进入设备的配置模式,华为设备需要输入system-view这个时候提示符会有普通的]结束改为#结束,如果直接调用send_command方法执行此命令,而不修改expect_string会让netmik继续在回显中查找原先的提示符的正则(以]结束的设备名称),显然是会失败的,会抛出错误,无法获取到预期的正则,超时报错。这个时候我们需要修改此参数,根据当前输入命令实际的提示符的特征来赋值,比如输入system-view的特征是还有`]

from netmiko import ConnectHandler

dev = {
   'device_type': 'huawei',
       &
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ARM(ZYNQ) cortexa9 Cross compiled CAN utils: To run CAN, use the below command: 1. Set bit-timing Can supports bitrates upto 1Mb/s. Xilinx CAN h/w and driver supports these bit rates Note: Triple sampling is not supported by Xilinx CAN H/W. $ ./ip link set can0 type can bitrate 200000 or $ ./canconfig can0 bitrate 200000 2. Bring up the device $ ./ip link set can0 up or $ ./canconfig can0 start 3. Bring down the device $ ./ip link set can0 down or $ ./canconfig can0 stop 4. Transmit and receive packets with standard id number $ ./cansend can0 -i 0x14 $ ./candump can0 5. Transmit and receive packets with extended id number (--loop argument here) $ ./cansend can0 -i 0x333 $ ./candump can0 6. Loopback mode $ ./canconfig can0 ctrlmode loopback on 7. Checking link state (checking bitrate/errors/packets) $ ./ip -d -s link show can0 8. Checking net device state $ ifconfig can0 9. Getting statistics via proc $ cat /proc/net/can/stats 10. Socket CAN core uses several filter lists to deliver received CAN frames to CAN protocol modules. These receive lists, their filters and the count of filter matches can be checked in the appropriate receive list. All entries contain the device and a protocol module identifier: $ cat /proc/net/can/rcvlist_all rcvlist_all - list for unfiltered entries (no filter operations) rcvlist_eff - list for single extended frame (EFF) entries rcvlist_err - list for error message frames masks rcvlist_fil - list for mask/value filters rcvlist_inv - list for mask/value filters (inverse semantic) rcvlist_sff - list for single standard frame (SFF) entries
《Python海龟宝典》是一本关于使用Python编程语言中海龟库的指南。海龟库是Python语言内置的一个图形库,可以通过简单的指令控制一只海龟在屏幕上绘制图形。 这本宝典详细介绍了如何使用Python中的海龟库进行图形绘制。首先,宝典提供了有关海龟库的基本概念和使用方法的入门知识。读者可以学习如何创建海龟对象,并使用各种指令来控制海龟的移动、转向和画笔状态等。 接着,宝典介绍了如何使用海龟库绘制各种基本的图形,如直线、正方形、三角形等。宝典详细解释了每个图形的绘制方法和参数,读者可以根据自己的需求来调整图形的样式和大小。 此外,宝典还介绍了如何使用循环、判断和函数等编程概念来实现更复杂的图形绘制。读者可以学习如何使用循环语句来重复绘制相同的图形,如绘制一圈圆形,以及如何使用判断语句来根据条件来绘制不同的图形。 除了基本图形,宝典还介绍了如何使用海龟库绘制更高级的图形,如星形、螺旋曲线等。宝典提供了详细的代码示例和说明,使读者能够轻松理解并尝试使用这些高级图形绘制方法。 总的来说,《Python海龟宝典》提供了一个全面而易于理解的指南,帮助读者掌握使用Python中的海龟库进行图形绘制的技巧和方法。无论是初学者还是有一定编程经验的人,都可以通过这本宝典来学习和提高自己的绘图技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值