Files
SenMeshNet/electron/bridges/inspection/alertRuleStore.cjs

554 lines
14 KiB
JavaScript
Raw Normal View History

"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) {
if (text === null || text === undefined) return def;
if (typeof text === "object") return text;
try { return JSON.parse(text); }
catch { 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;
}
});
}
// ---------- 批量保存(远程 HTTP 用) ----------
function saveRules(readFn, writeFn, rules) {
_rules = Array.isArray(rules) ? rules : [];
_save(writeFn);
return _rules;
}
// ---------- 重置(测试用) ----------
function _resetForTest() {
_rules = null;
}
module.exports = {
listRules,
getRule,
createRule,
updateRule,
deleteRule,
toggleRule,
evaluateRule,
getRulesForDevice,
saveRules,
_resetForTest,
};