使用Netmiko进行交互式操作

Netmiko 的 send_command 方法可以很方便的在网络设备上执行命令,如各种 show、发送一些基本配置等;但是如果是交互式的操作,例如拷贝文件、升级系统等需要人工确认的操作,貌似就有点不行了。

其实 send_command 方法提供了这个功能,从它的参数中可以看到,有一个expect_string参数,可以通过这个参数来进行交互式操作。

这个参数就是表面意思: 期望字符串,实际使用中,这里需要传入一个正则表达式,然后 Netmiko 会从返回的文本中搜索该字符串,找到之后即为执行结束,关闭连接。

1
2
3
# send_command 方法支持的所有参数
def send_command
(self, command_string, expect_string=None, delay_factor=1, max_loops=500, auto_find_prompt=True, strip_prompt=True, strip_command=True, normalize=True, use_textfsm=False, textfsm_template=None, use_ttp=False, ttp_template=None, use_genie=False, cmd_verify=True)

copy 文件

当我们从设备上进行拷贝文件时,设备会提示输入Y/N 进行确认:

此时如果使用 Netmiko,就需要让脚本来自己确认操作,来实验一下:

1
2
3
4
5
6
7
8
9
10
11
12
from netmiko import ConnectHandler as ch
host = {
'device_type': 'hp_comware',
'host': '192.168.56.20',
'username': 'netdevops',
'password': 'netdevops',
'port': 22,
}
cmd = 'copy http://192.168.56.1:9212/vlan.cfg flash:/'
conn = ch(**host)
# 这里要注意使用原始字符串,并对正则表达式中的元字符进行转义
output = send_command(cmd. expect_string=r'\[Y/N\]:')

执行结果如下,可以看到 netmiko 检测到指定的字符后,就退出了执行。

执行到这里后,我们可以继续发送一个 Y 来进行操作,并对输出进行拼接。
这里需要注意一点:
同一个SSH连接中,如果定义了expect_string,那么后续发送命令时,仍然检测该字符串。
所以,第二次发送命令Y时,就需要根据实际情况把检测字符串改回来,如下:

1
2
3
4
...
output = conn.send_command(cmd, expect_string=r'\[Y/N\]:')
output += conn.send_command('Y', expect_string=r'>')
print(output)

执行结果如下:

设备上可以查看到这个文件:

一个问题:
当传输文件到设备上时,可能会碰到文件名冲突的情况,设备检测到冲突文件后,还会再提示让输入Y/N 确认是否进行覆盖。

这时,可以先用 dir命令,根据返回文本判断是否存在文件,或者直接覆盖等。具体的就根据实际需求来了~

如果是从设备上传输文件到服务器(让设备主动上传配置文件到服务器上),如果存在文件名冲突,则会直接传输失败。(仅针对 H3C 设备)

升级系统

上文中介绍了如何使用 Netmiko copy 文件,当工作中进行批量升级系统时,就可以预先通过这种方式将系统升级文件传到设备上。

在之前文章中提到过:send_command 检测提示符的超时时间大约为 100 秒,而系统文件一般情况下都比较大,传送时间可能会超过 100 秒,进而导致传输中断。

遇到这种情况时,就可以使用delay_factor参数来增加等待的时间:

1
2
3
...
output = conn.send_command(cmd, expect_string=r'\[Y/N\]:')
output += conn.send_command('Y', expect_string=r'>', delay_factor=3)

delay_factor 的取值 可根据具体的网络情况等因素进行设置,最好预留时间多一点,因为最终 netmiko 检测到预期的提示符后也会退出。

当把系统传输到设备后,可以继续使用 expect_string 进行后续的一系列交互操作,例如设置启动文件、重启设备等,具体细节就需要根据使用场景来进行完善。