Files
NetMesh/electron/bridges/inspection/alertRuleStore.cjs
zhaolei c64e00d835 feat: 新增设备巡检模块实现完整的巡检告警功能
新增设备巡检模块核心功能,包括:
- 巡检数据存储与调度系统
- 华为/H3C交换机及Linux服务器采集器
- 设备扩展配置与告警规则管理
- 主机详情页巡检配置入口
- 产品名称自定义设置功能
- 网络设备SSH exec通道兼容处理
2026-10-09 10:37:48 +08:00

544 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
/**
* 告警规则数据存储
*
* 告警规则结构:
* {
* id: "rule_xxx",
* name: "CPU 使用率过高",
* metric: "cpu_usage",
* operator: ">",
* threshold: "80",
* level: "critical",
* duration: 1, // 连续超标次数(防抖动)
* scope_type: "all", // all / tier / device / catalog
* scope_value: null, // 范围值(tier_key 或 hostId 数组 或 catalog_id)
* enabled: true,
* created_at: timestamp,
* updated_at: timestamp,
* }
*/
const { STORAGE_KEY_ALERT_RULES } = require("./storageKeys.cjs");
const { OPERATORS, ALERT_LEVELS } = require("./types.cjs");
let _rules = null;
function _ensureLoaded(readFn) {
if (_rules === null) {
const raw = readFn(STORAGE_KEY_ALERT_RULES);
_rules = raw ? _safeParse(raw, []) : _getDefaultRules();
}
}
function _safeParse(text, def) {
try { return JSON.parse(text); }
catch (e) { return def; }
}
function _save(writeFn) {
writeFn(STORAGE_KEY_ALERT_RULES, JSON.stringify(_rules));
}
/**
* 默认告警规则(预置)
*/
function _getDefaultRules() {
return [
{
id: "rule_cpu_critical",
name: "CPU 使用率过高",
metric: "cpu_usage",
operator: OPERATORS.GT,
threshold: "80",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_cpu_warning",
name: "CPU 使用率异常",
metric: "cpu_usage",
operator: OPERATORS.GT,
threshold: "70",
level: ALERT_LEVELS.WARNING,
duration: 2,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_memory_critical",
name: "内存使用率过高",
metric: "memory_usage",
operator: OPERATORS.GT,
threshold: "85",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_memory_warning",
name: "内存使用率异常",
metric: "memory_usage",
operator: OPERATORS.GT,
threshold: "75",
level: ALERT_LEVELS.WARNING,
duration: 2,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_offline",
name: "设备离线",
metric: "online",
operator: OPERATORS.EQ,
threshold: "false",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
// ---------- 磁盘使用率 ----------
{
id: "rule_disk_critical",
name: "磁盘使用率过高",
metric: "disk_usage",
operator: OPERATORS.GT,
threshold: "90",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_disk_warning",
name: "磁盘使用率异常",
metric: "disk_usage",
operator: OPERATORS.GT,
threshold: "80",
level: ALERT_LEVELS.WARNING,
duration: 2,
scope_type: "all",
scope_value: null,
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
// ---------- 网络设备通用(交换机/防火墙) ----------
{
id: "rule_netdev_temp_critical",
name: "设备温度过高",
metric: "temperature",
operator: OPERATORS.GT,
threshold: "60",
level: ALERT_LEVELS.CRITICAL,
duration: 2,
scope_type: "catalog",
scope_value: "huawei_h3c_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_netdev_power_critical",
name: "电源模块故障",
metric: "power_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "catalog",
scope_value: "huawei_h3c_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_netdev_fan_warning",
name: "风扇模块故障",
metric: "fan_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.WARNING,
duration: 1,
scope_type: "catalog",
scope_value: "huawei_h3c_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_netdev_portdown_warning",
name: "端口 Down 数过多",
metric: "port_down_count",
operator: OPERATORS.GT,
threshold: "2",
level: ALERT_LEVELS.WARNING,
duration: 2,
scope_type: "catalog",
scope_value: "huawei_h3c_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_netdev_cpu_warning",
name: "交换机 CPU 使用率过高",
metric: "cpu_usage",
operator: OPERATORS.GT,
threshold: "75",
level: ALERT_LEVELS.WARNING,
duration: 2,
scope_type: "catalog",
scope_value: "huawei_h3c_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_netdev_memory_warning",
name: "交换机内存使用率过高",
metric: "memory_usage",
operator: OPERATORS.GT,
threshold: "80",
level: ALERT_LEVELS.WARNING,
duration: 2,
scope_type: "catalog",
scope_value: "huawei_h3c_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
// ---------- Cisco 交换机 ----------
{
id: "rule_cisco_temp_critical",
name: "Cisco 交换机温度过高",
metric: "temperature",
operator: OPERATORS.GT,
threshold: "60",
level: ALERT_LEVELS.CRITICAL,
duration: 2,
scope_type: "catalog",
scope_value: "cisco_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_cisco_power_critical",
name: "Cisco 电源模块故障",
metric: "power_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "catalog",
scope_value: "cisco_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_cisco_fan_warning",
name: "Cisco 风扇模块故障",
metric: "fan_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.WARNING,
duration: 1,
scope_type: "catalog",
scope_value: "cisco_switch",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
// ---------- 华为防火墙 ----------
{
id: "rule_hwfw_temp_critical",
name: "华为防火墙温度过高",
metric: "temperature",
operator: OPERATORS.GT,
threshold: "60",
level: ALERT_LEVELS.CRITICAL,
duration: 2,
scope_type: "catalog",
scope_value: "huawei_firewall",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_hwfw_power_critical",
name: "华为防火墙电源故障",
metric: "power_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "catalog",
scope_value: "huawei_firewall",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_hwfw_fan_warning",
name: "华为防火墙风扇故障",
metric: "fan_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.WARNING,
duration: 1,
scope_type: "catalog",
scope_value: "huawei_firewall",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
// ---------- 飞塔防火墙 ----------
{
id: "rule_fortinet_temp_critical",
name: "飞塔防火墙温度过高",
metric: "temperature",
operator: OPERATORS.GT,
threshold: "60",
level: ALERT_LEVELS.CRITICAL,
duration: 2,
scope_type: "catalog",
scope_value: "fortinet_firewall",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_fortinet_power_critical",
name: "飞塔防火墙电源故障",
metric: "power_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.CRITICAL,
duration: 1,
scope_type: "catalog",
scope_value: "fortinet_firewall",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
{
id: "rule_fortinet_fan_warning",
name: "飞塔防火墙风扇故障",
metric: "fan_failure_count",
operator: OPERATORS.GT,
threshold: "0",
level: ALERT_LEVELS.WARNING,
duration: 1,
scope_type: "catalog",
scope_value: "fortinet_firewall",
enabled: true,
preset: true,
created_at: Date.now(),
updated_at: Date.now(),
},
];
}
// ---------- CRUD ----------
function listRules(readFn) {
_ensureLoaded(readFn);
return [..._rules];
}
function getRule(readFn, ruleId) {
_ensureLoaded(readFn);
return _rules.find((r) => r.id === ruleId) || null;
}
function createRule(readFn, writeFn, data) {
_ensureLoaded(readFn);
const rule = {
id: `rule_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
name: data.name,
metric: data.metric,
operator: data.operator,
threshold: String(data.threshold),
level: data.level,
duration: data.duration || 1,
scope_type: data.scope_type || "all",
scope_value: data.scope_value || null,
enabled: data.enabled !== false,
preset: false,
created_at: Date.now(),
updated_at: Date.now(),
};
_rules.push(rule);
_save(writeFn);
return { ...rule };
}
function updateRule(readFn, writeFn, ruleId, updates) {
_ensureLoaded(readFn);
const idx = _rules.findIndex((r) => r.id === ruleId);
if (idx === -1) return null;
_rules[idx] = {
..._rules[idx],
...updates,
updated_at: Date.now(),
};
_save(writeFn);
return { ..._rules[idx] };
}
function deleteRule(readFn, writeFn, ruleId) {
_ensureLoaded(readFn);
const idx = _rules.findIndex((r) => r.id === ruleId);
if (idx === -1) return false;
_rules.splice(idx, 1);
_save(writeFn);
return true;
}
function toggleRule(readFn, writeFn, ruleId, enabled) {
return updateRule(readFn, writeFn, ruleId, { enabled });
}
// ---------- 告警判断 ----------
/**
* 判断指标值是否触发规则
* @param {number|string} value - 指标值
* @param {string} operator - 比较符
* @param {string} threshold - 阈值
* @returns {boolean}
*/
function evaluateRule(value, operator, threshold) {
if (value === null || value === undefined) return false;
// disk_usage 是数组,检查任意挂载点是否超标
if (Array.isArray(value)) {
const numThreshold = parseFloat(threshold);
if (isNaN(numThreshold)) return false;
// 数组中每个元素是 { filesystem, usage_percent, mount }
return value.some((d) => {
const usage = typeof d === "object" ? d.usage_percent : parseFloat(d);
return !isNaN(usage) && usage > numThreshold;
});
}
// 数字比较
const numValue = parseFloat(value);
const numThreshold = parseFloat(threshold);
if (!isNaN(numValue) && !isNaN(numThreshold)) {
switch (operator) {
case OPERATORS.GT: return numValue > numThreshold;
case OPERATORS.LT: return numValue < numThreshold;
case OPERATORS.GTE: return numValue >= numThreshold;
case OPERATORS.LTE: return numValue <= numThreshold;
case OPERATORS.EQ: return numValue === numThreshold;
case OPERATORS.NE: return numValue !== numThreshold;
}
}
// 字符串比较
const strValue = String(value);
const strThreshold = String(threshold);
switch (operator) {
case OPERATORS.EQ: return strValue === strThreshold;
case OPERATORS.NE: return strValue !== strThreshold;
default: return false;
}
}
/**
* 获取设备适用的所有规则
* @param {object} deviceExt - 设备扩展信息
* @returns {Array} 适用的规则列表
*/
function getRulesForDevice(readFn, deviceExt) {
_ensureLoaded(readFn);
return _rules.filter((rule) => {
if (!rule.enabled) return false;
switch (rule.scope_type) {
case "all":
return true;
case "tier":
return deviceExt.tier && deviceExt.tier === rule.scope_value;
case "device":
return Array.isArray(rule.scope_value) && rule.scope_value.includes(deviceExt.host_id);
case "catalog":
return deviceExt.catalog_id === rule.scope_value;
default:
return false;
}
});
}
// ---------- 重置(测试用) ----------
function _resetForTest() {
_rules = null;
}
module.exports = {
listRules,
getRule,
createRule,
updateRule,
deleteRule,
toggleRule,
evaluateRule,
getRulesForDevice,
_resetForTest,
};