4. Netmiko批量运维入门

Netmiko 是 Paramiko 之上的一层“多厂商 SSH 驱动库”,它把不同厂商设备在登录提示符、分页机制、配置模式切换、保存命令上的差异封装成统一接口。对网络自动化来说,这意味着我们不必为 Cisco IOS、华为 VRP、H3C Comware、Juniper Junos 各写一套 Paramiko 交互逻辑,而是用同一套 Python 代码,通过 device_type 参数切换驱动,完成 show 命令采集、配置下发、分页处理、超时与异常控制,最终实现批量配置备份。

理解 Netmiko 的关键,是理解它内部的一次连接生命周期:建立 SSH 会话 → 识别提示符 → 进入特权/配置模式 → 发送命令 → 处理分页 → 读取回显 → 断开。下图展示了这一信号链与四类厂商驱动的对应关系,以及分页、超时、异常在链路中的位置。

Netmiko 连接生命周期与多厂商驱动映射 ① SSH 建链 host/port/凭据 ② 提示符识别 base_prompt ③ 模式切换 enable / config ④ 发送命令 send_command ⑤ 读取回显 read_timeout 分页处理(关键差异点) Cisco: --More-- | Huawei/H3C: ---- More ---- Junos: 自动关闭分页,无需处理 超时与异常控制 conn_timeout / read_timeout / auth_timeout NetmikoTimeoutException / AuthenticationException device_type 驱动映射 Cisco IOS cisco_ios enable 模式 / write memory 华为 VRP huawei system-view / save H3C Comware hp_comware system-view / save force Juniper Junos juniper_junos configure / commit 批量配置备份输出 backup/2025-01-15/ ├─ cisco_r1.cfg ├─ huawei_sw1.cfg ├─ h3c_sw2.cfg ├─ juniper_fw1.conf 每台设备独立 try/except,单点失败不影响整体任务

连接四类厂商设备

Netmiko 用 ConnectHandler 建立连接,核心参数是 device_type。不同厂商的驱动名不同,但调用方式完全一致。下面是一个连接 Cisco IOS 设备并执行 show 命令的最小示例:

from netmiko import ConnectHandler

device = {
    "device_type": "cisco_ios",
    "host": "192.168.1.1",
    "username": "admin",
    "password": "Cisco@123",
    "secret": "Enable@123",      # enable 密码
    "port": 22,
    "conn_timeout": 10,
    "read_timeout": 30,
}

with ConnectHandler(**device) as conn:
    conn.enable()                          # 进入特权模式
    output = conn.send_command("show version")
    print(output)

华为、H3C、Juniper 只需替换 device_type:华为用 huawei,H3C 用 hp_comware,Juniper 用 juniper_junos。注意 Junos 没有传统意义上的 enable 模式,conn.enable() 对 Junos 不适用,应直接发送 show 命令或进入 configure 模式。

发送 show 命令与配置命令

Netmiko 提供两个核心方法:send_command() 用于发送 show 类只读命令,返回字符串;send_config_set() 用于发送配置命令列表,自动进入配置模式、逐条下发、退出配置模式。例如给华为交换机批量下发 VLAN 配置:

config_commands = [
    "vlan 100",
    "description AUTO_VLAN_100",
    "quit",
]
conn.send_config_set(config_commands)
conn.save_config()   # 华为执行 save,Cisco 执行 write memory

send_config_set() 内部会根据驱动自动处理 system-view(华为/H3C)、configure terminal(Cisco)、configure(Junos)等模式切换,这是 Netmiko 相比裸 Paramiko 最大的价值。

分页、超时与异常处理

分页是批量运维中最常见的“坑”。Cisco 输出满屏出现 --More--,华为/H3C 出现 ---- More ----,如果不处理,send_command() 会一直等待直到 read_timeout 超时。Netmiko 默认在连接时发送 terminal length 0(Cisco)、screen-length 0 temporary(华为/H3C)来关闭分页,但部分老设备或权限受限账号可能失败,此时可显式设置:

conn.send_command("show running-config", expect_string=r"#")
# 或手动关闭分页
conn.send_command("terminal length 0")

超时参数需要区分三类:conn_timeout 控制 TCP 建链时间,auth_timeout 控制认证时间,read_timeout 控制命令回显读取时间。批量场景下建议 conn_timeout=10、read_timeout=60,避免大配置读取被误判超时。

异常处理必须逐台隔离。常见异常包括 NetmikoTimeoutException(连接或读取超时)、NetmikoAuthenticationException(账号密码错误)、ConfigInvalidException(配置命令被设备拒绝)。批量任务中,一台设备失败不应中断整个循环:

from netmiko import NetmikoTimeoutException, NetmikoAuthenticationException

for dev in devices:
    try:
        with ConnectHandler(**dev) as conn:
            cfg = conn.send_command("show running-config")
            save_backup(dev["host"], cfg)
    except NetmikoAuthenticationException:
        log.error(f"{dev['host']} 认证失败")
    except NetmikoTimeoutException:
        log.error(f"{dev['host']} 连接超时")
    except Exception as e:
        log.error(f"{dev['host']} 未知异常: {e}")

批量配置备份实战

把上述能力组合起来,就是一个可用的批量备份脚本。核心思路是:设备清单用列表或 CSV 维护,每台设备独立连接、独立采集、独立落盘,文件名包含主机名与日期,便于版本追溯。下面给出一个可直接参考的备份函数:

import os, datetime
from netmiko import ConnectHandler

BACKUP_DIR = "backup"

def backup_device(dev):
    host = dev["host"]
    today = datetime.date.today().isoformat()
    out_dir = os.path.join(BACKUP_DIR, today)
    os.makedirs(out_dir, exist_ok=True)

    with ConnectHandler(**dev) as conn:
        if dev["device_type"] == "cisco_ios":
            conn.enable()
            cfg = conn.send_command("show running-config")
            ext = "cfg"
        elif dev["device_type"] in ("huawei", "hp_comware"):
            cfg = conn.send_command("display current-configuration")
            ext = "cfg"
        elif dev["device_type"] == "juniper_junos":
            cfg = conn.send_command("show configuration")
            ext = "conf"
        else:
            raise ValueError("不支持的 device_type")

    path = os.path.join(out_dir, f"{host}.{ext}")
    with open(path, "w", encoding="utf-8") as f:
        f.write(cfg)
    return path

执行后,备份目录结构如下(示例):

backup/
└── 2025-01-15/
    ├── 192.168.1.1.cfg      # Cisco R1
    ├── 192.168.1.2.cfg      # 华为 SW1
    ├── 192.168.1.3.cfg      # H3C SW2
    └── 192.168.1.4.conf     # Juniper FW1
判断备份是否成功,不能只看脚本是否报错。应检查:文件是否生成、文件大小是否明显偏小(如小于 500 字节可能只采到提示符)、内容是否包含关键配置段(如 interface、vlan、hostname)。建议在脚本末尾打印每台设备的备份路径与字节数,便于快速核对。
生产环境不要用明文密码硬编码在脚本里。建议从环境变量、加密配置文件或密钥管理服务读取凭据;同时为自动化账号分配最小权限,避免误操作影响业务。

掌握以上内容后,你已经可以用 Netmiko 完成四类主流厂商设备的连接、命令下发、分页处理、异常隔离与批量备份。下一阶段可以在此基础上引入并发(如 concurrent.futures)提升大批量设备采集效率,但并发前务必先确认单台设备的超时与异常处理已经稳定。