目录
前言
python作为网工进阶必学的技能,利用各种网络自动化库自动完成各种网络配置任务,不仅可以在配置的时候节约大量时间,还可以直观的了解到Python是如何把繁杂、单调、耗时的传统网络运维实现自动化(所有实验均基于华为的ENSP)
本章主要讲解
- 如何使用Python里的telnetlib模块连接到网络设备
- 初识Paramiko和Netmiko模块
- 通过Paramiko和Netmiko连接到网络设备
- 使用input()函数和getpass模块
1.环境要求
检查一下是否正确安装了下列工具并且保证版本能够正常使用
- python 3.10.x(笔者这里的python是3.10.6)
- Pycharm社区版或者专业版(社区版足矣)
- 华为的ENSP模拟三层交换设备
- 操作系统Windows 10
2.拓扑图
保证交换机可以和宿主机互通
然后配置aaa登录以及和外界互通的IP地址
stelnet server enable ssh user python ssh user python authentication-type password ssh user python service-type all ssh client first-time enable # aaa local-user python password cipher python local-user python privilege level 15 local-user python service-type telnet ssh # interface Vlanif1 ip address 192.168.56.2 255.255.255.0 # user-interface vty 0 4 authentication-mode aaa protocol inbound all
3.实验目的
通过Telnetlib,Netmiko,Paramiko模块登录交换机SW1,SW2,SW3,SW4,然后给每台交换机的环回口配地址
4.实验过程
4.1 Python中的Telnet和SSH模块
4.1.1 Telnetlib
telnet作为一种不安全的登录方法,在python中,我们不经常用它远程登陆网络设备,Telnetlib作为python的内置模块,不需要pip下载就能直接使用,鉴于Telnet的不安全性,通常不用在生产网络当中,本小节只举一例来讲解Telnetlib模块的使用方法
import telnetlib import time host = "192.168.56.2" //管理地址的IP地址 user = "python" //创建的AAA用户的用户名 password = "python" //创建AAA用户的登录密码 telnet = telnetlib.Telnet(host) telnet.read_until(b"Username: ") telnet.write(user.encode('ascii') + b"\n") telnet.write(user + '\n') telnet.read_until(b"Password: ") telnet.write(user.encode('ascii') + b"\n") telnet.write(password + "\n") telnet.write(b"sys\n") telnet.write(b"int loo0\n") telnet.write(b"ip add 2.2.2.2 255.255.255.255\n") time.sleep(0.5) telnet.write(b"quit\n") print(telnet.read_very_earger().decode('ascii')) telnet.close()在python3中,telnetlib模块下所有函数的返回值都变成了字节型字符串(Byte strings),因此,在python3中使用telnetlib需要注意以下几点
- 在字符串面前需要加一个b
- 在变量和telnetlib函数后面需要加上.encode('ascii')函数
- 在read_all()函数后面需要加上decode('ascii')函数
注意:1.encode是解码的意思,将用户输入用ascii解码
2.b表示将用户的输入解码成字符串
3.telnet.read_very_earger方法表示打印,这样就可以在运行结果中清楚的看到我们对设备做了什么配置,并且这这个方法只有在退出telnet才会生效,因此我们必须在之前通过telnet.write(b"quit\n")退出telnet
代码分段讲解如下:
首先通过import语句导入telnetlib模块
import telnetlib import time
然后创建三个变量,分别是host,user,password,分别对应交换设备的管理地址,Telnte用户名和密码,且三个变量的类型是字符串类型
host = "192.168.56.2" user = "python" password = "123"
调用telnetlib模块里面的Telnet()函数,将它赋值给变量telnet,然后以Telnet方式登录
192.168.56.2
telnet = telnetlib.Telnet(host)
通过Telnet登录交换机的时候,终端输出最下面的提示信息为“Username:”,我们通过telnet.read_until("Username: ")和telnet.read_until("Password: ")告诉Python,如果在终端信息里读到“Username:”和“Password:”字样,就使用telnet.write()函数来输入用户名和密码,记得加换行符'\n',这里我们用CRT模拟一下Telnet连接
telnet.read_until(b"Username: ") telnet.write(user.encode('ascii') + b"\n") telnet.write(user + '\n') telnet.read_until(b"Password: ")
至此,已经成功通过Telnet登录到SW1上了,接下来就用Telnetlib的write()函数在交换机上输入各种配置命令,给环回口配置IP地址,划分VLAN等操作
telnet.write(b"sys\n") telnet.write(b"int loo0\n") telnet.write(b"ip add 2.2.2.2 255.255.255.255\n") time.sleep(0.5) telnet.write(b"quit\n") print(telnet.read_very_earger().decode('ascii')) telnet.close()
最后结果就和我们正常配置一样,但是笔者这里的python版本过高,导致telnetlib已经在这个版本被移除了,这里就不过多演示了,有兴趣的可以试试,代码如果写对了就会只出现这一个报错,如果有其他地方报错,比如和宿主机不能连通,会继续出现报错,显示连接失败,如下图,
4.1.2 Netmiko
Python中支持SSH协议实现远程连接设备的模块主要有Paramiko和Netmiko两种,Paramiko是Python中一个非常著名的开源SSHv2项目,基于Python 2.7和Python3.4+开发
Netmiko是Python的第三方模块,需要通过pip安装,但是笔者在这里不推荐用pip安装,笔者通过这种方法安装之后在Python里检测不到这个模块,这里推荐用PyCharm安装,如下图
点击“+”
然后搜索模块
笔者这里已经安装过了,同时paramiko模块也装好了,这里就不演示,直接点击Install Package安装就行了
然后开始做实验,与上面的Telnet实验一样,首先我们要登录SW1,然后查看一下环回口有没有地址,防止我们在试验中混淆,接下来创建一个名为ssh_netmiko.py的脚本
代码如下
from netmiko import ConnectHandler SW1 = { 'device_type': 'huawei', 'ip': '192.168.56.2', 'username': 'python', 'password': 'python' } connect = ConnectHandler(**SW1) print("成功登录到" + SW1['ip']) config_command = ['int loo 1 ','ip add 1.1.1.1 32'] output = connect.send_config_set(config_command) print(output) result = connect.send_command('disp cur int loo 1') print(result)
代码分段讲解如下
首先通过import语句从Netmiko模块导入他的链接库函数ConnectHandler()。该函数用来实现SSH登录网络设备,是Netmiko最重要的函数
from netmiko import ConnectHandler
然后创建一个名为SW1的字典,字典包含 device_type、 ip 、 username、password必选的键,device_type键表示支持的厂家的设备,Netmiko支持多数厂家设备,比如Cisco,huawei,Arista,HP等主流厂商设备,由于不通厂商设备登录SSH后命令行界面和特性各不相同,因此我们必须通过device_type来指定需要登陆设备的类型,如果要是Cisco,device_type的键值为csico_ios,后面三个就很好理解了,笔者在这里就不一一赘述了
SW1 = { 'device_type': 'huawei', 'ip': '192.168.56.2', 'username': 'python', 'password': 'python' }
然后调用ConnectHandler()函数,用已经创建的字典SW1进行SSH连接,将它赋值给connect变量,注意SW1前面的**为关键字参数kwargs,在函数里,关键字参数表示传入函数的参数为字典格式
connect = ConnectHandler(**SW1)
创建一个登陆提示,如果登录成功就告诉我们
print("成功登录到" + SW1['ip'])
然后创建一个config_commands的列表,其元素为需要在交换机依次执行的命令
config_command = ['int loo 1 ','ip add 1.1.1.1 32']
调用ConnectHandler()的send_config_set()函数来使用上述命令对SW1做配置,参数就是我们上面创建出来的列表,并把配置过程打印出来
output = connect.send_config_set(config_command) print(output) result = connect.send_command('disp cur int loo 1') print(result)
最后调用ConnectHandler()的Send_command函数,对交换机输入命令show run int loo 1,并将回显内容打印出来,需要注意的是connect.send_command一次只能向设备输入一条命令,connect.send_config_set则可以向设备一次输入多个命令
运行代码,结果如图所示
4.1.3 Paramiko实验举例
Paramiko和Netmiko不同,Netmiko是基于Paramiko开发的,自然比Paramiko要更好用,比如,Paramiko不会在做配置的时候给我们做配置的时候自动加上system-view,return等命令,相信大家在上面已经看出来了,Telnetlib实验需要我们敲sys进入全局下进行配置,配置完需要敲quit退出,Netmiko就完全不需要,大家可以仔细看Netmiko运行结果,如下图
是不是自动给我们加上了system-view和return命令,Python是一次性执行脚本里所有的命令的,中间没有间隔时间,当我们一次性执行过多的命令,通常出现SSH终端跟不上速度,导致某些命令缺失没有被输入的问题,同样,在用print函数显示回显内容或者open.write()将回显写入文档进行保存,也会因为缺失时间间隔导致命令不完整,Netmiko自动帮我们解决了这个难题,这也是Netmiko比Paramiko的好用的原因之一,而且在Paramiko这个模块中,我们必须导入time模块,然后使用time模块下的sleep()方法来解决这个问题,关于time模块我们会在下面的实验中讲解,这里安装Paramiko就不再赘述,和Netmiko安装方法一样
首先创建一个名为ssh_paramiko.py的脚本,内容如下
import paramiko import time ip = '192.168.56.2' username = 'python' password = 'python' client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=ip, username=username, password=password) print("成功登录到{}".format(ip)) command = client.invoke_shell() command.send('sys\n') command.send('int loo 2\n') command.send('ip add 2.2.2.2 32\n') command.send('return\n') command.send('save\n') command.send('Y\n') time.sleep(2) output = command.recv(65535) print(output.decode("ascii")) client.close()
代码分段讲解如下
通过import语句导入paramiko和time两个模块
import paramiko import time
然后创建三个变量:ip,username,password,分别对应我们要登陆的交换机SW1的管理地址,SSH用户名和密码
ip = '192.168.56.2' username = 'python' password = 'python’
默认情况下,Paramiko会拒绝任何位置SSH公钥,这我们需要用client.set_missing_host_key_policy(paramiko.AutoAddPolicy())来让Paramiko来接受SSH的服务端,这是在任何时候使用Paramiko连接SSH的标准配置
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
然后调用paramiko.SSHClient()和client.connect()进行SSH登录,里面包含的三个变量就是我们创建的ip,username,password,如果登陆成功,就提示用户登录成功的交换机的管理IP
client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=ip, username=username, password=password) print("成功登录到{}".format(ip))
SSH连接成功过后,需要调用command = client.invoke_shell()来唤醒Shell来向SW1输入你想要的配置,注意这里需要输入system-view,不然进不了全局配置模式下,就会导致配失败
command = client.invoke_shell() command.send('sys\n') command.send('int loo 2\n') command.send('ip add 2.2.2.2 32\n') command.send('return\n') command.send('save\n') command.send('Y\n')
最后,就是我们的前面所说的,因为python是一次性执行所有脚本的命令的,中间没有间隔时间,这样会导致命令遗漏和回显内容不完整的问题,在Paramiko的recv()将回显结果保存之前,我们需要调用time模块下的time方法让python休眠2s,这样回显才能被完整保存下来,这里的command.recv(65535)中的65535代表截取65535的字符的回显内容,这也是Paramiko一次能截取的最大回显内容数,另外,与Telnetlib类似,在Python3中,Paramiko街区的弧线内容格式为字节型字符串,需要用decode("ascii")将其解析为ASCII编码,否则打印出来的output的内容格式会很难看,有兴趣的同学可以试试不用decode解析,这里笔者就不做演示了
time.sleep(2) output = command.recv(65535) print(output.decode("ascii"))
配置完毕之后,使用close方法退出SSH
配置完毕之后,使用close方法退出SSH
client.close()
运行代码后看结果,验证,如下图所示
4.2 input()函数和getpass模块
在针对Telnetlib、Netmiko和Paramiko模块的基础知识讲解中,我们都将SSH登录的用户名和密码明文写在了脚本中,这种做法一般用在实验里,但是在生产环境中是不够安全的,在生产环境中,正确的做法是使用input()函数和getpass模块来分别提示用户手动输入SSH用户名和密码,这也是本实验重点讲解的部分
4.2.1 实验目的
- 使用input()函数和getpass模块实现交互式的SSH用户名和密码输入
- 通过for循环同时为三台交换机配置VLAN10-VLAN20
4.3.2 实验准备
在运行代码之前,首先检查交换机配置,看看VLAN是否存在
然后创建Python脚本文件
代码如下
import paramiko import time import getpass username = input('Username: ') password = getpass.getpass('Password: ') for i in range(2,5): ip = "192.168.56." + str(i) client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=ip, username=username, password=password,look_for_keys=False) print("成功登录到{}".format(ip)) command = client.invoke_shell() command.send('screen-length 0 temporary\n') command.send('sys\n') for n in range(10,21): command.send('vlan ' + str(n) + '\n') command.send('description python_vlan' + str(n) + '\n') time.sleep(1) command.send('return\n') command.send('save\n') command.send('Y\n') time.sleep(2) output = command.recv(65535) print(output.decode("ascii")) client.close()
代码分段讲解如下
首先导入paramiko、time和getpass3种模块
import paramiko import time import getpass username = input('Username: ') password = getpass.getpass('Password: ')
因为三台交换机的IP地址是连续的,都是192.168.65.X,我们直接做一个简单的for循环来遍历三台交换机,然后配合下一行代码ip = "192.168.56." + str(i)来实现循环批量登录交换机,注意这里的i是整数,我们输入的属于字符,所以要用str(i)来转化成字符串
for i in range(2,5): ip = "192.168.56." + str(i) client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=ip, username=username, password=password,look_for_keys=False) print("成功登录到{}".format(ip)) command = client.invoke_shell() command.send('screen-length 0 temporary\n') command.send('sys\n')
同样的道理,我们要创建VLAN10-VLAN20,这些VLANID都是连续的,所以又可以配合一个简单的for循环来达到循环配置VLAN10-VLAN20的目的,这里使用的是嵌套for循环,需要注意缩进,这里创建VLAN的时候可以创建一个打印内容来提醒我们正在创建那个VLAN,每创建一个VLAN都需要1s的间隔
for n in range(10,21): command.send('vlan ' + str(n) + '\n') command.send('description python_vlan' + str(n) + '\n') time.sleep(1)
最后保存配置
command.send('return\n') command.send('save\n') command.send('Y\n') time.sleep(2) output = command.recv(65535) print(output.decode("ascii"))
4.3.3 验证
注意:这里用的是IDLE shell验证的,用pycharm会卡在输入密码那里,具体原因不知道为啥
检查交换机配置