python用于备份H3C网络设备

  • 作为运维工程师,需要定期去备份网络设备的配置文件,以备不时之需。有问题随时交流

  • H3C设备(包括防火墙、交换机、AC控制器等)需要开启ssh远程登陆,并且具有管理权限

  • 目前ComwareV5和ComwareV7版本测试通过。

  • H3C设备侧配置,用户名自己可以命名:
    用户名配置
    local-user h3c_admin class manage
    password hash gutxPXFKFH$8PaVCqKRK1CxuS9p0tDRN0s/r1HxJ74AsjC9bUg3U8PaVCqKRK1CxuS9p0tDRN0s/r1Hx8PaVCqKRK1CxuS9p0tDRN0s/r1Hx
    service-type ssh terminal
    authorization-attribute user-role level-15
    authorization-attribute user-role network-operator

    开启ssh登陆
    ssh server enable
    ssh user h3c_admin service-type stelnet authentication-type password

  • 新建H3C设备列表文件,文件名为h3c_devices.csv 包含五个字段hostname,ip,port,username,password 例如以下格式

    hostname,ip,port,username,password
    SHXH-CXL-CORE-01,172.31.254.1,22,h3c_admin@system,Admin1234
    SHXH-CXL-AS-01,172.31.254.2,22,h3c_admin@system,Admin1234

  • 以下python脚本,脚本当中涉及到的变量请根据自己的实际情况调整。

'''
自动创建backups 目录并且生成以日期为名称的文件夹,将交换机配置文件保存本地文件目录
自动上传配置到ftp服务器,文件目录为backups,以日期为名称的文件夹
邮件推送备份情况通知
'''

import os
import time
from datetime import datetime
from netmiko import ConnectHandler
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from ftplib import FTP
import csv

def backup_config(device, target_directory):
    device_info = {
        'device_type': 'hp_comware',
        'ip': device['ip'],
        'username': device['username'],
        'password': device['password'],
        'port': device['port'],  # Default SSH port
        'secret': '',  # This is the enable password
        'verbose': False,
    }

    try:
        connection = ConnectHandler(**device_info)
        connection.enable()
        # Increase the timeout to allow for larger configurations
        connection.timeout = 30  # Increase the default timeout if needed
        output = connection.send_command("display current-configuration")
        connection.disconnect()

        # Print the output for debugging purposes
        # print(f"Output for {device['hostname']}:")
        # print(output)

        # 使用 GBK 编码写入文件 使用 encoding='gbk' 和 errors='replace' 来处理非法字符。
        # 这样可以确保即使遇到非法字符也能继续写入文件,而不是抛出异常。
        filename = f"{target_directory}/{device['hostname']}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.cfg"
        with open(filename, "w", encoding='gbk', errors='replace') as file:
            file.write(output)
            # print(f"Wrote {len(output)} characters to {filename}")

        return filename, True

    except Exception as e:
        print(f"Failed to backup {device['hostname']}: {e}")
        return None, False

def upload_to_ftp(filename, ftp_server, ftp_port, ftp_username, ftp_password, base_ftp_directory):
    try:
        with FTP() as ftp:
            ftp.connect(host=ftp_server, port=ftp_port)
            ftp.login(user=ftp_username, passwd=ftp_password)

            # 获取当前日期并格式化为字符串
            current_date = datetime.now().strftime("%Y-%m-%d")

            # 构建 FTP 上的完整目录路径
            ftp_directory = os.path.join(base_ftp_directory, current_date)

            print("Switching to /backups directory...")
            # 首先切换到 /backups 目录
            try:
                ftp.cwd('/backups')
            except Exception as e:
                print("Failed to switch to /backups directory: ", e)
                # 如果 /backups 不存在,则尝试创建
                try:
                    print("Creating /backups directory...")
                    ftp.mkd('/backups')
                    ftp.cwd('/backups')
                except Exception as e:
                    print("Failed to create /backups directory: ", e)
                    raise

            print(f"Creating or switching to {current_date} directory...")
            # 创建日期子目录
            try:
                ftp.cwd(current_date)
            except Exception as e:
                # 子目录不存在,创建它
                ftp.mkd(current_date)
                ftp.cwd(current_date)

            print(f"Uploading {filename}...")
            # 上传文件
            with open(filename, "rb") as file:
                ftp.storbinary(f'STOR {os.path.basename(filename)}', file)
            print(f"Uploaded {filename} successfully.")
        return True
    except Exception as e:
        print(f"Failed to upload {filename} to FTP: {e}")
        return False

def ftp_directory_exists(ftp, directory):
    try:
        # 尝试切换到目录
        ftp.cwd(directory)
        return True
    except Exception as e:
        # 如果切换失败,则目录不存在
        return False

def create_ftp_directories(ftp, directory):
    if directory == '':
        return

    try:
        # 分离出子目录和父目录
        parent, subdirectory = os.path.split(directory)

        # 如果父目录不为空,先切换到父目录
        if parent:
            ftp.cwd(parent)

        # 如果当前目录不存在,则创建
        if not ftp_directory_exists(ftp, directory):
            ftp.mkd(subdirectory)
    except Exception as e:
        print(f"Error creating directory: {e}")

def read_devices_from_csv(filename):
    devices = []
    with open(filename, newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            devices.append({
                'hostname': row['hostname'],
                'ip': row['ip'],
                'port': int(row['port']),
                'username': row['username'],
                'password': row['password']
            })
    return devices

    # 修改以下邮件服务器地址,用于发送备份报告的邮箱账号和密码
def send_email(subject, body, to):
    server = smtplib.SMTP('mail.xx.cn', 587)
    server.starttls()
    server.login('report@xx.cn', 'Password123')

    msg = MIMEMultipart()
    msg['From'] = 'report@xx.cn'
    msg['To'] = ', '.join(to)
    msg['Subject'] = subject

    msg.attach(MIMEText(body))

    server.send_message(msg)
    server.quit()


def main():
    # devices.csv更新设备信息
    devices = read_devices_from_csv('h3c_devices.csv')

    # 定义输出目录
    output_folder = "backups"

    # 获取当前日期并格式化为字符串
    current_date = datetime.now().strftime("%Y-%m-%d")

    # 构建完整的文件夹路径
    target_directory = os.path.join(output_folder, current_date)

    # 如果输出目录不存在,则创建
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 如果子文件夹不存在,则创建
    if not os.path.exists(target_directory):
        os.makedirs(target_directory)

    successful_backups = []
    failed_backups = []

    # 确保 FTP 目录 /backups 已经存在,修改以下FTP服务器地址,端口号,用户名,密码,目录
    try:
        with FTP() as ftp:
            ftp.connect(host='10.0.0.22', port=2121)
            ftp.login(user='h3c', passwd='h3c@123321')
            if not ftp_directory_exists(ftp, '/backups'):
                ftp.mkd('/backups')
    except Exception as e:
        print(f"Failed to create /backups directory on FTP: {e}")

    for device in devices:
        print(f"Backing up {device['hostname']}...")
        backup_file, success = backup_config(device, target_directory)
        if success:
            successful_backups.append(device['hostname'])
                # 修改以下FTP服务器地址,端口号,用户名,密码,目录
            if not upload_to_ftp(backup_file, '10.0.0.22', 2121, 'h3c', 'h3c@123321', '/backups'):
                # 如果FTP上传失败,则从successful_backups列表中移除该设备,并添加到failed_backups列表中
                successful_backups.remove(device['hostname'])
                failed_backups.append(device['hostname'])
        else:
            failed_backups.append(device['hostname'])

    # Prepare the email message
    body = "Backup Report:\n\n"
    if successful_backups:
        body += f"Successful Backups ({len(successful_backups)}):\n"
        for hostname in successful_backups:
            body += f"- {hostname}\n"

    if failed_backups:
        body += f"\nFailed Backups ({len(failed_backups)}):\n"
        for hostname in failed_backups:
            body += f"- {hostname}\n"

    send_email(
        "Backup Report",
        body,
        ["luoguoguo@xx.com"]
    )

if __name__ == "__main__":
    main()

posted @ 2024-11-13 14:04  凡人的四季  阅读(3)  评论(0编辑  收藏  举报