# ROMAN 定制中心 — 可移植 Zabbix 前端模块 一个自包含、多语言的 Zabbix 7.4 前端模块(custom module / plugin)。加载后会在 **Administration → ROMAN 定制中心** 增加一个定制页面,分四个 Tab: - **告警(Alert)** - **机器人 key**:单字段读写全局宏 `{$WECOM_KEY}`,无“账号/接收目标”概念(群机器人就是往群里发一条消息);可“发送测试”直接打企微接口看 `errcode`。 - **告警策略引擎**:内置 5 套策略预设(稳健运维 / 只保命 / 全量观察 / 夜间降噪 / 核心从严)。**先“预览”(dry-run,不写入)→ 再“应用”**。应用会:① 设置媒介严重度阈值;② 把模板触发器、触发器原型、已发现(LLD)触发器按类别批量改严重度。必告警类别一律钉到 **灾难(Disaster=5)**,因此无论阈值多高都必然发出。 - **手动阈值**:勾选会通知的严重度 + 总开关(写媒介 `severity` / `active`)。 - **优化(Optimization)** - **服务端调优生成器**:选“小/中/大”规模,生成 `StartSNMPPollers` 等 `.env`/compose 参数与重建命令——**只生成、不落地**,由运维复制到主机自行重建 server 容器(零风险、零特权)。 - **模板导入**:内置的是**真实的华为模板** `Huawei VRP by SNMP walk`(导出文件在 `templates/`),点“导入”即导入 Zabbix;导入已存在模板会就地更新,导入新模板会新建。 - **模板切换(迁移设备)**:选“旧模板 → 新模板”,**预览**列出受影响设备 → **确认切换**把每台设备的模板链接替换为新模板(这就是“导入后是否切换”那一步)。 - **地图标记**:以 **单点(Zabbix server 主机)** 作为代表点,设置 `location_lat` / `location_lon`。 - **环境初始化 / 自检**:见下文“全新 Zabbix 两步装好”——一键补媒体类型、机器人用户、动作与 `{$WECOM_KEY}` 宏。 - **L2 拓扑(Topology)** - **只读展示**:STP 指定桥 + MAC 学习生成交换机级联关系,绝不使用 `ifAlias` 猜链路;不写交换机、不创建用户。 - **层级与历史**:`防火墙 → 行为管理 → 总核心 → 分核心`;7 天 gzip 历史快照,右上单面板按实际日期/时间回看。 - **展示与导出**:告警/离线/延迟/链路速率配色、终端端口矩阵;PNG 导出固定日间模式并把图例烘焙进图片。 - **日常维护(Maintenance)** - **按类别批量改告警等级**:选一个“触发器类别”(如 设备离线 / 硬件故障 / 性能 …)+ 目标严重度,点 **应用**,即把该类别下**模板触发器、触发器原型、已发现(LLD)触发器**一次性改到该等级(复用策略引擎同一套写入逻辑,完全可逆)。适合“把某一类警报统一拉高/压低”。 - **按单个触发器精确调整**:按名称搜索触发器(最多显示 200 条),对每行可 ①勾选/取消 = 启用/停用告警(写 `trigger.status`,0 启用 / 1 停用);②行尾下拉直接选该触发器的严重度(0–5)。改完点 **保存**,**页面自动刷新**、即时可见(server 配置缓存约 60 秒内同步到告警逻辑)。 - 单套环境常有数万个触发器,需先输入关键字搜索(最多显示 200 条)。所有调整仅改 `triggers.priority` / `status`,不删除任何对象。 所有改动都通过 **Zabbix 官方 API / 受控 SQL** 写入数据库,因此:换机器、重建容器、升级镜像后设置都在;只要“加载插件”即可复用。 ## 全新 Zabbix:两步装好 **第一步 —— 装插件本体**(把文件搬进去): ```bash # 在解压出来的 web-modules 目录里执行: ./install.sh # 自动找到运行中的 zabbix-* web 容器并复制进去 # 或指定普通(非 docker)前端模块目录: ./install.sh /usr/share/zabbix/modules ``` `install.sh` 会在 MySQL 容器可访问时顺手建 L2 表,并在 Zabbix `module` 表已就绪时自动登记/启用 `wecom_center`;若提示表未就绪,再到 **Administration → Modules → Scan directory → 启用 `WecomCenter`**(或执行 README 末尾的 SQL)。 **第二步 —— 点“初始化”**:打开 **ROMAN 定制中心** 页面,首次进入会自动显示 **First-time setup**: 粘贴群机器人 Key → 点 **Initialise / self-check**。它会自动补齐整条链路(缺啥建啥,已存在则复用、可反复点当自检): | 对象 | 说明 | |------|------| | `{$WECOM_KEY}` 全局宏 | 存群机器人 webhook key | | 媒体类型 `WeCom Group Robot` | type=4 webhook,内置发送脚本(markdown,失败回退 text) | | 机器人用户 `wecomrobot` | 挂上面这个媒体类型,severity = High+Disaster | | 触发器动作 `Send alarm by Wecom Robot` | 告警/恢复各发一条 markdown 到群里(含 `{$ZBX_URL}` 详情链接) | 同一次初始化也会幂等创建 L2 拓扑的 `l2_topology_history` / `l2_topology_config`,配置行缺失时写默认配置(不覆盖已有配置)。如果只想初始化拓扑,到 **ROMAN 定制中心 → L2 拓扑 → 初始化 / 自检 L2 存储** 单独点一次即可;它不会创建用户或改动告警对象。采集器 cron 仍需在宿主机安装(见使用说明 10.4)。 装完之后日常调参都在页面上点,不用再碰命令行。 ## 目录结构 ``` WecomCenter/ ├── manifest.json # 模块清单(v2.0.1),注册 2 个 action ├── Module.php # 模块入口:注册视图目录、初始化 i18n、注入左侧菜单 ├── actions/ │ ├── WecomCenterView.php # GET 控制器,渲染页面 │ └── WecomCenterSave.php # POST 控制器,分发一键方案/保存/测试/导入/地图 ├── views/ │ └── wecom.center.view.php # 页面模板(Zabbix 原生 UI 组件) ├── lib/ │ ├── I18n.php # 极简多语言层(按当前语言加载,缺省回退英文) │ └── Helper.php # 业务逻辑:媒介/账号/key、方案预设、导入、坐标、测试 ├── locale/ # 35 个语言文件(见“多语言”) ├── templates/Huawei VRP by SNMP walk.yaml # 内置真实华为模板(导入/切换用) ├── assets/wecom.center.css └── install.sh # 一步搬运脚本(docker 自动探测 / 指定目录) ``` ## 安装(可移植方式) > **有现成 docker-compose(推荐)**:仓库根目录的 `docker-compose.yaml` 已把插件目录做成 > `${WEB_MODULES_DIR:-./web-modules}:/usr/share/zabbix/modules}`,并新增一次性服务 > `wecom-module-init` 会在 MySQL 就绪后**自动把 `wecom_center` 模块登记为已启用**(幂等)。 > 所以 `git clone` 后直接 `docker compose up -d`,起来就有插件,**无需手动启用**。 1. **持久化模块目录**:web 服务下挂载宿主目录(compose 已内置,默认用仓库同级 `./web-modules`): ```yaml zabbix-web-nginx-mysql: volumes: - ${WEB_MODULES_DIR:-./web-modules}:/usr/share/zabbix/modules ``` > 已有环境若模块目录在别处,设环境变量 `WEB_MODULES_DIR=/opt/zabbix/zabbix-server/web-modules` 覆盖即可。 2. 把本 `WecomCenter/` 目录整体放到该挂载目录下(仓库里 `web-modules/WecomCenter/` 即是),然后 `docker compose up -d` 重建 web 容器使挂载生效(数据不动,仅 web 短暂重启)。 3. **启用模块**(写入 `module` 表,status=1 为启用): - 用仓库 compose 时:`wecom-module-init` 服务**已自动完成**; - 手动方式(非 compose / 想手动): ```sql SET @nid := (SELECT COALESCE(MAX(moduleid),0)+1 FROM module); INSERT INTO module(moduleid,id,relative_path,status,config) SELECT @nid,'wecom_center','modules/WecomCenter',1,'[]' WHERE NOT EXISTS (SELECT 1 FROM module WHERE id='wecom_center'); ``` (也可在 Administration → General → Modules 里点“启用”。) 4. 刷新网页,左侧 **Administration → ROMAN 定制中心** 即可进入。 > 换环境:重复 1–3 即可。模块代码放在 git 里,`web-modules/` 随仓库走;MySQL 卷里保存着 `module` 启用记录,二者都在 → 插件始终在线。 ## 多语言 - 共 **35 个语言文件**,覆盖 Zabbix 全部 36 个 locale(`en_GB`/`en_US` 共用英文)。 - **已人工翻译**:`zh_CN`、`zh_TW`、`ja_JP`、`ko_KR`、`ru_RU`、`de_DE`、`fr_FR`、`es_ES`、`pt_BR`、`it_IT`、`pl_PL`、`tr_TR`。 - 其余语言文件存在但暂未翻译,运行时自动回退英文(页面照常工作,不会报错)。 - 增加/完善语言:复制 `locale/en.php` 为 `locale/.php` 并翻译 value 即可,键名保持不变。模块会读取当前用户语言(`CWebUser::$data['lang']`)自动切换。 ## 设计要点(适配 Zabbix 7.4) - `manifest.json` 用 `manifest_version: 2.0`;action 的控制器类位于 `actions/`(自动加载器会把子命名空间段转小写)。 - 视图目录必须在 `Module::init()` 里 `CView::registerDirectory($this->getRelativePath().'/views')`。 - 菜单注入:`APP::Component()->get('menu.main')->findOrAdd(_('Administration'))->getSubmenu()->add(...)`。 - 关键 API 注意:`mediatype.get` **不支持 `sortfield=name`**(会整体返回 false);`configuration.import` 的规则键是复数 `templates`(不是 `template`);`trigger.update` **不接受 `triggers` 数组**,只能逐条用 `triggerid` 更新。 - 告警“开关”落在用户媒介的 `active` 字段:**0=启用、1=停用**;严重度为位掩码(未分类=1…灾难=32)。触发器“是否告警”落在 `trigger.status`:**0=启用、1=停用**。 ## 告警媒介说明(key 已迁到全局宏) 页面基于“Webhook 类型(type=4)的媒介 + 一个机器人账号(默认用户名 `wecomrobot`)的媒介记录”工作。 - **机器人 key 存于全局宏 `{$WECOM_KEY}`**(Administration → Macros),页面“机器人 key”字段直接**读取/写入该宏**——key 不再散落在一长串 `webhook_url` 里。换机器人只改这一格。 - 媒介 102 的固定参数:`key = {$WECOM_KEY}`、`message = {ALERT.MESSAGE}`。 - Webhook 脚本按 `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key= + params.key` 拼 URL,用 **markdown** 发送(失败自动回退 text)。 - 一键方案 / 勾选保存 → 修改该账号对应媒介的 `severity` / `active`。 - 发送测试 → 用 base + `{$WECOM_KEY}` 拼 URL 直接 POST,检查返回 `errcode:0`。 ## 配套告警链路(告警方案 v2,已按预期配置) - **动作 7「Send alarm by Wecom Robot」**:问题消息改为 markdown 红字(``),并**新增恢复操作**发绿字(``),两者均带前端直达链接 `{$ZBX_URL}/tr_events.php?triggerid={TRIGGER.ID}&eventid={EVENT.ID}`。 - **全局宏**:`{$WECOM_KEY}`(机器人 key)、`{$ZBX_URL}`(前端地址,默认 `http://192.168.87.20:8080`)。 - **收件人**:统一为机器人账号 `wecomrobot`(uid 6)的媒介 102,不再指向真人账号。 - **备份与回滚**:改动前已导出 `/opt/zabbix/backup/wecom-config-backup-*.json`(含媒介 102、动作 7、全局宏),可用对应 API 还原。 若环境中没有 Webhook 媒介类型,页面会提示“未找到 webhook 媒介类型”。 ## 告警策略引擎(核心) **设计原则**:每条策略里,“必告警”类别一律设为最高严重度 **灾难 Disaster(5)**——因为“无论如何,最严重的总得告警”,这样无论阈值怎么卡都必然通过。策略同时给其余类别定阈值。**没有默认策略**:页面上列出预设,用户“选择 → 预览 → 应用”,应用可重复执行。 | 预设 | 阈值(最低会通知的级别) | 适用 | |---|---|---| | 稳健运维 steady | 严重(High) 及以上 | 日常生产 | | 只保命 core | 仅灾难(Disaster) | 最大降噪 | | 全量观察 observe | 警告(Warning) 及以上 | 新接入/排障 | | 夜间降噪 night | 仅灾难 | 夜班静默 | | 核心从严 balanced | 一般严重(Average) 及以上 | 比稳健略宽 | **类别与“必告警”**(按优先级顺序判定,一个触发器只归一类,高优先覆盖低优先): `device_down(设备离线) > hw_fault(硬件故障) > restarted(重启) > core_link(核心/上联) > interface_down(接口down) > perf(性能) > other(不动)`。 `device_down / hw_fault / restarted / core_link` 属于必告警,钉到 Disaster。 **一次“应用”实际改哪些对象**(三管齐下,缺一不可): 1. **模板触发器**(普通触发器):`API trigger.update`,立即生效并自动下发到已链接主机。 2. **触发器原型**:`API triggerprototype.update`,保证以后重新发现的新触发器也一致。 3. **已发现触发器(flags=4,LLD 生成,无 templateid)**:`trigger.update` 会报 `Cannot update "priority" for a discovered trigger`,故用**受控 SQL** `UPDATE triggers SET priority` 按类别批量改;分“低优先级类别先写、高优先级后写”,确保重叠时高优先胜出。前端读库即时可见,server 配置缓存约 60 秒内自动刷新。 **实测结论(2026-11-04,单套 186 台华为交换机 / 全库 45,824 触发器)**: - 走页面后端真实点“应用 steady”:模板触发器 4 个、原型 5 个、已发现触发器 11,047 个全部改成功;抽检 `73801 Unavailable by ICMP ping` 4→5、`73807 Fan critical` 原型 3→5 ✅。 - 应用后已做**全量还原**:全部 45,824 行 `priority` 与快照比对 **0 误差**,媒介严重度/策略宏一并复位。证明“一键刷新”在所有探测节点上可运行且**完全可逆**。 - “预览(dry-run)”按类别列出触发数/将改动数,不写入。已在页面验证渲染正常、无 PHP 报错。 ## 模板切换(旧→新迁移) 区别于“导入”,切换是把**已在用的设备**从一个模板迁到另一个模板: 1. 在“优化 → 模板切换”里选 `从模板(旧)` 与 `到模板(新)`(下拉只列 `Huawei` 相关模板)。 2. 点**预览**:调用 `host.get(templateids=旧)` 列出受影响设备(最多显示 300 个名字)与实际台数,不写入。 3. 点**确认切换**:对每台设备 `host.update`,把 `templates` 集合中的旧模板替换为新模板(保留其它模板链接、去重)。LLD 会按新模板重新采集。 4. 页面顶部弹出结果提示(切换了多少台)。 > 实测:`10962(walk) → 10229(旧)` 预览正确显示 **186 device(s)**(带设备名 chips)。当前环境旧模板 10229 挂 0 台,所以反向 `10229 → 10962` 为空操作——这是数据现状,不是功能问题。 ## 按钮乱码(已修复) 如果 L2 拓扑工具栏出现 `鈼?`、`鉂氣潥`、`锛?`、`?/span>` 之类的文字,那不是浏览器字体问题,而是 `topology.view.php` 里的 UTF-8 图标被按 GBK/ANSI 重新编码过。2.0.1 起图标全部改用 HTML 数字实体(`◷` / `▾` / `❚` / `+` / `−`),`install.sh` 也会在复制前扫描 PHP/JS,发现同类 mojibake 直接报错并停止安装。以后升级请直接重跑 `install.sh`,不要用文本编辑器“另存为”模块文件。 ## 已知限制(如实说明) - **核心 vs 接入的 `Link down` 无法在原型层面区分**(只有一个原型):两者统一设为“一般严重(Average=3)”,71 条核心链路不会被单独拔高;如需对核心链路更敏感,后续可加事件规则/标签区分。 - **模板“导入后切换”迁移**:功能已具备(导入 + 预览 + 确认切换)。当前环境旧模板 `Huawei VRP by SNMP(10229)` 挂载主机数为 0,全部 186 台已在 `Huawei VRP by SNMP walk(10962)`,所以“旧→新迁移”在此环境下是空操作;换到真有旧模板带机的环境才会真正迁移。 - **Geomap 底图**:Zabbix Geomap 组件需**浏览器能访问外网**加载 OSM 瓦片;纯内网环境下底图会空白(标记点逻辑仍正确)。