Python批量备份华为设备配置到FTP服务器

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)
相关推荐
drebander8 分钟前
使用 Java Stream 优雅实现List 转化为Map<key,Map<key,value>>
java·python·list
tangliang_cn16 分钟前
java入门 自定义springboot starter
java·开发语言·spring boot
程序猿阿伟17 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
新知图书28 分钟前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
威威猫的栗子30 分钟前
Python Turtle召唤童年:喜羊羊与灰太狼之懒羊羊绘画
开发语言·python
力透键背30 分钟前
display: none和visibility: hidden的区别
开发语言·前端·javascript
bluefox197931 分钟前
使用 Oracle.DataAccess.Client 驱动 和 OleDB 调用Oracle 函数的区别
开发语言·c#
ö Constancy1 小时前
c++ 笔记
开发语言·c++
墨染风华不染尘1 小时前
python之开发笔记
开发语言·笔记·python
徐霞客3201 小时前
Qt入门1——认识Qt的几个常用头文件和常用函数
开发语言·c++·笔记·qt