feat: 新增设备巡检模块实现完整的巡检告警功能

新增设备巡检模块核心功能,包括:
- 巡检数据存储与调度系统
- 华为/H3C交换机及Linux服务器采集器
- 设备扩展配置与告警规则管理
- 主机详情页巡检配置入口
- 产品名称自定义设置功能
- 网络设备SSH exec通道兼容处理
This commit is contained in:
2026-10-09 10:37:48 +08:00
parent 9202506c46
commit c64e00d835
75 changed files with 12087 additions and 446 deletions

View File

@@ -3,7 +3,31 @@ import { Host, Snippet } from '../../domain/models';
export const INITIAL_HOSTS: Host[] = [];
export const INITIAL_SNIPPETS: Snippet[] = [
{ id: '1', label: 'Check Disk Space', command: 'df -h', tags: [] },
{ id: '2', label: 'Tail System Log', command: 'tail -f /var/log/syslog', tags: [] },
{ id: '3', label: 'Update Ubuntu', command: 'sudo apt update && sudo apt upgrade -y', tags: [] },
// === 服务器系统 ===
{ id: 'sys-df', label: '磁盘使用', command: 'df -h', tags: ['系统'] },
{ id: 'sys-free', label: '内存使用', command: 'free -h', tags: ['系统'] },
{ id: 'sys-uptime', label: '运行时长', command: 'uptime', tags: ['系统'] },
{ id: 'sys-top', label: '进程快照', command: 'top -b -n1 | head -20', tags: ['系统'] },
{ id: 'sys-ss', label: '端口监听', command: 'sudo ss -tulpn', tags: ['系统'] },
{ id: 'sys-failed', label: '失败服务', command: 'sudo systemctl --failed', tags: ['系统'] },
{ id: 'sys-journal', label: '最近日志', command: 'journalctl -n 50 --no-pager', tags: ['系统'] },
// === 网络诊断 ===
{ id: 'net-ping', label: '连通性测试', command: 'ping -c 4 8.8.8.8', tags: ['网络'] },
{ id: 'net-trace', label: '路由追踪', command: 'traceroute 8.8.8.8', tags: ['网络'] },
{ id: 'net-dns', label: 'DNS 解析', command: 'nslookup google.com', tags: ['网络'] },
{ id: 'net-ip', label: '网卡详情', command: 'ip addr show', tags: ['网络'] },
{ id: 'net-fw', label: '防火墙规则', command: 'sudo iptables -L -n --line-numbers', tags: ['网络'] },
// === Docker ===
{ id: 'dk-ps', label: '容器列表', command: 'docker ps -a', tags: ['Docker'] },
{ id: 'dk-img', label: '镜像列表', command: 'docker images', tags: ['Docker'] },
{ id: 'dk-stats', label: '资源使用', command: 'docker stats --no-stream', tags: ['Docker'] },
{ id: 'dk-df', label: '磁盘占用', command: 'docker system df', tags: ['Docker'] },
{ id: 'dk-prune', label: '清理无用', command: 'docker system prune -af', tags: ['Docker'] },
// === 更新 / 维护 ===
{ id: 'upd-apt', label: 'Ubuntu 更新', command: 'sudo apt update && sudo apt upgrade -y', tags: ['更新'] },
{ id: 'upd-yum', label: 'CentOS/RHEL 更新', command: 'sudo yum update -y', tags: ['更新'] },
{ id: 'upd-tail-log', label: '实时系统日志', command: 'tail -f /var/log/syslog', tags: ['系统'] },
];

View File

@@ -3,7 +3,7 @@ export type LocaleOption = {
label: string;
};
export const DEFAULT_UI_LOCALE = 'en';
export const DEFAULT_UI_LOCALE = 'zh-CN';
// Add new languages by appending to this list and providing message dictionaries.
export const SUPPORTED_UI_LOCALES: LocaleOption[] = [

View File

@@ -1,3 +1,6 @@
/** User-editable product name shown in window title / about. */
export const STORAGE_KEY_PRODUCT_NAME = 'netcatty_product_name_v1';
export const STORAGE_KEY_HOSTS = 'netcatty_hosts_v1';
export const STORAGE_KEY_KEYS = 'netcatty_keys_v1';
export const STORAGE_KEY_GROUPS = 'netcatty_groups_v1';

View File

@@ -0,0 +1,268 @@
/**
* 巡检模块 - 前端 API 层
*
* 通过 window.electronAPI.inspection 调用主进程的巡检 IPC handlers。
*/
// ---------- 类型定义 ----------
export type AlertLevel = "critical" | "warning" | "info";
export type DeviceTier = "core" | "aggregation" | "access";
export type InspectionStatus = "success" | "failed" | "timeout";
export type AlertRecordStatus = "active" | "acknowledged" | "resolved" | "closed";
export type Operator = ">" | "<" | "==" | "!=" | ">=" | "<=";
export interface InspectionLabels {
alert_levels: Record<AlertLevel, string>;
device_tiers: Record<DeviceTier, string>;
inspection_status: Record<InspectionStatus, string>;
alert_record_status: Record<AlertRecordStatus, string>;
operators: Record<Operator, string>;
device_catalog: Record<string, string>;
metrics: Record<string, string>;
}
export interface DeviceCatalog {
id: string;
type_key: string;
name: string;
vendor: string;
adapter_class: string;
supported_metrics: string[];
default_thresholds: AlertRule[];
default_interval: number;
description: string;
preset: boolean;
}
export interface DeviceTierInfo {
key: DeviceTier;
label: string;
default_interval: number;
}
export interface DeviceExtension {
host_id: string;
/** 主机名(IP 或域名),用于调度器匹配 vault SSH 配置 */
hostname?: string | null;
catalog_id: string;
tier: DeviceTier | null;
inspection_interval: number | null;
inspection_enabled: boolean;
custom_thresholds: AlertRule[];
inspection_tags: string[];
last_scan_at: number | null;
last_scan_status: InspectionStatus | null;
last_scan_error: string | null;
created_at: number;
updated_at: number;
effective_interval?: number;
}
export interface AlertRule {
id: string;
name: string;
metric: string;
operator: Operator;
threshold: string;
level: AlertLevel;
duration: number;
scope_type: "all" | "tier" | "device" | "catalog";
scope_value: string | string[] | null;
enabled: boolean;
preset?: boolean;
created_at: number;
updated_at: number;
}
export interface InspectionResult {
id: string;
job_id: string | null;
device_id: string;
timestamp: number;
online: boolean;
status: InspectionStatus;
duration_ms: number;
metrics: Record<string, any>;
alerts: any[];
error_message: string | null;
}
export interface AlertRecord {
id: string;
rule_id: string;
rule_name: string;
device_id: string;
device_name: string;
metric: string;
metric_value: string;
threshold: string;
level: AlertLevel;
message: string;
triggered_at: number;
status: AlertRecordStatus;
acknowledged_by: string | null;
acknowledged_at: number | null;
resolved_at: number | null;
resolved_reason: string | null;
note: string | null;
}
export interface AlertStats {
total: number;
active: number;
active_critical: number;
active_warning: number;
active_info: number;
acknowledged: number;
resolved: number;
closed: number;
}
export interface SchedulerStatus {
running: boolean;
queue_size: number;
active_scans: number;
concurrency: number;
}
// ---------- API 调用 ----------
const api = (window as any).netcatty?.inspection;
function isAvailable(): boolean {
return !!api;
}
function invoke(name: string, ...args: any[]): Promise<any> {
if (!api || typeof api[name] !== "function") {
console.warn(`[Inspection] api.${name} 不可用`);
return Promise.resolve(null);
}
return api[name](...args);
}
// ---------- 标签 ----------
export const inspectionLabelsApi = {
isAvailable,
getLabels: (): Promise<InspectionLabels> => invoke("getLabels"),
};
// ---------- 系统配置 ----------
export const inspectionSysConfigApi = {
get: (): Promise<Record<string, any>> => invoke("getSysConfig"),
update: (updates: Record<string, any>) => invoke("updateSysConfig", updates),
};
// ---------- 设备类型 ----------
export const inspectionCatalogApi = {
list: (): Promise<DeviceCatalog[]> => invoke("getCatalog"),
getTiers: (): Promise<DeviceTierInfo[]> => invoke("getTiers"),
getAdapters: (): Promise<string[]> => invoke("getAdapters"),
};
// ---------- 设备扩展 ----------
export const inspectionDeviceApi = {
getAll: (): Promise<Record<string, DeviceExtension>> => invoke("getAllExtensions"),
get: (hostId: string): Promise<DeviceExtension | null> => invoke("getExtension", hostId),
upsert: (hostId: string, data: Partial<DeviceExtension>): Promise<DeviceExtension> =>
invoke("upsertExtension", hostId, data),
remove: (hostId: string): Promise<boolean> => invoke("deleteExtension", hostId),
getEffectiveInterval: (hostId: string): Promise<number> =>
invoke("getEffectiveInterval", hostId),
getEnabled: (): Promise<DeviceExtension[]> => invoke("getEnabledDevices"),
};
// ---------- 告警规则 ----------
export const inspectionAlertRuleApi = {
list: (): Promise<AlertRule[]> => invoke("listRules"),
get: (ruleId: string): Promise<AlertRule | null> => invoke("getRule", ruleId),
create: (data: Partial<AlertRule>): Promise<AlertRule> => invoke("createRule", data),
update: (ruleId: string, updates: Partial<AlertRule>): Promise<AlertRule | null> =>
invoke("updateRule", ruleId, updates),
remove: (ruleId: string): Promise<boolean> => invoke("deleteRule", ruleId),
toggle: (ruleId: string, enabled: boolean): Promise<AlertRule | null> =>
invoke("toggleRule", ruleId, enabled),
};
// ---------- 巡检结果 ----------
export const inspectionResultApi = {
getLatestAll: (): Promise<InspectionResult[]> => invoke("getLatestAll"),
getLatestByDevice: (hostId: string, limit = 20): Promise<InspectionResult[]> =>
invoke("getLatestByDevice", hostId, limit),
getRecent: (limit = 50): Promise<InspectionResult[]> =>
invoke("getRecentResults", limit),
};
// ---------- 告警记录 ----------
export const inspectionAlertApi = {
list: (options?: {
status?: AlertRecordStatus;
level?: AlertLevel;
device_id?: string;
limit?: number;
}): Promise<AlertRecord[]> => invoke("listAlerts", options),
getActive: (): Promise<AlertRecord[]> => invoke("getActiveAlerts"),
getStats: (): Promise<AlertStats> => invoke("getAlertStats"),
acknowledge: (alertId: string, operator = "system"): Promise<AlertRecord | null> =>
invoke("acknowledgeAlert", alertId, operator),
resolve: (
alertId: string,
reason = "manual",
operator = "system",
): Promise<AlertRecord | null> =>
invoke("resolveAlert", alertId, reason, operator),
close: (alertId: string, note = ""): Promise<AlertRecord | null> =>
invoke("closeAlert", alertId, note),
updateNote: (alertId: string, note: string): Promise<AlertRecord | null> =>
invoke("updateAlertNote", alertId, note),
};
// ---------- 调度器 ----------
// SSHConfig 是用于 SSH 连接的主机配置(hostname/port/username/password/privateKey 等)
export type SshHostConfig = Record<string, unknown>;
export const inspectionSchedulerApi = {
start: (hostConfigs?: Record<string, SshHostConfig>): Promise<SchedulerStatus> =>
invoke("schedulerStart", hostConfigs ? { hostConfigs } : {}),
stop: (): Promise<SchedulerStatus> => invoke("schedulerStop"),
status: (): Promise<SchedulerStatus> => invoke("schedulerStatus"),
scanNow: (hostId: string): Promise<any> => invoke("scanNow", hostId),
scanAllNow: (): Promise<any> => invoke("scanAllNow"),
};
// ---------- 单次巡检执行 ----------
export interface RunInspectionResult {
success: boolean;
status: string;
metrics: Record<string, any>;
error: string | null;
duration: number;
alerts: any[];
}
export interface HostConfigForInspection {
id: string;
label?: string;
hostname: string;
port?: number;
username: string;
password?: string;
privateKeyContent?: string;
passphrase?: string;
}
export const inspectionExecApi = {
/**
* 执行一次完整巡检(前端传入完整主机配置)
* @param hostId 主机 ID
* @param hostConfig 主机连接配置
* @param catalogId 设备类型 ID(采集器 ID)
*/
runInspection: (
hostId: string,
hostConfig: HostConfigForInspection,
catalogId: string
): Promise<RunInspectionResult> =>
invoke("runInspection", { hostId, hostConfig, catalogId }),
};