资讯动态

用Python和Netmiko实现华为交换机自动化巡检与邮件报告

发布时间:2026/10/15 17:44:58 来源:尧图企业网站定制
如果每天早上到工位的第一件事是登录一大堆网络设备一台一台敲命令、记输出、比对昨天的数据我想很多运维同行都会有这样的念头——这活儿能不能让程序替我干我手上一度要维护二十多台华为交换机原先的巡检全靠人肉。SSH登录、逐条执行display命令、看CPU、看内存、看接口状态再手工记录成表格。设备少的时候还能忍设备一多光是全部登录一遍就得大半个小时更别提整理日报和对比历史数据了。后来我花了一个下午写了一套基于Python3的巡检脚本把流程完全自动化自动登录所有交换机按固定命令清单执行巡检收集回显最后整理成一份带概要表格的邮件发到自己的邮箱。现在每天早上打开邮箱当天所有设备的状态一目了然有异常再上设备确认。这篇文章把这套方案的完整过程讲一遍——从需求分析、库选型、编码实现到实际跑起来遇到的坑适合有Python基础、正在被重复性设备巡检消耗时间的运维朋友参考。1. 被巡检逼疯之后我这套自动化的原始需求1.1 手动巡检的三大痛点先说手动巡检具体烦在哪里。第一个痛点是纯时间消耗。二十多台设备每台都要登录执行五六条命令等回显复制保存。熟手一台也得两三分钟一趟下来四五十分钟就没了。关键是这活儿没有任何技术含量就是重复、重复、再重复。中间接个电话、回个消息整个节奏就乱了很容易漏掉命令。第二个痛点是记录方式五花八门。今天用文本文件记明天改Excel过两天觉得截图更直观。最后日报里三种形式混在一起月底做汇总的时候谁都看不明白。数据口径不统一就没法做趋势对比。设备是哪一天开始CPU偏高的、光功率是缓慢下降还是突然异常全靠模糊记忆。第三个痛点是漏检。手工巡检最大的问题不是慢而是不稳定。心跳、CPU、内存这些常规项一般不会漏但光模块收发光功率、接口错包数、单板温度这些需要逐条细看的指标在高强度工作节奏下很容易被带过。等设备真出问题再回头看日志才发现之前已经有过先兆。1.2 一个脚本想解决哪些事动手写脚本之前我给自己定了三个目标后面所有设计都围绕这三个目标展开。第一巡检过程全自动。所有设备的登录、命令执行、结果收集全部由程序完成不需要人工干预。第二结果可对比、可追溯。每台设备的原始巡检输出都按固定格式落盘文件名带设备名和日期随时能和昨天、上周的同类数据对比。第三报告主动推送。巡检完成后自动生成汇总报表通过邮件发送到指定邮箱。我早上到公司先看邮件发现问题再上设备确认而不是一台台主动登录去看。简单说自动化只是手段真正有价值的是把设备数据统一收集起来、每天稳定推送让巡检这件事变得可以依赖。2. 连接华为交换机为什么我选Netmiko而不是直接调Paramiko2.1 两个库的差别Python连网络设备绕不开两个库Paramiko和Netmiko。Paramiko是底层SSH协议库相当于一台手动挡的车——动力完整但离合、换挡全要自己控制。你需要自己处理TCP连接、SSH认证、命令交互、回显读取、提示符匹配任何一个环节处理得不仔细就会出现命令发送了但读取不完整、或者读到上一轮残留输出的情况。Netmiko是在Paramiko之上封装的网络设备操作库相当于自动挡的车。它把设备登录、命令行交互、分页处理、enable模式切换这些繁琐细节封装好了你要做的只是告诉它这是华为设备、用户名密码是什么、执行什么命令。两者对比如下对比项ParamikoNetmiko封装层次底层SSH协议面向网络设备的操作封装设备类型适配不区分厂商内置huawei、cisco_ios等几十种device_type命令交互需自行处理prompt和回显自动等待命令执行完成分页处理需自行发送命令禁用分页有内置逻辑但仍建议主动处理学习成本高细节多低上手快灵活性高一切可控中极端场景需调参适配对巡检这种固定流程来说Netmiko完全够用而且省掉大量交互细节的踩坑时间。如果你只想快速把设备巡检跑起来Netmiko是更务实的选择。只有当你需要实现特别复杂的交互逻辑、绕开封装层做底层操作时才值得去碰Paramiko。2.2 华为设备的登录方式与Netmiko的device_type华为交换机的SSH登录在设备开启SSH服务后用设备上配置的账号密码进行认证即可登录后默认进入用户视图。Netmiko里对应的device_type是huawei它会按照华为设备的交互习惯来处理提示符等待、命令发送节奏。这里有一个特别容易踩的点华为设备默认开启命令分页。登录后如果直接执行一条很长的display命令输出会被截断成一个个page停在---- More ----等待用户按回车。Netmiko虽然有分页处理逻辑但最稳妥的做法是在连接建立之后、正式执行巡检命令之前先发送一条screen-length 0 temporary关闭分页。这条命令只在当前SSH会话内生效不会修改设备全局配置安全且不留痕迹。我见过有的同事直接把screen-length 0 permanent写进设备配置省事是省事但改变了设备默认行为遇到个别不允许改动配置的环境就麻烦了。我的建议始终是用temporary后缀的方式脚本会话内控制不影响设备本身。3. 核心实现登录、执行巡检命令、收集回显3.1 设备清单和巡检命令怎么设计先把设备清单定义好。最简单的方式是在脚本里维护一个列表。设备少的时候够用后面多了可以改成从文件或数据库读取。# devices.py DEVICES [ { name: core-sw-01, ip: 192.0.2.11, username: audit_user, password: your_password, }, { name: access-sw-01, ip: 192.0.2.21, username: audit_user, password: your_password, }, ]关于账号权限我建议不要直接用设备的管理员账号跑巡检。我在实际环境里单独建了一个审计账号只授予display类的只读权限。即使脚本文件泄露也不会把设备完全暴露出去。这也是我吃过一次亏之后养成的好习惯——脚本里存的密码越少越好权限越小越好。巡检命令要覆盖交换机的关键健康指标。我整理了下面这份清单日常巡检基本够用命令巡检目的display device硬件状态是否有板卡掉线或告警display cpu-usageCPU占用率及近期负载display memory-usage内存使用率display temperature all各单板温度display interface brief所有接口状态找出Down口display transceiver interface 接口名光模块收发光功率逐口查询display version系统版本和运行时长光模块的查询不能一次性霍霍执行太多命令。我通常先执行display interface brief从输出里解析出处于Up状态的光口列表再循环执行display transceiver interface来查询收发光功率。这样既不会漏查也不会把命令数量搞得太多。3.2 登录与执行主循环核心登录和执行逻辑用Netmiko写出来比较简洁from netmiko import ConnectHandler def collect_device_raw_output(device): net_connect ConnectHandler( device_typehuawei, hostdevice[ip], usernamedevice[username], passworddevice[password], port22, global_delay_factor2, ) # 当前会话临时关闭分页避免长命令输出被截断 net_connect.send_command(screen-length 0 temporary) commands [ display device, display cpu-usage, display memory-usage, display temperature all, display interface brief, ] output_lines [] for cmd in commands: output net_connect.send_command(cmd, read_timeout60) output_lines.append(f########## {cmd} ##########) output_lines.append(output) # 解析Up状态的光口并逐个查询收发光功率 brief_text output_lines[-1] up_ports get_up_optical_interfaces(brief_text) for port in up_ports: output_lines.append(f########## display transceiver interface {port} ##########) output_lines.append(net_connect.send_command(fdisplay transceiver interface {port}, read_timeout30)) net_connect.disconnect() return \n.join(output_lines)代码里有两个参数值得专门说一下。第一个是global_delay_factor2。它表示命令发送间隔的倍率。华为旧款交换机和配置量大的设备在CPU占用高的时候命令回显会明显变慢用默认参数容易出现命令还没执行完就读取超时的情况。我统一设置成2之后整体稳定性明显提升。遇到性能特别差的设备可以单独调成3或4代价是单台设备的巡检耗时变长但对日报场景来说这点时间可以接受。第二个是read_timeout60。这是针对display interface这类输出量特别大的命令设置的。接口数量多的汇聚交换机一次display interface brief可能回显上千行默认等待时间经常不够。设置了这个参数后基本没再出现过回显读不全的情况。3.3 光口解析、回显清洗与落盘光口列表的解析逻辑可以单独写一个函数。display interface brief的输出每行格式大致是接口名 状态 协议...我们只要把光口且状态为up的挑出来def get_up_optical_interfaces(brief_output): up_ports [] for line in brief_output.splitlines(): parts line.split() if len(parts) 2 and parts[1] up: if any(parts[0].startswith(p) for p in (GE, XGE, 40GE, 100GE)): up_ports.append(parts[0]) return up_ports这个函数的写法比较保守。实际环境中接口命名格式可能不同比如华为有GigabitEthernet、XGigabitEthernet这样带全称的显示方式只要把你的前缀列表换成完整关键字即可。解析完之后返回的端口列表直接丢进主循环里逐个查询。命令执行完原始输出要清洗一下再保存。华为设备的回显里经常夹杂大量空行不处理的话邮件正文和日志文件会非常乱。我通常做三步按行拆分、去掉首尾空行、合并连续空行。如果输出里出现乱码字符还要单独处理编码问题这个放到后面的踩坑章节细讲。清洗后的结果按设备落盘文件名规范是设备名_日期.txt。比如core-sw-01_20250115.txt。原始文件保留下来的好处是邮件里如果漏掉了细节随时能回服务器翻原始记录不依赖邮件留存。def save_raw_output(name, content, date_str): filename f{name}_{date_str}.txt with open(filename, w, encodingutf-8) as f: f.write(content) return filename4. 邮件模块把一堆txt变成一封能看的巡检报表4.1 用SMTP发送邮件的基础配置邮件发送我用的是Python标准库smtplib和email不需要额外安装第三方包。关键配置有三块SMTP服务器地址、发件账号、授权码。这里特别提醒一句不要用邮箱登录密码去发邮件。现在的邮箱服务商基本都支持开通SMTP服务后生成专用授权码。授权码独立于登录密码可随时撤销。就算脚本文件被别人看到了也不至于整个邮箱账号暴露。这个坑很常见一定要重视。配置示例SMTP_SERVER smtp.example.com SMTP_PORT 465 # 或者587取决于服务商 SMTP_USER senderexample.com SMTP_AUTH_CODE 你的授权码 MAIL_TO receiverexample.com端口配置要注意465通常配合SSL加密587一般使用STARTTLS。具体用哪个端口、是否需要加密遵从邮箱服务商的文档为准。我之前固定写465后来换了一个服务商总是发不出去排查了一圈才发现是端口策略不同。4.2 正文用HTML表格展示设备概要如果直接把所有设备的原始输出贴在邮件正文里几十台设备会让邮件长到没人愿意看。所以我做了两级信息呈现邮件正文只放概要表格完整输出放附件。概要表格的生成逻辑是从每台设备的原始输出里提取关键指标——CPU使用率、内存使用率、最高温度、接口Down数量、设备告警状态。提取方法以CPU为例import re def extract_cpu_usage(raw): match re.search(rCPU\sutilization\sis\s(\d)%, raw) if match: return int(match.group(1)) return None不同型号的设备回显格式略有差异正则需要按你的实际环境微调。第一次跑的时候建议把原始输出打印出来对照着写解析规则。收集完所有设备数据后用HTML拼接表格异常的行标红显示def build_html_rows(summary_list): rows for item in summary_list: status 正常 color if item[cpu] is not None and item[cpu] 70: status CPU偏高 color background-color: #ffe0e0; if item[temp] is not None and item[temp] 45: status 温度偏高 color background-color: #ffe0e0; rows ftr style{color}td{item[name]}/tdtd{item[ip]}/td rows ftd{item[cpu]}%/tdtd{item[mem]}%/td rows ftd{item[temp]}°C/tdtd{item[down_intf]}/td rows ftd{status}/td/tr return rows为什么要用HTML而不是纯文本因为巡检结果里最需要一眼看出来的是哪台设备有问题。纯文本邮件很难做视觉区分HTML表格加上标红打开邮件三秒就知道今天需不需要处理异常。阈值只是示例——我自己的环境里把CPU 70%、温度45度作为重点关注线你要根据机房制冷条件和设备硬件规格自定义不能照搬。4.3 附件打包和邮件发送完整原始输出我建议压缩成zip作为附件否则几十个txt文件堆在邮件里列表拖得很长附件数量也会触发部分邮箱的拦截策略。Python标准库zipfile可以直接处理import zipfile def create_attachment(file_list, zip_name): with zipfile.ZipFile(zip_name, w, zipfile.ZIP_DEFLATED) as zf: for f in file_list: zf.write(f) return zip_name邮件发送整体拼起来就是组装MIMEMultipart对象把HTML正文add进去再添加zip附件最后通过smtplib发送。主题带上日期方便后续检索subject f交换机巡检报告 {date_str}发送完毕后在日志里打印每台设备的执行状态——哪台成功、哪台登录失败、哪台命令超时。这些信息本身也是一份很好的巡检审计记录。5. 实测中绕不开的坑从分页到垃圾邮件5.1 分页问题没有彻底消失我最初以为一条screen-length 0 temporary就一劳永逸了实际跑了一周发现还有漏网之鱼。华为设备的某些命令比如display interface当接口数量特别多时即使关闭分页输出也可能超过设备单次返回缓冲上限出现输出被截断但不报任何错误的情况。这个问题非常隐蔽因为命令本身执行成功了只是回显被悄悄截断。我的处理办法是两条腿走路。第一尽量在脚本里拆分查询范围接口多就分批查不让单条命令的输出量越过设备的安全线。第二在解析结果时增加完整性校验——比如检查输出末尾是否出现预期的结束标志如果没有就标记为可能不完整在邮件里提示人工复核。宁可在报告里多一个标注也不要把不完整的数据当成完整数据用。5.2 编码问题为什么有的设备输出乱码华为不同产品线、不同软件版本的回显编码并不完全一致。我遇到过S系列老版本输出是GBK新版本和部分CE系列又变成UTF-8的情况。Netmiko在读取回显时默认按UTF-8解码遇到GBK内容就会出现中文乱码最常见的就是设备描述、接口备注的注释乱成一团。排查方法并不复杂。先用net_connect.read_channel()手动读取一小段原始输出用十六进制打印出来看看中文区域对应的编码规则判断是GBK还是UTF-8。然后在ConnectHandler里通过encoding参数明确指定net_connect ConnectHandler( ..., encodingutf-8, )如果设备端确实输出GBK就改成encodinggbk。还有一种思路是在设备上把回显编码统一配置为UTF-8但这属于改动设备全局配置我一般不这么干优先在脚本侧适配。由于我维护的设备新旧型号混杂最终脚本里按设备名做了两个连接配置集合新老设备各用各的编码问题彻底解决。5.3 部分老设备交互慢导致超时有一台用了很多年的接入交换机内存占用长期在80%以上。用默认参数跑的时候偶尔会出现命令发送成功但回显读取不完整的情况。排查网络没有丢包登录也正常最后加日志才发现是设备端响应太慢命令执行完了但回显分片到达的间隔超过了Netmiko的读取等待时间。解决方式就是前面提到的global_delay_factor调大、read_timeout加长。我最后把这台老设备的连接参数单独拆成一个字典单独维护用更高的倍率处理其他设备保持默认参数。写自动化脚本不用忌讳每台设备配置不一样能照顾到网络里最差的那台设备方案才是真的稳定。5.4 邮件发出去被当成垃圾邮件这是个很现实的问题。每天固定时间自动发送、附件还是zip的邮件很容易命中收件方邮件系统的垃圾邮件过滤策略。我踩过之后做了几个调整。第一发件邮箱域名配置SPF记录否则被公共邮件服务商拦截的概率很高——这个去邮箱服务商的控制台里设一下就可以。第二邮件标题不要使用纯数字或者重复结构我固定成交换机巡检报告-日期这样清晰可读的格式。第三附件压缩后的文件名保持可读规范不要用随机字符。如果你是完全自己发给自己做好这三步基本不会再被拦。如果你的公司有内部邮箱系统最稳妥的办法是直接用内部邮箱作为SMTP发件方内外隔离不需要和公网邮箱的过滤策略较劲。6. 定时执行和后续可以扩展的方向6.1 用Linux定时任务跑起来脚本写完后的最后一步是让它每天自动跑。我用的是Linux的cron定时任务。假设脚本路径是/opt/network_inspect/main.py想在工作日每天早上8点30分执行在crontab文件里这样写30 8 * * 1-5 cd /opt/network_inspect /usr/bin/python3 main.py logs/run_$(date \%Y\%m\%d).log 21这里有个细节容易踩坑cron特殊处理%符号日期格式里的%必须写成%否则cron会把它当成换行符导致命令解析失败执行日志里全是bad command。我第一次配置时没注意这个排查了很久才发现是转义问题。另外脚本本身一定要做好单台设备异常的隔离。我在主循环里给每台设备的处理都加了try-except单台登录失败不会中断整个巡检流程最后邮件里汇总成功N台失败M台失败原因见附件。这样即使有一台设备临时抽风其他设备的报告依然准时到达。6.2 继续完善的方向这套脚本跑稳定之后我陆续加了一些周边能力按你的实际需求取舍就好。第一设备清单外部化。把设备信息从Python字典挪到YAML或数据库里加设备、改密码不用改代码。我后来直接把设备清单做成一个简单的文本表维护起来方便很多。第二告警阈值配置化。CPU、内存、温度等指标的预警值集中放到配置文件里不同设备可以设不同的阈值。第三结果入库。每天巡检结果写入数据库到月底拉出来看趋势就方便了。第四对接即时通信告警。邮件适合做每日日报异常告警可以额外推到消息群里让对应负责人第一时间看到。不过说实话这些扩展都不复杂。核心的巡检和推送链路稳定之后剩下的都是逻辑上怎么消费这些数据的问题。自动化巡检真正值钱的地方不在代码本身而在你终于能把日常重复工作交给程序让自己去做更有价值的事情。最后说一点个人体会。这套脚本从写下第一行到稳定运行前后大概用了不到一周。后续半年多基本没怎么动过它。表面上看起来是每天省了四五十分钟但真正让我觉得值得的是巡检这件事从此变得可以依赖——程序不会因为走神漏掉一台设备不会因为忙起来跳过一条命令。只要设备清单是准确的每天的数据一定是齐的。如果你也在被重复的设备巡检消耗时间我建议你也花点时间把这件事自动化。第一版不用追求完美先做到能跑通、能发信再逐步打磨细节即可。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑