Excel表格存放交换机信息:
备份文件夹效果图:
Windows系统配置计划任务定时执行python脚本:
Program/script: C:\Python\python.exe
Add arguments (optional): D:\Python_PycharmProjects\JunLan_pythonProject1\Python_CodeFile\netmiko\Batch_backup_Huawei_switch_configuration_to_FTP.py
完整Python代码:
python
'''
该代码用于批量备份网络设备配置。通过读取Excel表格中的设备IP地址和登录凭据,使用netmiko库连接设备并备份配置。
具体实现方法包括:读取Excel表格中的设备IP地址和登录凭据;使用netmiko库连接设备;使用send_command_timing()方法下发交换机命令获,将获取的配置上传到FTP服务器。
注意事项:1、FTP服务器的IP地址、用户名和密码需要提前配置好;2、ftp命令中的文件名不能包含空格或其他特殊字符。3、ftp命令中的文件名不能超出64个文字。
'''
from netmiko import ConnectHandler, NetmikoTimeoutException, NetmikoAuthenticationException
from openpyxl import load_workbook
from rich.progress import track
from datetime import datetime
import socket, os
def read_excel_data(): # 设定一个函数来读取Excel数据
file_path = r'D:\Network_Backup\IT_assets.xlsx' # 在函数内部定义Excel文件路径
workbook = load_workbook(filename=file_path) # 加载Excel文件
sheet = workbook["Huawei"] # 指定名为"Huawei"的工作表
# 获取各列数据
ips = [cell.value for cell in sheet['C'][1:]] # 获取IP地址列数据,从第二行开始
names = [cell.value for cell in sheet['D'][1:]] # 获取设备名称列数据
username_col = [cell.value for cell in sheet['E'][1:]] # 获取用户名列数据
password_col = [cell.value for cell in sheet['F'][1:]] # 获取密码列数据
return ips, names, username_col, password_col # 返回获取到的数据
def ssh_connection():
ips, names, username_col, password_col = read_excel_data() # 调用(执行)函数读取Excel数据,赋予变量,这里使用相同的变量名
num_switches = min(len(ips), len(names), len(username_col), len(password_col)) # 获取交换机数量,确定循环次数,以较短的数据范围为准
ftp_host = '10.1.74.23' # FTP 服务器的 IP 地址
ftp_username = 'ftpbackup' # FTP 服务器的用户名
ftp_password = 'qbk>c]0a' # FTP 服务器的密码
success_count = 0 # 初始化成功计数器
failure_count = 0 # 初始化失败计数器
backup_dir = os.path.join(r'D:\Network_Backup', f"{datetime.now().strftime('%Y%m%d')}") # 创建备份目录,以当前日期命名
log_file_path = os.path.join(backup_dir, "Huawei_backup_summary.log") # 创建日志文件,保存连接错误信息
output_data_file = os.path.join(backup_dir, "Huawei_output_data.txt") # 创建输出数据文件,即回显内容保存的文件
if not os.path.exists(backup_dir): # 判断是否存在该文件夹
os.makedirs(backup_dir) # 不存在则创建文件夹
new_folder_name = os.path.basename(backup_dir) # 获取新创建的文件夹名称
# print(f"New folder created: {new_folder_name}")
with open(log_file_path, 'a') as log_file: # 使用 'a' 模式以追加方式打开日志文件
with open(output_data_file, 'a') as data_file: # 使用 'a' 模式以追加方式打开数据文件,即用来保存回显内容
for i in track(range(num_switches), description="Running..."): # 遍历交换机,使用 track 函数显示进度条
try:
ip = ips[i] # 获取 IP 地址
name = names[i] # 获取交换机名称
username = username_col[i] # 获取当前索引i对应的用户名信息
password = password_col[i] # 获取当前索引i对应的密码信息
now = datetime.now() # 获取当前日期和时间
now_time = now.strftime("%Y%m%d_%H%M%S") # 格式化为年月日_时分秒
new_name_huawei = f"{name.replace(' ', '')}_{ip}_{now_time}_vrpcfg.zip" # 使用交换机名称、IP地址和当前时间生成新的文件名,其中name.replace将有空格的字符串替换为空字符串。
put = 'put vrpcfg.zip ' + new_name_huawei
device = { 'device_type': 'huawei_ssh', # 指定连接的类型
'ip': ip, # 从excel文件中获取IP地址
'username': username, # 从excel文件中获取用户名
'password': password, # 从excel文件中获取用户名
'conn_timeout': 20, # 连接超时时间默认为10秒,大多数情况下 15 秒足以应对网络传输中的大多数问题。
}
with ConnectHandler(**device) as net_connect: # 连接交换机
output = net_connect.send_command_timing('save ') # 保存配置
output += net_connect.send_command_timing('y') # 确认保存配置
output += net_connect.send_command_timing(f'ftp {ftp_host}') # 在交换机上执行连接 FTP 命令
output += net_connect.send_command_timing(ftp_username) # 输入FTP服务器用户名
output += net_connect.send_command_timing(ftp_password) # 输入FTP服务器密码
output += net_connect.send_command_timing(f'cd {new_folder_name}') # 切换到新创建的文件夹
output += net_connect.send_command_timing(put) # 执行 put 命令保存配置文件到 FTP 服务器,命令格式:put 本地(交换机)文件名 远程文件名
output_data = f"Device {ip} ({name}):\n{output}\n" # 将执行输出的内容转换为字符串,赋予给变量
# print(output_data)
if "226 Successfully transferred" in output_data: # 判断配置文件是否成功传输到FTP服务器
success_count += 1 # 统计成功计数器加1
print(f"File transfer successful for device {ip} {name}")
else:
failure_count += 1
print(f"File transfer failed for device {ip} {name}")
log_file.write("File transfer failed for device {ip} {name}")
data_file.write(put + "\n\n" + output_data + "\n" + "-" * 200 + "\n") # 将执行输出的内容写入到文件中
except Exception as e: # 捕获 NetmikoTimeoutException 异常,该异常通常在尝试连接设备超时时抛出
error_message = f"An error occurred while processing Device {ip} ({name}): {str(e)}\n"
# print(error_message, end="") # 不希望打印错误可注释
log_file.write(error_message + "\n" + "-" * 200 + "\n") # 将错误信息追加写入到日志文件中
failure_count += 1 # 当捕获到异常时,增加失败计数
except NetmikoTimeoutException as timeout_e: # 当与网络设备建立SSH连接时,如果超过预设的超时时间仍未成功,则会捕获此异常并打印相关错误信息。
error_message = f"Timeout occurred while connecting to Device {ip} ({name}): {str(timeout_e)}"
log_file.write(error_message + "\n" + "-" * 200 + "\n") # 将错误信息追加写入到日志文件中
failure_count += 1 # 当捕获到异常时,增加失败计数
except NetmikoAuthenticationException as auth_e: # 当提供的用户名或密码无法通过网络设备的验证时,将捕获此异常并输出认证失败的具体信息。
error_message = f"Authentication failed for Device {ip} ({name}): {str(auth_e)}"
log_file.write(error_message + "\n" + "-" * 200 + "\n") # 将错误信息追加写入到日志文件中
failure_count += 1 # 当捕获到异常时,增加失败计数
except socket.timeout as sock_timeout: # 这是在底层网络通信过程中遇到超时时抛出的异常,在进行网络连接时(例如:TCP连接阶段),如果等待响应的时间超过了设置的超时值,那么就会触发此异常,并打印相应的超时信息。
error_message = "Socket timeout occurred while connecting to Device {ip} ({name})."
log_file.write(error_message + "\n" + "-" * 200 + "\n") # 将错误信息追加写入到日志文件中
failure_count += 1 # 当捕获到异常时,增加失败计数
except KeyboardInterrupt: # 捕获用户手动中断(如按 Ctrl+C)
print("\nProgram interrupted by user.")
break
summary_message = "\nSummary:\nSuccessfully processed {} devices.\n{} devices failed to be processed.\n".format(success_count, failure_count)
log_file.write(summary_message + "\n" + "-" * 200 + "\n") # 将成功和失败的数量写入到日志文件中
# print(summary_message) # 打印成功和失败的数量
if __name__ == "__main__":
ssh_connection() # 调用(执行)函数进行 SSH 连接和配置文件下载
# print(num_switches)