记一个相对通用的远程备份交换机配置文件的脚本--python
脚本部分
import paramiko
import time
import re
import tarfile, os
from datetime import datetime
def clean_output(raw_output):
# 使用正则表达式去除 ANSI 转义序列和特殊字符
cleaned_output = re.sub(r'\x1b\[[0-9;]*[mGK]', '', raw_output)
# 保留可见字符和换行符
cleaned_output = ''.join(char for char in cleaned_output if char.isprintable() or char == '\n')
return cleaned_output
def get_switch_config(ip, username, password, conf_dir):
conf_name = conf_dir + ip + ".conf"
print("开始写入文件 ", conf_name)
with open(conf_name, "w"):
pass
with open(conf_name, "a", encoding='latin-1') as file:
# 创建一个SSH客户端
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接到交换机
client.connect(ip, username=username, password=password)
# 创建一个shell会话
channel = client.invoke_shell()
# 发送命令,获取配置
channel.send("dis cu\n")
time.sleep(5) # 等待命令执行
output = ''
while not channel.recv_ready():
time.sleep(0.1)
while channel.recv_ready():
output += channel.recv(65535).decode('latin-1')
# Remove the ANSI escape codes (e.g., '\x1b[42D')
output = re.sub(r'\x1b\[\d+D', '', output)
output = clean_output(output)
ends = "---- More ----"
w = False
if output.rstrip().endswith(ends):
w = True
output = output.rstrip().rstrip(ends).rstrip()
output = output.split('dis cu')[-1]
# print(output)
if not w:
last_newline = output.rfind('\n')
if last_newline != -1:
output = output[:last_newline] # 去除最后一行(包括换行符)
file.write(output)
file.write("\n")
while w:
# print("===========")
channel.send(" ")
time.sleep(5)
while not channel.recv_ready():
time.sleep(0.1)
output = ""
while channel.recv_ready():
output += channel.recv(65535).decode('latin-1')
# Remove the ANSI escape codes (e.g., '\x1b[42D')
output = re.sub(r'\x1b\[\d+D', '', output)
output = clean_output(output)
output = output.strip()
if output.endswith(ends):
output = output.rstrip(ends).strip()
else:
w = False
last_newline = output.rfind('\n')
if last_newline != -1:
output = output[:last_newline] # 去除最后一行(包括换行符)
# print(output)
file.write(output)
file.write("\n")
# 关闭连接
client.close()
def create_tar_gz_archive(files_to_archive):
# 获取当前日期和时间,并格式化为字符串
current_datetime = datetime.now().strftime("%Y%m%d_%H%M%S")
output_filename = f"{current_datetime}.tar.gz"
print("开始创建压缩包 ", output_filename)
with tarfile.open(output_filename, "w:gz") as tar:
for file in files_to_archive:
tar.add(file, arcname=os.path.basename(file))
def delete_files(file_list):
print("开始清理临时文件......")
for file in file_list:
try:
os.remove(file) # 或者使用 os.unlink(file)
print(f'Deleted file: {file}')
except OSError as e:
print(f'Error deleting file {file}: {str(e)}')
if __name__ == '__main__':
# 交换机信息
host = [
["192.168.1.2", 'xxxxxxxx', 'xxxxxxxxxxxxx'],
["192.168.1.3", 'xxxxxxxx', 'xxxxxxxxxxxxx'],
["192.168.1.4", 'xxxxxxxx', 'xxxxxxxxxxxxx'],
["192.168.1.5", 'xxxxxxxx', 'xxxxxxxxxxxxx'],
]
conf_dir = "./"
for i in host:
print("开始备份", i[0], "的配置文件")
get_switch_config(*i, conf_dir)
# 文件列表
files_to_archive = [conf_dir + i[0] + ".conf" for i in host]
# 打包
create_tar_gz_archive(files_to_archive)
# 删除临时文件
delete_files(files_to_archive)
编写脚本中遇到的问题
如何导出配置文件
这里采用的是比较原始的方法,通过查看配置文件,然后拼凑出来,这个过程是非常慢的,需要等文本全出来了再发送出来,这个就需要设置等待时间,而每次的等待时间并不是固定的,所以,就需要尽量把时间设置的合适点,否则出来的字符串就是不全的。
为什么会这么做,因为这边的交换机品牌不一样,型号不一致,所以,无法使用比较统一的便捷方法。
以前为统一设备型号的网络设备写过备份脚本,是通过tftp来接收配置文件,然后在交换机上执行发送命令就可以了,这种是最快最方便的方法,也是最省事的。
配置文件过长
配置文件过长,显示一部分,会在结尾加上 ---- More ----
,然后需要发送空格,才会给出下面部分的配置,所以上面的部分就会有判断文末是否有 ---- More ----
,有的话,就发送空格
不过,也有其他的解决版本(如果能够修改交换机配置文件的话)
<设备名称>system-view
[设备名称]user-interface vty 0 4 // 进入虚拟终端接口配置模式
[设备名称-ui-vty0-4]screen-length 0 // 设置行数限制为0,表示不限制行数
设置过后,就不再会出现 ---- More ----
了,但是查看配置的时候就会麻烦些
乱码的问题
在导出配置文件时,如果配置中存在非常见字符,会在接收的时候出现报错
这里试了好几种码,也就 latin-1
通用
所以,咱们这里就使用的 latin-1
channel.recv(65535).decode('latin-1')
输出的配置总是前面夹在这一些特殊空格字符
在导出时,总是会遇到前面有一段空格,但是通过 strip()
又无法剔除,后来发现,是一些不可显示的特殊字符
这边用的剔除方法
def clean_output(raw_output):
# 使用正则表达式去除 ANSI 转义序列和特殊字符
cleaned_output = re.sub(r'\x1b\[[0-9;]*[mGK]', '', raw_output)
# 保留可见字符和换行符
cleaned_output = ''.join(char for char in cleaned_output if char.isprintable() or char == '\n')
return cleaned_output
output = re.sub(r'\x1b\[\d+D', '', output)
output = clean_output(output)
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/17714778.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端