1. 项目概述
1.1 核心需求解析
做网络运维的朋友应该都遇到过这种情况:设备台账里躺着几十上百台华为交换机,领导要求每周出一份巡检报告,还要把所有设备的配置备份到本地。手动登录每台设备,敲几条命令看状态,再一条条复制配置内容……运气好两个小时搞定一台核心设备,运气不好赶上设备性能波动,命令回显半天不出来,整个人坐在机房或者工位上,心里全是"什么时候能干完"。
这个项目的核心就是解决这个痛点:用 Python 写一套脚本,自动登录华为交换机,批量执行巡检命令收集设备状态,再把每台设备的配置文件和关键运行状态自动备份到本地。我最初的目标很简单:每天早上到工位,双击一下脚本,喝杯水回来,巡检报告和备份文件都已经躺在文件夹里了。
适合谁来参考?第一类是像我一样负责中小规模网络、手里管着几十台设备的运维工程师,第二类是刚入行、想用 Python 提升网工效率的朋友,第三类是要做自动化运维转型、想了解网络设备南向接口怎么玩的同学。项目本身不难,但把登录、执行、解析、备份这一套流程跑通,你能省下的时间非常可观。
1.2 项目最终效果
脚本跑完以后,你会在本地目录里看到类似这样的结构:
backup/ ├── config_20250115/ │ ├── S5700-01_config.txt │ ├── S5700-02_config.txt │ └── ... └── report_20250115/ ├── S5700-01_report.txt └── ...每台设备一个配置文件、一份巡检报告。配置文件里是设备的完整 running-config 和 startup-config,巡检报告里记录了设备名、型号、系统运行时间、CPU 内存利用率、接口状态、告警日志里的关键异常、VRRP 状态、DHCP 地址池状态这些核心信息。整个流程跑下来,平均每台设备耗时在 30 秒到 1 分钟之间,和手动登录操作一比,效率提升非常明显。
2. 整体方案设计与技术选型
2.1 为什么选 Python 而不是现成的网管软件
有人可能会问:华为有 eSight,第三方有 SolarWinds、Zabbix,为什么还要自己写脚本?说实话,正经大厂部署一套完整网管平台,效果确实比脚本强,但问题是:很多中小企业只有两三台核心交换机,为一个几百台设备的网管平台花几万块买授权、搞服务器,完全不现实。而且商业网管软件在做"配置备份"这件事上,往往做得比较重——要装 Agent、要配 SNMP 告警、要维护 CMDB,都是系统工程。
Python 的好处恰恰是轻量。我只需要一台能联网的电脑,装个 Python 3 环境,加两个第三方库,写一套逻辑简洁的脚本,就能把"巡检"和"备份"这两件高频重复的日常任务自动掉。对运维来说,日常工作中最贵的是时间,用最小成本解决最痛的问题,这才是关键。
2.2 技术栈拆解
项目里我用到了这几样东西:
- Python 3.8+:当前主流版本,对第三方库的支持最稳。
- Netmiko:这是一个基于 Paramiko 的库,专门用来做网络设备的 SSH 连接和命令交互。它最大的价值在于把"登录设备、进入 enable 模式、关闭分页、执行命令、读取输出"这些重复劳动封装成了简单的 API。
- Paramiko:Netmiko 底层依赖的 SSH 协议实现库,负责真正建立加密连接。
- textfsm / re:处理命令回显文本时,用来做正则表达式匹配和模板解析。
- pandas / openpyxl:把解析出来的结构化信息写入 Excel 格式的巡检报告。
这里我特别说一下为什么选 Netmiko。直接用 Paramiko 我也试过,确实能做,但需要手工处理很多细节,比如命令回显的读取时机、设备的分页提示符(---- More ----)要怎么翻页、enable 模式的切换。Netmiko 把这些都封装掉了,你只需要告诉它设备的 IP、用户名、密码、设备类型,它就能自动完成交互过程。不过要注意,Netmiko 本质上只是给 Paramiko 包了一层友好的接口,你在深入调试时还是能遇到 SSH 层面的问题,后面我会在常见问题里详细展开。
2.3 设备访问方式的选择
华为交换机支持的远程管理方式有 SSH、Telnet、SNMP 和通过网络管理接口的 Web 页面。我的选择是 SSH,理由很简单:
- Telnet 是明文传输,密码在网络里裸奔,这在生产环境里要尽量避免。
- SNMP 适合读取状态信息,但配置备份和完整巡检命令的执行能力很弱。
- Web 页面交互复杂,无法脚本化。
SSH 是网络设备自动化的标准通道,安全性好、交互可控性高,Netmiko 对华为设备的 SSH 支持也很成熟。如果你的网络环境里面有些老旧设备只支持 Telnet,我也会给一个备选方案,但建议优先级不要放在 SSH 前面。
2.4 整体流程规划
整个项目的执行流程分为四步:
- 设备清单维护:用一个 Excel 或 yaml 文件记录所有待巡检设备的 IP、名称、登录账号密码、设备类型。
- 连接与命令执行:脚本读取清单后,逐台通过 SSH 连接设备,依次执行巡检命令。
- 配置备份:抓取 display current-configuration 的输出,写入以设备名和日期命名的文本文件。
- 报告生成:把巡检命令的输出做关键字分析和状态提取,生成一份可读的巡检报告。
这个流程写起来并不复杂,但实际执行时有很多坑。比如华为设备的display current-configuration输出非常长,默认会分页,如果没关掉分页,脚本会卡死在---- More ----提示符上。又比如不同型号的华为交换机,命令回显的格式存在细微差异,做文本解析时不能把正则写死。
3. 环境准备与依赖安装
3.1 安装 Python 环境
我默认你的电脑是 Windows,Linux 和 macOS 的操作逻辑类似,只是安装包下载方式不同。
去 Python 官网下载对应你操作系统的安装包,版本选 3.8 或更高就行,注意安装时勾选Add Python to PATH这个选项。如果不勾选,后续在命令行里输入python会提示找不到命令,这个坑很常见。
安装完成后,在命令行输入python --version,能正常输出版本号就说明装好了。我当前用的版本是 3.10,跑这个项目没有任何问题。
如果提示python不是内部或外部命令,去 Windows 的"设置 -> 系统 -> 关于 -> 高级系统设置 -> 环境变量",把 Python 的安装目录和Scripts子目录加到Path变量里,保存后重新打开命令行。
3.2 安装第三方依赖库
在命令行依次执行下面两条命令:
pip install netmiko pip install pandas openpyxl如果你在公司内网环境,可能没有外网权限,pip 会一直卡在连接超时。这种情况建议用公司内部搭建的 PyPI 镜像源,或者临时用国内镜像源。命令可以这样写:
pip install netmiko -i https://pypi.tuna.tsinghua.edu.cn/simple安装完以后,可以用pip show netmiko确认版本。我这里用的 Netmiko 版本是 4.x,如果你用的是老版本(比如 3.x),部分 API 的返回结构会有细微差异,遇到问题先升级库再说。
3.3 设备侧的准备工作
华为交换机默认可能只开放了 Telnet 或 Console 管理口,要支持 SSH 远程登录,需要在设备上手动开启 SSH 服务。这是个常见的前置条件,很多人在跑脚本时发现连不上,最后排查半天发现是设备 SSH 功能压根没开。
设备上的配置大概如下:
system-view stelnet server enable ssh user admin authentication-type password ssh user admin service-type stelnet local-user admin password irreversible-cipher yourpassword local-user admin service-type ssh配置完成后,用任意 SSH 客户端(比如 PuTTY)先手动连一次,确认能正常登录。这一步很关键,如果 PuTTY 都连不进去,脚本更不可能连上。
4. 核心脚本实现
4.1 设备清单文件设计
我建议用 Excel 文件来维护设备清单,运维同事看起来直观,修改也方便。表格结构长这样:
| 设备名 | 管理IP | 用户名 | 密码 | 端口 | 设备类型 |
|---|---|---|---|---|---|
| S5700-01 | 192.168.1.10 | admin | password123 | 22 | huawei |
| S5710-02 | 192.168.1.11 | admin | password123 | 22 | huawei |
设备类型这里写huawei,Netmiko 会识别并选择对应的交互逻辑。如果你的环境里混入了思科设备,把设备类型换成cisco_ios就行,但命令集 middleware 得调整,后面会讲到。
4.2 核心登录与命令执行模块
先写一个最基础的版本,验证网络连通性和登录逻辑。下面是核心代码:
from netmiko import ConnectHandler import time device = { "device_type": "huawei", "ip": "192.168.1.10", "username": "admin", "password": "password123", "port": 22, "timeout": 30, } connection = ConnectHandler(**device) output = connection.send_command("display version") print(output) connection.disconnect()send_command是同步阻塞的,命令执行完、回显读取完毕才返回。这里你可能会遇到两个小问题:
- 如果设备上开启了交互式确认(比如
display current-configuration在某些设备上会询问是否需要分页),Netmiko 的默认逻辑可能处理不了,需要你在设备侧关闭相应交互。 - 如果命令执行时间特别长,超过了 Netmiko 的默认超时时间,会抛出超时异常。我建议在设备连接参数里显式设置
timeout和session_timeout,两边都拉长一点。
下面是带超时配置的优化版本:
from netmiko import ConnectHandler device = { "device_type": "huawei", "ip": "192.168.1.10", "username": "admin", "password": "password123", "port": 22, "timeout": 60, "session_timeout": 60, } connection = ConnectHandler(**device) connection.enable()这里有个细节:华为设备的enable模式和思科的密码机制不同。华为默认没有单独的 enable 密码,如果你在设备上设置了super密码,需要给ConnectHandler传递secret参数,然后enable()才会切换成功。如果你不确定设备有没有配置 super 密码,先手动登录敲一下system-view看能不能进。
4.3 巡检命令清单
巡检的核心是收集哪些信息?我把日常运维中必须关注的点整理成了下面的命令清单:
| 命令 | 巡检目标 |
|---|---|
| display version | 设备型号、软件版本、运行时间 |
| display device | 硬件状态,查看是否有异常部件 |
| display cpu-usage | CPU 利用率 |
| display memory-usage | 内存利用率 |
| display temperature | 设备温度 |
| display interface brief | 接口状态概览,是否有 Down 口 |
| display current-configuration | 设备当前配置 |
| display logbuffer | 系统日志缓冲区中的告警和错误信息 |
| display vrrp brief | 如果跑 VRRP,确认主备状态 |
| display dhcp server ip-pool | 如果开了 DHCP 服务,确认地址池状态 |
执行这些命令时,合理的顺序很重要。状态类命令(version、device、cpu、memory、temperature)应该优先执行,因为它们执行快、能快速判断设备是否健康;配置类命令(display current-configuration)放在最后执行,因为它输出量大、耗时长。万一中途脚本断掉,你已经拿到了最关键的状态信息。
4.4 完整巡检与备份脚本
下面是一个完整的单设备巡检与备份脚本,我尽量把注释写清楚:
from netmiko import ConnectHandler from datetime import datetime import os import re # 设备连接参数 device = { "device_type": "huawei", "ip": "192.168.1.10", "username": "admin", "password": "password123", "port": 22, "timeout": 60, "session_timeout": 60, } def save_to_file(directory, filename, content): """将内容写入文件,自动带时间戳""" if not os.path.exists(directory): os.makedirs(directory) filepath = os.path.join(directory, filename) with open(filepath, "w", encoding="utf-8") as f: f.write(content) return filepath def collect_device_info(connection): """收集设备状态信息""" info = {} commands = { "设备信息": "display version", "CPU使用率": "display cpu-usage", "内存使用率": "display memory-usage", "设备温度": "display temperature", "接口状态": "display interface brief", "VRRP状态": "display vrrp brief", "DHCP地址池": "display dhcp server ip-pool", } for description, command in commands.items(): try: output = connection.send_command(command) info[description] = output except Exception as e: info[description] = f"[错误] {str(e)}" return info def backup_config(connection): """备份设备配置""" output = connection.send_command("display current-configuration") return output def parse_cpu_usage(text): """解析CPU利用率""" match = re.search(r"CPU Usage\s*:\s*(\d+)%", text) if match: return match.group(1) return "N/A" def parse_memory_usage(text): """解析内存利用率""" match = re.search(r"Memory Usage\s*:\s*(\d+)%", text) if match: return match.group(1) return "N/A" def generate_report(device_name, info, config_content): """生成巡检报告""" now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") report_path = save_to_file( "reports", f"{device_name}_report_{now.split(' ')[0]}.txt", f"设备巡检报告 - {date.today()}\n设备名称: {device_name}\n巡检时间: {now}\n\n" ) # 解析关键状态 cpu = parse_cpu_usage(info.get("CPU使用率", "")) mem = parse_memory_usage(info.get("内存使用率", "")) # 写入报告内容 with open(report_path, "a", encoding="utf-8") as f: f.write(f"CPU利用率: {cpu}%\n内存利用率: {mem}%\n\n") f.write("=== 详细状态信息 ===\n") for desc, output in info.items(): f.write(f"\n--- {desc} ---\n{output}\n") return report_path def main(): now = datetime.now() date_str = now.strftime("%Y%m%d") try: connection = ConnectHandler(**device) device_name = connection.send_command("display current-configuration | include sysname").split()[-1] # 备份配置 config = backup_config(connection) config_path = save_to_file( "backups", f"{device_name}_config_{date_str}.txt", f"# 备份时间: {now.strftime('%Y-%m-%d %H:%M:%S')}\n{config}" ) print(f"[成功] 配置已备份到 {config_path}") # 巡检 info = collect_device_info(connection) report_path = generate_report(device_name, info, config) print(f"[成功] 巡检报告已生成: {report_path}") except Exception as e: print(f"[失败] {device['ip']} 连接或执行异常: {str(e)}") finally: try: connection.disconnect() except: pass if __name__ == "__main__": main()这个脚本能跑通基本流程,但还有一些细节可以优化,比如接口状态统计中 Down 口的数量、日志告警的关键字提取。下面我专门讲这些细节。
5. 关键细节增强
5.1 接口状态分析与 Down 口告警
display interface brief的输出里,接口状态分up和down两种。日常巡检最烦的就是某个接口悄悄 down 了,可能是对端设备关机、光模块故障,也可能是人为误操作。脚本里可以加一段统计逻辑:
def analyze_interfaces(output): down_interfaces = [] for line in output.splitlines(): parts = line.split() if len(parts) >= 4 and parts[0].startswith("GE") or parts[0].startswith("XGE"): if parts[2] == "down" or parts[3] == "down": down_interfaces.append(parts[0]) return down_interfaces拿到 down 口列表后,报告的开头就直接列出,这样打开报告第一眼就知道有没有异常。如果不想看一堆正常接口,可以只把 down 口写进报告,正常接口的统计数字写在旁边就行。
5.2 日志告警关键字提取
display logbuffer的输出非常长,动不动几万行。全部写进报告没意义,反而是关键告警容易淹没在里面。我一般在收集日志后,用正则筛选级别为ERROR、WARNING、ALERT的记录,再把匹配到的行写进报告的"告警摘要"部分。
def filter_alarm_logs(log_text): lines = log_text.splitlines() alarm_lines = [] for line in lines: # 华为日志常见级别关键词 if re.search(r"\b(ERROR|WARNING|ALERT)\b", line, re.IGNORECASE): alarm_lines.append(line) return alarm_lines然后报告里给出一个计数和最近 20 条告警内容,足够快速判断设备是否存在潜在风险。
5.3 CPU 使用率的历史比对
单次 CPU 使用率只能反映当前时刻的状态,如果设备在高峰期 CPU 跑到 90%,可能只是瞬时抖动,过一会儿就恢复了。为了更准确地判断,可以额外执行display cpu-usage history,把设备历史上的 CPU 使用率曲线数据抓下来。虽然这个主要是用来看趋势的,但只要能拿到峰值和当前值,就可以大致判断设备负载是突发型还是持续型。脚本里可以做个简单判断:
cpu_value = int(cpu_usage) if cpu_value > 80: alert = "警告: CPU使用率过高" elif cpu_value > 60: alert = "注意: CPU使用率偏高" else: alert = "正常"这种判断虽然简单,但配合历史数据,能发现很多早期隐患。
6. 批量设备管理
6.1 多设备循环处理
单设备脚本只是第一步,生产环境里你要管理的是几十台设备。改进方式是把设备清单放到一个列表里,遍历登录和执行。这里我直接把登录逻辑封装成一个类,方便代码复用:
import pandas as pd from netmiko import ConnectHandler import time class HuaweiDeviceManager: def __init__(self, excel_path): self.df = pd.read_excel(excel_path) self.results = [] def process_all_devices(self): for index, row in self.df.iterrows(): device = { "device_type": "huawei", "ip": row["管理IP"], "username": row["用户名"], "password": row["密码"], "port": int(row["端口"]) if "端口" in row else 22, "timeout": 60, "session_timeout": 60, } try: connection = ConnectHandler(**device) # 收集信息和备份配置 # ... connection.disconnect() self.results.append({ "设备IP": row["管理IP"], "设备名": row["设备名"], "状态": "成功" }) except Exception as e: self.results.append({ "设备IP": row["管理IP"], "设备名": row["设备名"], "状态": f"失败: {str(e)}" })注意 Excel 文件里的密码是明文存储,这个在个人脚本里可以接受,但如果你的设备密码有强合规要求,建议改为在程序运行时从环境变量或密码库读取。还有一个细节:如果设备登录失败一次,不要立即重试,避免在有账户锁定策略的设备上把账号锁掉。
6.2 串行与并行执行的选择
批量执行有两种模式:串行和并行。串行是一台接一台地处理,逻辑简单,不容易出错;并行是同时开多个 SSH 连接,处理速度快,但对设备的性能和管理通道的压力有要求。
我的建议是:设备数量少于 30 台,串行完全够用,平均一台 30 秒,30 台也就 15 分钟。如果你管的是上百台设备,可以用concurrent.futures.ThreadPoolExecutor做并行,线程数控制在 5 到 10,别贪多。下面是并行执行的关键代码:
from concurrent.futures import ThreadPoolExecutor, as_completed def process_one(device_row): # 单台设备处理逻辑 pass with ThreadPoolExecutor(max_workers=5) as executor: futures = [executor.submit(process_one, row) for _, row in self.df.iterrows()] for future in as_completed(futures): result = future.result() print(result)并行执行时需要注意:华为设备默认只允许有限数量的并发 SSH 会话(通常是 5 到 10 个),如果你开太多线程,后面的连接会被设备拒绝。所以线程数要根据设备能力来定,保守一点就 5 个以内。
6.3 失败重试机制
设备偶尔会抽风,SSH 握手超时、网络闪断、用户名密码输错,这在批量巡检时几乎必然发生。脚本里最好加上重试逻辑:
import time def connect_with_retry(device, retries=3, delay=5): for attempt in range(retries): try: connection = ConnectHandler(**device) return connection except Exception as e: if attempt < retries - 1: print(f"连接失败(第{attempt+1}次),{delay}秒后重试...") time.sleep(delay) else: raise e重试次数建议 2 到 3 次,间隔时间 5 秒以上。太重试会把设备的管理会话数占满,反而引发其他问题。
7. 常见问题与排查技巧实录
7.1 SSH 登录失败:Authentication failed
这个问题排在第一位,遇到概率太高了。常见原因有三个:
- 账号密码错误:明文核对一下,注意 Excel 里可能有多余空格,
strip()一下再传入。 - 设备上没开启 SSH 服务:用 PuTTY 手动连一次,如果能连但脚本连不上,大概率是 Netmiko 的
device_type参数不对。华为设备一般用huawei,如果是新版本 VRP 平台,可以试试huawei_vrpv8。 - 密码里有特殊字符:比如
@、#、$等,在 Excel 或 yaml 里会被转义或者被 Python 字符串处理出问题。建议先打印出来核对。
7.2 命令执行卡在 ---- More ----
这是华为设备最常见的老坑。display current-configuration输出过长,设备会自动分页,显示---- More ----等待用户按键。如果不处理,Netmiko 会一直等下去直到超时。
解决办法是登录连接后,先发送命令关闭分页。Netmiko 针对华为设备有自己的自动处理逻辑,但也会遇到漏网之鱼,稳妥的做法是手动发送关闭分页的命令:
connection.send_command("screen-length 0 temporary")这条命令只对当前登录会话生效,不会修改设备永久配置,非常安全。执行完以后,后续所有命令的回显都不会分页。
提示:不同华为设备型号对screen-length 0 temporary的支持情况略有差异。S5700 系列基本没问题,有些老款 S3700 上这条命令可能不存在,需要用undo terminal monitor之类的命令辅助,具体以设备提示为准。
7.3 命令回显内容乱码
部分华为设备 SSH 登录后的默认语言是中文或英文,取决于系统配置。如果你的终端编码和设备的编码不一致,输出到文件里会出现乱码。解决办法有两个方向:
- 在代码里用
encoding="utf-8"写入文件,同时保证设备的 SSH 会话编码是 UTF-8。 - 如果设备侧不支持改编码,可以在脚本开头统一把回显内容用
errors="ignore"的参数写入,至少能保证脚本不中断。
另外注意,华为的设备名如果包含中文字符,生成文件名时要做清洗,把非 ASCII 字符替换掉,否则某些系统上创建文件会失败。
7.4 Netmiko 超时设置不合理
Netmiko 有两个超时维度:timeout是全局阻塞超时,session_timeout是会话级超时。默认值对小型设备够用,但执行display memory-usage等命令时,如果设备繁忙,回显可能会超过默认的阻塞时间。我建议统一设置:
device = { ... "timeout": 60, "session_timeout": 60, "conn_timeout": 30, }conn_timeout只控制建立 TCP 连接阶段,如果网络不通它会很快报错,不用和timeout混在一起。
7.5 备份文件内容不完整
如果你发现备份出来的配置文件比设备上实际配置短,多半是命令执行时机太早,设备还没有把完整配置回显完。排查方法是手动执行一次display current-configuration,看最后一行是否以return结尾。如果备份文件末尾缺少return,说明回显被截断了,可以:
- 在脚本中增加一个配置结束判断,循环读取直到遇到
return。 - 或者把
send_command换成send_command_timing,手动控制读取节奏。
后一种方式看似灵活,实际容易踩坑,因为需要自己判断每次读取的数据长度,不稳定。我更推荐前一种做法——检查输出末尾的特征字符串。
7.6 脚本在 Windows 计划任务里跑不起来
Windows 计划任务执行 Python 脚本时,经常会遇到"路径不对"或"找不到 python"的问题。解决办法是在计划任务里把"起始于"目录设为脚本所在目录,并在命令里写全 Python 的绝对路径,例如:
C:\Python310\python.exe C:\scripts\network_inspect.py另外如果脚本里有相对路径(比如backups目录),一定要用绝对路径,因为计划任务启动时的工作目录不是你脚本所在的目录,很容易出现目录不存在的问题。
8. 自动化调度与报告格式优化
8.1 配置 Linux Crontab 定时任务
如果你的巡检机是 Linux 服务器(比如一台内网跳板机),可以用 crontab 实现每日自动巡检。
# 每天早上 08:30 执行巡检 30 8 * * * cd /home/admin/network_inspect && /usr/bin/python3 network_inspect.py >> /var/log/network_inspect.log 2>&1注意使用 Python 的绝对路径,避免 PATH 环境变量不同导致找不到 python。日志重定向一定要加,这样有问题时能回溯。
8.2 巡检报告转 Excel 格式
很多人更喜欢 Excel 报告,方便筛选、排序和做图表。pandas 可以轻松实现。下面是把多台设备的摘要信息汇总到一张表里的示例:
import pandas as pd summary_data = [] for result in results: summary_data.append({ "设备IP": result["ip"], "设备名": result["name"], "CPU利用率": result["cpu"], "内存利用率": result["mem"], "Down口数量": result["down_count"], "告警数量": result["alarm_count"], "巡检状态": result["status"], }) df = pd.DataFrame(summary_data) df.to_excel("巡检报告_20250115.xlsx", index=False)这样每次巡检结束,Excel 表格里就是每台设备的健康状态摘要,领导要数据也能直接发过去。
8.3 异常状态钉钉/邮件通知
巡检完了没人看等于白巡检。建议加一个告警通知:如果有设备 CPU 超过阈值、有 Down 口或者有 ERROR 级别日志,就通过邮件或钉钉机器人推消息。
邮件可以用 Python 内置的smtplib发送。钉钉机器人更简单,用requests库往 webhook 地址 POST 一条 JSON 消息就行。我在实际使用中会同时开邮件和钉钉,邮件留给领导查历史记录,钉钉即时推给运维群,有问题能第一时间发现。
9. 安全性与权限管理
9.1 账号权限最小化
巡检脚本在设备上使用什么账号,很重要。我建议创建一个专用的巡检账号,权限只读,不要直接给 admin 或超级管理员权限。在华为设备上创建一个只有查看权限的本地用户,可以这样配置:
system-view local-user inspect password irreversible-cipher yourpassword local-user inspect service-type ssh local-user inspect privilege level 1privilege level 1 的账号能执行大部分display命令,但不能修改配置。这样即使脚本或者账号泄露,也不会被别人远程改了设备配置。要说缺点,就是极少数 display 命令在 level 1 下会没有权限,比如display diagnostic-information这种诊断命令可能被拒,那种场景单独加白名单即可。
9.2 密码存储方案
脚本里明文存储密码,虽然方便,但确实存在安全隐患。如果你在公司内网环境、大家的信任边界明确,可以接受;但如果是共享的跳板机,我建议把密码放到环境变量或独立配置文件中,配置文件权限设成 600。
读取环境变量的方式:
import os password = os.getenv("SWITCH_PASS", "")在你的 shell 环境里设置好SWITCH_PASS,脚本运行时会自动读取。对我个人来说,如果设备数量少、运维团队就我一个人,直接用yaml文件存密码也够用,但记得把那个文件加入.gitignore。
9.3 敏感设备操作保护
自动巡检脚本不涉及配置变更,所以风险相对可控。但如果你想扩展成自动备份并上传配置、或者自动执行某些变更操作,一定要加确认机制:在执行变更命令前,让脚本使用send_command而不是send_command_timing,并且在代码里做二次确认,防止误操作。
10. 期望管理与后续扩展
10.1 这个脚本能做什么、不能做什么
不少朋友看我分享这类脚本,第一反应就是"能不能顺带做个配置下发",我的回答是:能,但请慎重。巡检脚本的核心价值是"收集"和"记录",不是"变更"。配置变更涉及的风险远高于巡检,写错一条命令可能导致整个业务中断。所以项目里我只做巡检和备份,不做自动下发,等你有足够信心再考虑把那部分能力加上。
10.2 从脚本到平台
当设备数量超过 100 台以后,单纯的脚本模式管理起来会有些吃力。那时候可以考虑把脚本演进成一个轻量的内部工具:加一个 Web 界面,把设备清单改成数据库存储,把巡检结果存成带索引的记录。但这个升级要一步步来,不要一开始就想做一个大平台,先把巡检脚本用熟、用好,积累出稳定可靠的执行逻辑,再谈上层。其实很多团队的自动化运维就是从这样一个几十行的小脚本起步的。
10.3 聊聊替代方案
除了 Python + Netmiko,还有几个现成的方案值得大家了解:
- Ansible:基于 Python 开发,华为设备有对应的 collection,用 playbook 写巡检和备份更规范,但学习成本也更高。
- Nornir:更适合做并行批量任务的 Python 框架。
- Paramiko 原生:如果你不想引入 Netmiko,直接基于 Paramiko 自己写,灵活度和可控性最高,但要自己处理很多交互细节。
对我个人来说,日常跑增量巡检和临时备份,Netmiko 最顺手。Ansible 适合正式一点、需要版本化管理 playbook 的场景,如果你已经在用 Ansible 管服务器,顺手把网络设备也管起来是不错的选择。
11. 踩坑心得与实战建议
11.1 先小范围试点,再全量推开
第一次跑全量巡检前,我强烈建议先选三台不同类型的设备做试点:一台核心交换机、一台接入交换机、一台汇聚设备。把试点设备跑通、输出内容人工核一遍,确认脚本的解析逻辑兼容后再扩展到全部设备。原因很简单,各型号华为设备的命令回显格式存在差异,你很难一次性把所有情况都覆盖到。
11.2 保留历史版本,形成对比
备份配置这件事,不要只存最新版本。我会在每次巡检备份后,额外把上一次的配置做一个 diff,把差异行输出到报告里。这样哪天设备配置被意外改动,能快速定位到是哪台设备、哪一行变了。实现 diff 可以用 Linux 自带的diff命令,或者 Python 里的difflib库。
import difflib with open("config_old.txt", "r") as f1, open("config_new.txt", "r") as f2: old_lines = f1.readlines() new_lines = f2.readlines() diff = difflib.unified_diff(old_lines, new_lines, lineterm="", n=0) for line in diff: print(line)实战中我发现,配置 diff 的价值甚至比巡检本身还大。很多棘手的网络故障,最后定位下来就是某台设备配置被谁改了一行,有了 diff 历史,这种问题就很好查了。
11.3 定期验证备份文件的可恢复性
备份文件躺在文件夹里,不等于关键时刻能恢复。我一般每季度抽一台设备做一次恢复演练:把备份里的配置恢复到设备上,确认业务正常。这样做一方面验证了备份文件的完整性,另一方面也验证了整个备份流程没有静默失败。如果哪次发现备份文件不完整,多半是回显截断问题,那就回到上面的第 7.5 节去排查。
11.4 脚本的可维护性
代码写清楚注释和模块化,不只是给别人看的,更是给三个月后的自己看的。我有一次临时急着改脚本,跳过了封装函数,全写在一个大 for 循环里,结果一个月后自己都看晕了。后来老老实实把设备列表、连接、采集、解析、报告生成拆成不同模块,维护成本直线下降。
11.5 结合业务视角做巡检
最后提醒一点:巡检不只是看设备健康指标,更要结合业务视角。比如某台交换机是专门承载办公网络的,那在巡检报告里除了看 CPU、内存、接口状态,最好还要关注网络是否出现过广播风暴、有没有 CPU 占用率突增的时段。你的巡检脚本是手段,最终目的是让网络稳定运行、问题提前暴露。
12. 写在项目之后
整个项目跑下来,我最深刻的体会是:用 Python 做华为交换机的巡检和配置备份,本质上就是用自动化替代手工重复劳动,把运维人员从"登录设备、敲命令、复制粘贴"这种低价值工作里解放出来。脚本写起来不算复杂,但一次投入、长期受益,每天省下的半小时一小时,累积下来是相当可观的时间成本。
如果你也是运维或者网络管理人员,我建议你先从一两条命令做起,不要一上来就写一个完整的批量巡检系统。先把display version用脚本跑通,再逐步加命令、加设备,最后做成一个每天自动跑的完整流程。踩过的坑我都写在前面了,希望你能绕开它们,把你的第一套网络巡检自动化项目顺利落地。