5.1 实验1 大规模批量修改交换机Qos的配置 在第4章的实验2中提到了,要使用Python来批量连接管理IP地址不连续的网络设备,可以把设备的管理IP地址预先写入一个文本文件,然后在代码中使用for循环配合open()函数和readlines()函数逐行读取该文本文件里的管理IP地址,达到循环批量登录多台网络设备的目的。 在成功登录交换机后,我们可以配合command.send()来对网络设备“发号施令”,但在前面的例子中我们都是将要输入的命令预先写在脚本里,比如command.send("conf t\n")、command.send("router eigrp 1\n")和command.send("end\n")等。这种将配置命令预先写在脚本里的方法便于初学者理解和学习,在只有几台设备的实验环境中常用。但是在有成千上万台网络设备需要管理的生产环境中,这种方法显得很笨拙,缺乏灵活性。举例来说,假设生产环境中有不同型号、不同操作系统、不同命令格式的设备各1 000台,比如思科的3750和3850交换机,前者运行的是IOS,后者运行的是IOS-XE。 *近你接到任务,需要分别给这两种交换机批量修改QoS的配置,因为两者的命令格式差异巨大(一个是MLS QoS,一个是MQC QoS),必须反复修改command.send()部分的代码,如果只是简单数条命令还好办,一旦遇到大规模的配置,那么这种方法的效率会很低。 解决这个问题的思路是分别创建两个文本文件,一个用来存放配置3750交换机要用的命令集,另一个用来存放配置3850交换机要用到的命令集,然后在Python脚本里同样通过for循环加open()函数来读取两个文件里的内容,达到分别给所有3750和3850交换机做QoS配置的目的,这样做的好处是无须修改command.send()部分的代码,因为所有的命令行已经在文本文件里预先设置好了。 但是新的问题又来了,每次配备不同型号的设备,都必须手动修改open()函数所打开的配置文本文件及IP地址文件,比如在给3750交换机做配置时,需要open('command_ 3750.txt')和open('ip_3750.txt'), 给3850交换机做配置时,又需要open('command_3850.txt')和open('ip_3850.txt'),这样一来二去修改配置脚本的做法大大缺乏灵活性。如果只有两种不同型号、不同命令格式的设备还能应付,那么当生产环境中同时使用3750(IOS)、3850(IOS-XE)、Nexus 3k/5k/7k/9k(NX-OS)、CRS3/ASR9K(IOS-XR),甚至其他厂商的设备,而又要对所有这些设备同时修改某个共有的配置。比如网络新添加了某台TACACS服务器,要统一给所有设备修改它们的AAA配置;又或者网络新添加了某台NMS系统,要统一给所有设备修改SNMP配置。因为不同OS的���备的配置命令完全不同,这时就能体会到痛苦了。此时我们可以用下面实验中的sys.argv来解决这个问题。 5.1.1 实验背景 本实验将在真机下完成。 假设现在手边有3台管理IP地址在168.100.x /24网段的3750交换机和3台管理IP地址在172.16.100.x/24网段的3850交换机,它们的hostname和管理IP地址分别如下。 3750_1: 192.168.100.11
3750_2: 192.168.100.22
3750_3: 192.168.100.33
3850_1: 172.16.100.11
3850_2: 172.16.100.22
3850_3: 172.16.100.33 5.1.2 实验目的 修改所有3750和3850交换机的QoS配置,更改它们出队列(output queue)的队列参数集2(queue-set 2)的缓存(buffers)配置,给队列1、2、3和4分别分配15%、25%、40%和20%的缓存(默认状况下是25%、25%、25%和25%)。 5.1.3 实验准备 (1)首先创建两个名为command_3750.txt和ip_3750.txt的文本文件,分别用来保存我们将要配置3750交换机的QoS命令,以及所有3750交换机的管理IP地址。 [root@CentOS-Python ~]# cat command_3750.txt configure terminal
mls qos queue-set output 1 buffers 15 25 40 20 end wr mem
[root@CentOS-Python ~]# cat ip_3750.txt
192.168.100.11
192.168.100.22
192.168.100.33 (2)同理,创建两个名为command_3850.txt和ip_3850.txt的文本文件,分别用来保存我们将要配置3850交换机的QoS命令,以及所有3850交换机的管理IP地址。 [root@CentOS-Python ~]# cat command_3850.txt
configure terminal
class-map match-any cos7
match cos 7
class-map match-any cos1
match cos 1
exit
policy-map queue-buffer
class cos7
bandwidth percent 10
queue-buffers ratio 15
class cos1
bandwidth percent 30
queue-buffers ratio 25
exit
exit
interface gi1/0/1
service-policy output queue-buffer
end
wr mem
[root@CentOS-Python ~]# cat ip_3850.txt
172.16.100.11
172.16.100.22
172.16.100.33 (3)在主机上创建实验1的脚本,将其命名为lab1.py。 5.1.4 实验代码 将下列代码写入脚本lab1.py。 import paramiko import time import getpass import sys username = input('username: ') password = getpass.getpass('password: ') ip_file = sys.argv[1] cmd_file = sys.argv[2] iplist = open(ip_file, 'r') for line in iplist.readlines(): ip = line.strip() ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.connect(hostname=ip,username=username,password=password) print "You have successfully connect to ", ip command = ssh_client.invoke_shell() cmdlist = open(cmd_file, 'r') cmdlist.seek(0) for line in cmdlist.readlines(): command.send(line "\n") time.sleep(1) cmdlist.close() output = command.recv(65535) print (output.decode("ascii")) iplist.close() ssh_client.close 5.1.5 代码分段讲解 (1)因为要用到sys.argv,所以我们导入了sys模块。sys模块是Python中十分常用的内建模块。其余部分的代码都是在前面实验中讲过的,不再赘述。 import paramiko import time import getpass import sys username = input('username: ') password = getpass.getpass('password: ') (2)创建两个变量ip_file和cmd_file,分别对应sys.argv[1]和sys.argv[2]。 ip_file = sys.argv[1] cmd_file = sys.argv[2] argv是argument variable参数变量的简写形式,这个变量的返回值是一个列表,该列表中的元素即我们在主机命令行里运行Python脚本时输入的命令。sys.argv[0] 一般是被调用的.py脚本的文件名,从sys.argv[1]开始就是为这个脚本添加的参数。举个例子,我们现在返回主机,输入下面这条命令。 [root@CentOS-Python ~]# python3.8 lab1.py ip_3750.txt cmd_3750.txt 那么,这时的sys.argv即含有lab1.py、ip_3750.txt、cmd_3750.txt 3个元素的列表。这时sys.argv[0] = lab1.py,sys.argv[1] = ip_3750.txt,sys.argv[2] = cmd_3750.txt。相应地,代码里的ip_file = sys.argv[1] 此时等同于ip_file = ip_3750.txt,cmd_file = sys.argv[2]此时等同于cmd_file = cmd_3750.txt。同理,如果这时我们在主机上执行如下命令。 [root@CentOS-Python ~]# python3.8 lab1.py ip_3850.txt cmd_3850.txt 则此时ip_file = ip_3850.txt,cmd_file = cmd_3850.txt。由此可见,配合sys.argv,我们可以很灵活地选用脚本需要调用的参数(文本文件),而无须反反复复地修改脚本代码。 (3)需要注意的是,在剩下的代码中,我们没有在脚本里预先写好具体的QoS配置命令,取而代之的是通过cmd_file = sys.argv[2]配合cmdlist = open(cmd_file, 'r')和for line in cmdlist.readlines()来读取独立于脚本之外的配置命令文件,可以随意在命令行里选择我们想要的配置命令文件,也就是本实验中的cmd_3750.txt和cmd_3850.txt。 iplist = open(ip_file, 'r') for line in iplist.readlines(): ip = line.strip() ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.connect(hostname=ip,username=username,password=password) print "You have successfully connect to ", ip command = ssh_client.invoke_shell() cmdlist = open(cmd_file, 'r') cmdlist.seek(0) for line in cmdlist.readlines(): command.send(line "\n") time.sleep(1) cmdlist.close() output = command.recv(65535) print (output.decode("ascii")) iplist.close() ssh_client.close 5.1.6 验证 [root@CentOS-Python ~]# python3.8 lab1.py ip_3750.txt cmd_3750.txt Username: python password: You have successfully connect to 192.168.100.11 3750_1#conf t 3750_1(config)#mls qos queue-set output 1 buffers 15 25 40 20 3750_1(config)#end 3750_1#wr mem Building configuration... [OK] You have successfully connect to 192.168.100.22 3750_2#conf t 3750_2(config)#mls qos queue-set output 1 buffers 15 25 40 20 3750_2(config)#end 3750_2#wr mem Building configuration... [OK] You have successfully connect to 192.168.100.33 3750_3#conf t 3750_3(config)#mls qos queue-set output 1 buffers 15 25 40 20 3750_3(config)#end 3750_3#wr mem Building configuration... [OK] [root@CentOS-Python ~]# python lab1.py ip_3850.txt cmd_3850.txt Username: python password: You have successfully connect to 172.16.100.11 3850_1#configure terminal Enter configuration commands, one per line. End with CNTL/Z. 3850_1(config)#class-map match-any cos7 3850_1(config-cmap)#match cos 7 3850_1(config-cmap)#class-map match-any cos1 3850_1(config-cmap)#match cos 1 3850_1(config-cmap)#exit 3850_1(config)#policy-map queue-buffer 3850_1(config-pmap)#class cos7 3850_1(config-pmap-c)#bandwidth percent 10 3850_1(config-pmap-c)#queue-buffers ratio 15 3850_1(config-pmap-c)#class cos1 3850_1(config-pmap-c)#bandwidth percent 30 3850_1(config-pmap-c)#queue-buffers ratio 25 3850_1(config-pmap-c)#exit 3850_1(config-pmap)#exit 3850_1(config)#interface gi1/0/1 3850_1(config-if)#service-policy output queue-buffer 3850_1(config-if)#end 3850_1#wr mem Building configuration... Compressed configuration from 62654 bytes to 19670 bytes[OK] You have successfully connect to 172.16.100.22 3850_2#configure terminal Enter configuration commands, one per line. End with CNTL/Z. 3850_2(config)#class-map match-any cos7 3850_2(config-cmap)#match cos 7 3850_2(config-cmap)#class-map match-any cos1 3850_2(config-cmap)#match cos 1 3850_2(config-cmap)#exit 3850_2(config)#policy-map queue-buffer 3850_2(config-pmap)#class cos7 3850_2(config-pmap-c)#bandwidth percent 10 3850_2(config-pmap-c)#queue-buffers ratio 15 3850_2(config-pmap-c)#class cos1 3850_2(config-pmap-c)#bandwidth percent 30 3850_2(config-pmap-c)#queue-buffers ratio 25 3850_2(config-pmap-c)#exit 3850_2(config-pmap)#exit 3850_2(config)#interface gi1/0/1 3850_2(config-if)#service-policy output queue-buffer 3850_2(config-if)#end 3850_2#wr mem Building configuration... Compressed configuration from 62654 bytes to 19670 bytes[OK] You have successfully connect to 172.16.100.33 3850_3#configure terminal Enter configuration commands, one per line. End with CNTL/Z. 3850_3(config)#class-map match-any cos7 3850_3(config-cmap)#match cos 7 3850_3(config-cmap)#class-map match-any cos1 3850_3(config-cmap)#match cos 1 3850_3(config-cmap)#exit 3850_3(config)#policy-map queue-buffer 3850_3(config-pmap)#class cos7 3850_3(config-pmap-c)#bandwidth percent 10 3850_3(config-pmap-c)#queue-buffers ratio 15 3850_3(config-pmap-c)#class cos1 3850_3(config-pmap-c)#bandwidth percent 30 3850_3(config-pmap-c)#queue-buffers ratio 25 3850_3(config-pmap-c)#exit 3850_3(config-pmap)#exit 3850_3(config)#interface gi1/0/1 3850_3(config-if)#service-policy output queue-buffer 3850_3(config-if)#end 3850_3#wr mem Building configuration... Compressed configuration from 62654 bytes to 19670 bytes[OK]