netmiko运维网络设备

netmiko自动化配置网络设备

一、环境搭建

1.1 安装Python

Linux下自带python环境,但是Linux自带的python一般是比较老的版本,我们可以通过命令来查看Linux中python的版本

[root@localhost ~]# python --version
Python 2.7.5

建议大家在保留python2的基础上安装一个python3,因为python2和python3还是有一些区别的,同时安装python2和python3的环境,以便不时之需或者对比学习。

链接:https://www.python.org/downloads/source/

Snipaste_2023-12-04_10-23-57

1.2 安装python3

3.1首先解压源码包

tar -zxvf Python-3.10.13.tgz

3.2安装依赖包

yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel

3.3进入解压路径执行编译三部曲

cd Python-3.10.13
./configure --prefix=安装路径
make
make install

1.3 安装依赖模块netmiko

[root@backup backup]# pip3 install --trusted-host mirrors.huaweicloud.com -i https://mirrors.huaweicloud.com/repository/pypi/simple netmiko
[root@backup backup]# pip freeze | grep netmiko  #查看是否安装成功,如果是windows就是pip freeze | findstr netmiko

二、VRP配置自动存档

2.1 环境准备

配置脚本以及备份存档路径

[root@backup ~]# mkdir -p /backup/{script,data}

2.2 备份设备列表

准备号需要备份的设备,将设备ssh登录的ip、用户名、密码罗列准备再设备列表当中。

[root@backup ~]# cd /backup/script/
[root@backup script]# cat devices.txt 
IP地址    用户名    密码
192.168.10.1    user1    passwd1
192.168.20.1    user2    passwd2
192.168.30.1    user3    passwd3
192.168.40.1    user4    passwd4

2.3 编写备份脚本

编写备份脚本,脚本会自动登录设备执行display current-configuration查看设备配置,添加到备份温江当中。

[root@backup script]# cat HuaWeiVRP_backup.py 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import argparse
import time
from datetime import datetime
from netmiko import ConnectHandler

def load_devices_from_txt(file_path):
    """
    从文本文件中读取设备信息(字段以空格或 Tab 分隔):
       IP地址    用户名    密码
    空行及以 "#" 开头的行会被自动跳过。
    """
    devices = []
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith("#"):
                    continue
                parts = line.split()
                if len(parts) != 3:
                    print(f"格式错误,跳过该行:{line}")
                    continue
                device = {
                    "device_type": "huawei",  # 默认设备类型为华为
                    "ip": parts[0].strip(),
                    "username": parts[1].strip(),
                    "password": parts[2].strip()
                }
                devices.append(device)
    except Exception as e:
        print(f"加载设备列表文件失败:{e}")
    return devices

def backup_configuration(dev, backup_path):
    """
    针对单台华为设备进行配置备份:
      1. 连接设备;
      2. 执行 "display current-configuration" 命令获取配置;
      3. 将配置保存到备份目录中,生成的文件名格式为:[IP]_backup_[时间戳].txt
    """
    try:
        print(f"正在连接到设备 {dev['ip']} ...")
        net_connect = ConnectHandler(**dev,  conn_timeout=20)
    except Exception as e:
        print(f"连接 {dev['ip']} 失败: {e}")
        return

    config_command = "display current-configuration"
    try:
        print(f"[{dev['ip']}] 正在执行命令:{config_command}")
        config_output = net_connect.send_command(config_command)
    except Exception as e:
        print(f"[{dev['ip']}] 获取配置失败: {e}")
        net_connect.disconnect()
        return

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = os.path.join(backup_path, f"{dev['ip']}_backup_{timestamp}.txt")
    try:
        with open(filename, "w", encoding="utf-8") as f:
            f.write(config_output)
        print(f"[{dev['ip']}] 配置备份已保存到:{filename}")
    except Exception as e:
        print(f"[{dev['ip']}] 保存备份文件失败: {e}")

    net_connect.disconnect()
    print(f"[{dev['ip']}] 设备连接已关闭。\n")

def cleanup_old_backups(backup_path, retention_days=7):
    """
    清理备份目录内超过 retention_days 天的备份文件
    """
    now = time.time()
    retention_seconds = retention_days * 24 * 3600
    try:
        for fname in os.listdir(backup_path):
            file_path = os.path.join(backup_path, fname)
            if os.path.isfile(file_path):
                file_mtime = os.path.getmtime(file_path)
                if (now - file_mtime) > retention_seconds:
                    os.remove(file_path)
                    print(f"删除超过 {retention_days} 天的备份文件:{file_path}")
    except Exception as e:
        print(f"清理备份文件时出错:{e}")

def main():
    parser = argparse.ArgumentParser(
        description="备份华为设备配置(设备文件格式:IP 用户名 密码),每天执行一次,并保留最近7天的数据"
    )
    parser.add_argument("--backup-path", default="backup", help="备份文件存放目录(默认为 backup)")
    parser.add_argument("--devices-file", default="devices.txt", help="设备信息文本文件路径(默认为 devices.txt)")
    parser.add_argument("--retention-days", type=int, default=7, help="保留备份的天数(默认为 7 天)")
    args = parser.parse_args()

    # 确保备份目录存在
    if not os.path.exists(args.backup_path):
        os.makedirs(args.backup_path)
        print(f"创建备份目录:{args.backup_path}")

    devices = load_devices_from_txt(args.devices_file)
    if not devices:
        print("未加载到任何设备信息,请检查设备文件格式。")
        return

    for dev in devices:
        backup_configuration(dev, args.backup_path)

    cleanup_old_backups(args.backup_path, args.retention_days)

if __name__ == "__main__":
    main()

执行测试

注意运行之前修改devices.txt当中的设备登录信息。

[root@backup script]# python3 /backup/script/HuaWeiVRP_backup.py --backup-path /backup/data/ --devices-file /backup/script/devices.txt

image-20250417152349883

2.4 结合crontab实现每天存档

加入定时任务每天2点执行:

[root@backup data]# chmod +x /backup/script/HuaWeiVRP_backup.py
[root@backup data]# whereis python3
python3: /usr/local/bin/python3.9 /usr/local/bin/python3.9-config /usr/local/bin/python3 /usr/local/lib/python3.9
[root@backup script]# crontab -l
0 2 * * * /usr/local/bin/python3 /backup/script/HuaWeiVRP_backup.py --backup-path /backup/data/ --retention-days 30 --devices-file /backup/script/devices.txt >> /backup/script/backup.log 2>&1

注:--retention-days 30 是存档30天的意思。

ok!!!

这里把备份cisio的脚本也给出,同样的使用方法。

[root@kvm script]# cat cisio_backup.py 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import argparse
import time
from datetime import datetime
from netmiko import ConnectHandler

def load_devices(file_path):
    """
    从文本文件中加载设备信息,每一行的格式为:
       IP地址    用户名    密码
    空行或以 "#" 开头的行会被跳过。
    """
    devices = []
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith("#"):
                    continue
                parts = line.split()
                if len(parts) != 3:
                    print(f"格式错误,跳过该行:{line}")
                    continue
                device = {
                    "device_type": "cisco_ios",
                    "ip": parts[0].strip(),
                    "username": parts[1].strip(),
                    "password": parts[2].strip()
                }
                devices.append(device)
    except Exception as e:
        print(f"加载设备文件失败:{e}")
    return devices

def backup_device(dev, backup_path):
    """
    针对单台 Cisco 设备进行配置备份:
      1. 连接设备;
      2. 执行 "show running-config" 命令获取配置;
      3. 将配置保存到备份目录,文件名格式为:[IP]_backup_[时间戳].txt
    """
    try:
        print(f"正在连接到设备 {dev['ip']} ...")
        net_connect = ConnectHandler(**dev, conn_timeout=20)
    except Exception as e:
        print(f"连接 {dev['ip']} 失败: {e}")
        return

    config_command = "show running-config"
    try:
        print(f"[{dev['ip']}] 正在执行命令:{config_command}")
        config_output = net_connect.send_command(config_command)
    except Exception as e:
        print(f"[{dev['ip']}] 获取配置失败: {e}")
        net_connect.disconnect()
        return

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = os.path.join(backup_path, f"{dev['ip']}_backup_{timestamp}.txt")
    try:
        with open(filename, "w", encoding="utf-8") as f:
            f.write(config_output)
        print(f"[{dev['ip']}] 配置备份已保存到:{filename}")
    except Exception as e:
        print(f"[{dev['ip']}] 保存备份文件失败: {e}")

    net_connect.disconnect()
    print(f"[{dev['ip']}] 设备连接已关闭。\n")

def cleanup_backups(backup_path, retention_days):
    """
    清理备份目录中超过指定保留天数的备份文件
    """
    now = time.time()
    retention_seconds = retention_days * 24 * 3600
    try:
        for fname in os.listdir(backup_path):
            file_path = os.path.join(backup_path, fname)
            if os.path.isfile(file_path):
                file_mtime = os.path.getmtime(file_path)
                if (now - file_mtime) > retention_seconds:
                    os.remove(file_path)
                    print(f"删除超过 {retention_days} 天的备份文件:{file_path}")
    except Exception as e:
        print(f"清理备份文件时出错:{e}")

def main():
    parser = argparse.ArgumentParser(
        description="备份 Cisco 设备配置,每天执行一次,并保留指定天数的备份文件"
    )
    parser.add_argument("--backup-path", default="backup", help="备份文件存放目录(默认为 backup)")
    parser.add_argument("--devices-file", default="devices.txt", help="设备信息文件路径(默认为 devices.txt)")
    parser.add_argument("--retention-days", type=int, default=7, help="保留备份的天数(默认为 7 天)")
    args = parser.parse_args()

    if not os.path.exists(args.backup_path):
        os.makedirs(args.backup_path)
        print(f"创建备份目录:{args.backup-path}")

    devices = load_devices(args.devices_file)
    if not devices:
        print("未加载到任何设备信息,请检查设备文件格式。")
        return

    for dev in devices:
        backup_device(dev, args.backup_path)

    cleanup_backups(args.backup_path, args.retention_days)

if __name__ == "__main__":
    main()
posted @ 2025-04-17 16:08  国杰响当当  阅读(131)  评论(0)    收藏  举报