上次使用netmiko做了一个批量配置备份的小脚本,使用了一段时间发现一个问题。就是路由交换设备备份出来的配置能正常显示,但是部分厂商防火墙的配置备份出来中文就是乱码。
这个问题我也是困扰了很久,到处寻医问药都是让我解码编码,根本没用。后边我发现通过netmiko库执行命令获取的设备回显的格式是字符串(str),我感觉netmiko这个库在内部就已经解码编码完毕了,输出的就是utf-8的字符。所以,我们对netmiko输出的内容怎么解码编码都没用。
既然netmiko的输出的内容无法改变,就只能采用其他方式。要是能够将执行命令后,输出的原始字节获取到就好了,这样就可以针对设备的编码方式,对输出进行处理。最后我找到了paramiko库,这个库执行命令返回的类型是字节(bytes),这样就能根据我需要的编码进行输出了。
这次的加强版脚本,我使用了两种库(netmiko + paramiko),在执行的时候可以自行选择。如果设备支持的不是utf-8格式(如:H3C防火墙)则可以选择paramiko库执行。正常utf-8的设备可以使用netmiko库执行。但是,netmiko连接设备真的很慢,我又不会整多线程效果可想而知。(毕业设计的时候就没整明白,反正我也不是职业开发,哈哈)
完整代码如下:
# -*- encoding: utf-8 -*-
'''
@File : auto_Backup_ssh_client.py
@Time : 2021/08/01 09:16:39
@Author : Kun Zhou
@Version : 1.0
@Contact :
'''
# here put the import lib
from netmiko import ConnectHandler
from pathlib import Path
import openpyxl
import time,sys,os
import paramiko
def Read_excel(file_name):
wb = openpyxl.load_workbook(file_name)
sheet = wb.get_sheet_by_name('Sheet1')
row = sheet.max_row
column = sheet.max_column
device_list = {}
for i in range(2,row+1):
device_list['device{0}'.format(i-1)] = []
for j in range(1,column+1):
vla = sheet.cell(row = i,column = j).value
device_list['device{0}'.format(i-1)].append(vla)
return device_list
def Exe_command_ssh_client(device,command_file,Backup_file_name,code ):
if code == None:
code = "gb2312" #我是针对华三防火墙使用,所以默认编码是GB2312
save = open(Backup_file_name,'a',errors='ignore')
cmd = []
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(device["host"], 22, device["username"], device["password"])
for i in open(command_file,'r'):
cmd.append(i.replace('\n',''))
cmd_str = "\n ".join(cmd)
stdin, stdout, stderr = ssh.exec_command(cmd_str)
print('正在执行命令:',cmd)
result = stdout.read().decode(code).replace('\n','')
save.write(result)
print("命令执行完成!")
ssh.close()
print("断开连接"+ "\n\n\n")
save.close()
return result
def Exe_command(device,command_file,Backup_file_name):
save = open(Backup_file_name,'a',errors='ignore')
net_connect = ConnectHandler(**device)
net_connect.enable() #输入启用
for i in open(command_file,'r'):
cmd = i.replace('\n',' ')
print('正在执行命令:',cmd)
result = net_connect.send_command(cmd)
save.write(result)
print("命令执行完成!")
net_connect.disconnect()
print("断开连接"+ "\n\n\n")
save.close()
return result
def Connect(device,Backup_file_name,command_file,device_type,code):
print('正在连接{0}\n'.format(device['host']))
if device_type == "security":
#读取配置文件,配置文件存放在当前目录下
Exe_command_ssh_client(device,command_file,Backup_file_name,code)
elif device_type == "network":
Exe_command(device,command_file,Backup_file_name)
else:
print(device["host"] + "\t对应的设备类型不存在!")
def Huawei(ip,user,passwd):
huawei = {
'device_type':'huawei',
'host':ip,
'username':user,
'password':passwd,
}
return huawei
def H3c(ip,user,passwd): #如果是display 华三需要刷入额外命令,改变屏幕显示长度
h3c = {
'device_type':'hp_comware',
'host':ip,
'username':user,
'password':passwd,
}
return h3c
#
def Init(ip_file,dir_path,local_time):
device_list = Read_excel(ip_file)
for device_name in device_list.keys():
try:
if device_list[device_name][1] == 'huawei':
device = Huawei(device_list[device_name][0],device_list[device_name][3],device_list[device_name][4])
Backup_file_name = 'config_backup\\'+ dir_path + "\\" +device_list[device_name][2]+ "-" +local_time +'.txt'
Connect(device,Backup_file_name,command_file = "huawei_command.txt",device_type = device_list[device_name][5],code = device_list[device_name][6])
elif device_list[device_name][1] == 'h3c':
device = H3c(device_list[device_name][0],device_list[device_name][3],device_list[device_name][4])
Backup_file_name = 'config_backup\\'+ dir_path + "\\" +device_list[device_name][2]+ "-" + local_time + '.txt'
Connect(device,Backup_file_name,command_file = "h3c_command.txt",device_type = device_list[device_name][5],code = device_list[device_name][6])
else:
print('未定义设备!')
pass
except Exception as e:
print('连接超时:',e)
pass
time.sleep(1)
def menu():
print("注意仅有 security 的设备类型支持选择输出编码,不填写则默认gb2312;network 类型设备不能指定编码输出!")
print("-"*3+"选择执行周期:"+"-"*3 + "\n" +"1、一次\n" + "2、一天\n" + "3、三天\n" + "4、测试用(1小时)\n" + "5、退出\n")
num1 = input("请输入数字:")
if num1 == "1":
return 99999
elif num1 == "2":
return 86400
elif num1 == "3":
return 259200
elif num1 == "4":
return 1800
elif num1 == "5":
sys.exit(0)
else:
print("输入有误")
menu()
if __name__ == '__main__':
Flag = 0
sleep_time = menu()
if sleep_time == 99999:
Flag = 1
while True:
local_time = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime())
dir_path = time.strftime("%Y-%m-%d", time.localtime())
my_dir = Path("config_backup/"+dir_path+"/")
if my_dir.exists() == False:
os.makedirs("config_backup/"+dir_path)
Init('ip_add.xlsx',dir_path,local_time)
if Flag == 1:
break
else:
pass
time.sleep(sleep_time)
在该程序的目录下还需要以下几个文件或者文件夹:(exe文件忽略,是封装后的程序)
- config_backup 文件夹:用于存放获取配置文件,文件夹内会根据当前日期按天生成下级目录。
- h3c_command.TXT和huawei_command.TXT文本文件:用于存放华三和华为的执行命令。目前我只定义了两家厂商的设备。
- ip_add.xlsx表格:存放设备的登陆信息,以及设备编码信息。
ip_add.xlsx格式:
- 通过device_type可以选择执行命令的库:选择network则是使用netmiko执行;选择security是使用paramiko库执行,选择paramiko库时需要选择编码方式(code),不填写则默认GB2312
- device_company用于区分执行命令文件。
- device_name:为输出的配置文件名,文件名后会添加当前时间。
以上就是我的加强版设备备份程序,还请各位大佬指教。