感谢知乎两位大佬:@弈心和@朱嘉盛
@弈心大佬的实验主要是基于 linux 系统、思科设备或 GNS3 模拟器完成。
@朱嘉盛大佬考虑到当前在国内华为较为主流,也用 Windows 系统,尝试用华为的真机或者 eNSP 模拟器,把书中提及的实验做一做,方便大家学习记录,方便交流。
小编这里采用ensp windows复现一遍华为的实验。
平台工具:
- 实验平台:WIN10
- 使用工具:eNSP v1.3.00.100、python 3.7.3
实验拓扑:
注意:
书中使用了 192.168.2.0/24 ,我这里才有eve桥接的虚拟网段192.168.242.0/24来演示本次实验。
【SSH 服务端】LSW x,IP为 192.168.242.1x/24,连接到透明交换机SW1。
实验背景:
实际运维中,我们经常有这么个需求:登录设备,在设备上执行命令,采集回显信息,保存下来备份或待后续分析比较。
实验目的:
(1)登录设备,执行dis int bri收集设备端口概要信息,保存至本地目录。
(2)处理回显保存的文本,规范化显示。
实验过程
实验拓扑搭建、账号配置调测等在“环境搭建”文章中我们已详细介绍,这里从略。
第 1 步,创建Python脚本文件
有了前面几个实验的基础,相信我们可以很快码出功能性python脚本。延续咱们一贯的简单实用风格,代码我就不定义main函数,子函数,异常处理等内容了。我们聚焦提炼,先把要实现的功能做出来。
代码语言:javascript复制import paramiko
import time
username = 'python'
password = '123'
for i in range(11,16):
ip = '192.168.242.' str(i)
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=ip,username=username,
password=password,look_for_keys=False)
command = ssh_client.invoke_shell()
print('=-=-=-=-=-=-=-=-=-=-=-=-=-=')
print('已经成功登陆交换机 LSW-' str(i-10) ' ' ip)
# 关闭分屏功能
command.send('screen-length 0 temporaryn')
# 进入系统视图
command.send('sysn')
command.send('dis int brin')
time.sleep(2)
#抓取回显,放入output变量
output = command.recv(65535).decode('ASCII')
print(output)
#保存结果到python脚本同目录下的result文件夹中
f1 = open(f".\result\{ip}_dis_int_bri.txt","w")
f1.write(output)
f1.close()
ssh_client.close()
代码我大概过程串一下:根据实验拓扑交换机IP尾数11-15的规律做一个循环。循环中每次用paramiko模块SSH登录每台交换机,执行取消分屏,进入系统视图,执行dis int bri,抓取回显打印并写入txt,按“ip 指令”的命名规则,保存在result文件夹中,之后断开SSH。继续……直到循环结束。
第 2 步,运行Python脚本
好了,我们跑一下脚本。不出意外的话,我们可以从idle上看到回显,然后在result文件夹中看到保存的文件。至此,实验目的(1)已完成。
第 3 步,打开观察保存的文本
cmd上的print操作没异常,符合预期。保存下来的文本文件,我们先用记事本打开,发现有很多空行,见上图。强迫症患者哪里受得了??我们再用写字板打开看一下。结果只能是更加受不了。
第 4 步,规范化数据(一)
对上面的现象,起初我尝试搜下资料,但并未找到有针对性地解释这现象和解决办法的内容。我自己思考下,这现象估计是数据写入时不规范导致。强迫症还是小事,这种不规范可能会对后续其它操作带来不利影响。
怎么办?原因不知道,生产还是要进行的。那只能想个土办法来应对一下。
在python脚本的最后,补上下面代码。
代码语言:javascript复制f1 = open(f".\result\{ip}_dis_int_bri.txt","r")
f2 = open(f".\result\new_{ip}_dis_int_bri.txt","w")
for line in f1.readlines():
if line.split():
f2.write(line)
f1.close()
f2.close()
代码我大概过程串一下:前面的代码跑完后,python脚本重新打开每个文件,逐行读取。对读取的每一行先做split()分列操作,处理后,如果为空则跳过直接处理下一行了,如果非空则写入另一个文件中。这可以说是一个笨手笨脚效率低的方法。咱们是网工,能有效应对生产,效率低点没关系。
来,执行一下。我们发现result文件夹中处理后的new开头的文件,用记事本打开或者写字板打开就都正常了。
第 5 步,规范化数据(二)
虽然用第4步的代码我们已经能达到目的了。但是这样的代码一来效率低,二来也没办法解释为啥会出现空行。
我们回头观察未经过第4步空行“笨手笨脚”处理的文件。用UE编辑工具打开这个文件后(此时,不会显示空行,但用记事本打开则有空行),我们按快捷键ctrl h切换。观察每行末尾,我们会看到都有
我们查一下ASCI:
0x0D | r(carrige return) | 指打字头归位的动作 |
---|---|---|
0x0A | n(new line) | 指打字机上卷一行的动作 |
Windows系统中连用"rn",类UNIX系统多用"n"(看上面python代码我们在指令后面加了“n”)。回到用UE打开的文本,我们翻译一下。
OD OD OA |
---|
我推测Windows的记事本工具可能把r呈现成换行,rn也呈现成换行,于是空行就这么出现了。既然我们指令用“n”,那何不我们在接收回显是时候就直接把“r”都处理掉呢?
我们在第1步大代码中,修改这条代码,在最后面加上.replace('r',''),把“r”直接替换成空。
代码语言:javascript复制output = command.recv(65535).decode('ASCII').replace('r','')
完整的代码我再贴一次:
代码语言:javascript复制import paramiko
import time
username = 'python'
password = '123'
for i in range(11,16):
ip = '192.168.11.' str(i)
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=ip,username=username,
password=password,look_for_keys=False)
command = ssh_client.invoke_shell()
print('=-=-=-=-=-=-=-=-=-=-=-=-=-=')
print('已经成功登陆交换机 Layer3Switch-' str(i-10) ' ' ip)
# 关闭分屏功能
command.send('screen-length 0 temporaryn')
# 进入系统视图
command.send('sysn')
command.send('dis int brin')
time.sleep(2)
output = command.recv(65535).decode('ASCII').replace('r','')
print(output)
#保存结果到python脚本同目录下的result文件夹中
f1 = open(f".\result\{ip}_dis_int_bri.txt","w")
f1.write(output)
f1.close()
ssh_client.close()
再跑一下python脚本,马上就没有多余的空行了,这里就不截图了。至此,实验目的(2)完成。
另外再次用UE打开,发现还是会有"rn",这我估计Windows遇到“rn”时保持“rn”,遇到“n”时则处理成“rn”。
实验小结:
虽然用第4步的代码我们已经能达到目的了。但是这样的代码一来效率低,二比如我们想做配置备份,就把指令改成“dis cur”即可,这个实验还是挺具有通用性的。网工普遍没什么计算机编码解码基础,遇到此类问题可能会比较棘手。我也有过多次因处理乱码等搞到焦头烂额的经历。有时候我们使用点工具,看编码解码后的变化,或许能帮忙解决些问题吧。另外,当使用netmiko、nornir等高大上模块后,我们再回过头来使用paramiko模块,会不会觉得其实反而它轻巧好操作些呢?