feat: 监控架构优化 — 模型层 + Prometheus/Zabbix/SNMP pkg + Dockerfile升级Go1.24

整合 /srv/监控架构优化方案 核心代码:

后端模型(4个新文件):
- monitor.go: MonitorTarget(统一监控目标) + MonitorMetric(指标定义) + MetricValue(时序数据) + MetricHistory
- snmp.go: SNMPDevice + SNMPTemplate + OID模板管理
- site.go: SiteTask(拨测任务) + SiteResult(拨测结果)
- alert_v2.go: 增强告警(多条件规则/模板/升级策略/静默)

后端 pkg(3个包):
- pkg/prometheus/client.go (531行): PromQL查询/Range/Labels/Rules
- pkg/zabbix/client.go: Zabbix API (Host/Item/Trigger/History)
- pkg/snmp/collector.go (621行): gosnmp Walk/BulkWalk/自动发现

基础设施:
- Dockerfile: Go 1.21→1.24 (gosnmp依赖)
- Agent安装弹框: SSH一键安装Tab + server上下文
- 服务器列表操作栏: 安装按钮条件显示/隐藏

Handler层因类型不兼容暂时跳过,模型和客户端包已编译通过。
This commit is contained in:
attacker committed 2026-06-18 11:52:10 +00:00
1 parent f3a9e5e8d0
commit 24fa17c2a8
13 files changed
+3427 -98

No files matched your search

+92 -6
View File
@@ -1,5 +1,4 @@
import { useState } from 'react';
import { toast } from 'sonner';
import { useUserStore } from '@/store';
import {
Dialog,
@@ -10,11 +9,19 @@ import {
} from '@/components/ui/dialog';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Button } from '@/components/ui/button';
import { Copy, Check, Terminal, Download, Settings, Play, Cpu } from 'lucide-react';
import { Copy, Check, Terminal, Download, Settings, Play, Cpu, Zap, Loader2, Server } from 'lucide-react';
import { serverApi } from '@/services/api';
import { toast } from 'sonner';
interface AgentWizardProps {
open: boolean;
onOpenChange: (open: boolean) => void;
/** 可选:从服务器列表传入的目标服务器信息 */
server?: { id: number; hostname: string; ip: string } | null;
/** SSH一键安装成功回调 */
onInstalled?: (serverId: number) => void;
/** SSH一键安装失败回调 */
onFailed?: (serverId: number, message: string) => void;
}
/** 自动检测地址:origin(通过 Nginx 80 代理)用于安装脚本下载,backend 8080 用于 agent 直连 */
@@ -28,11 +35,13 @@ function detectServerAddress() {
return { origin: 'http://127.0.0.1', backend: 'http://127.0.0.1:8080' };
}
export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
export function AgentWizard({ open, onOpenChange, server, onInstalled, onFailed }: AgentWizardProps) {
const token = useUserStore((s) => s.token) || '<YOUR_TOKEN>';
const { origin, backend } = detectServerAddress();
const [copied, setCopied] = useState(false);
const [showManualInput, setShowManualInput] = useState(false);
const [sshInstalling, setSshInstalling] = useState(false);
const [activeTab, setActiveTab] = useState('auto');
// install.sh 通过 Nginx 代理下载(origin:80 → /agent/ → backend:8080)
const installCommand = `curl -fsSL ${origin}/agent/install.sh | bash -s -- --server ${backend} --token ${token}`;
@@ -132,22 +141,58 @@ export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
},
];
// SSH 一键安装(当从服务器列表传入 server 上下文时可用)
const handleSshInstall = async () => {
if (!server || !token) return;
setSshInstalling(true);
try {
const res: any = await serverApi.installAgent(server.id, token);
const installed = res?.installed || false;
if (installed) {
toast.success(`${server.hostname} Agent 安装成功`);
onInstalled?.(server.id);
onOpenChange(false);
} else {
toast.warning(`${server.hostname}: Agent 安装命令已执行,但服务未检测到运行`);
onInstalled?.(server.id);
onOpenChange(false);
}
} catch (e: any) {
const msg = e?.message || '安装失败';
toast.error(`${server.hostname} ${msg}`);
onFailed?.(server.id, msg);
} finally {
setSshInstalling(false);
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl bg-slate-900 border-slate-800 text-slate-100">
<DialogHeader>
<DialogTitle className="text-slate-100">部署 Agent</DialogTitle>
<DialogTitle className="text-slate-100">
{server ? `部署 Agent → ${server.hostname}` : '部署 Agent'}
</DialogTitle>
<DialogDescription className="text-slate-400">
在目标主机上执行以下命令即可完成 Agent 安装与注册
{server
? `目标主机 ${server.hostname} (${server.ip}),选择安装方式:`
: '在目标主机上执行以下命令即可完成 Agent 安装与注册'
}
</DialogDescription>
</DialogHeader>
<Tabs defaultValue="auto" className="w-full">
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="bg-slate-800 border border-slate-700">
<TabsTrigger value="auto" className="data-[state=active]:bg-slate-700">
<Terminal className="h-4 w-4 mr-1.5" />
安装Agent
</TabsTrigger>
{server && (
<TabsTrigger value="ssh" className="data-[state=active]:bg-slate-700">
<Zap className="h-4 w-4 mr-1.5" />
SSH一键安装
</TabsTrigger>
)}
<TabsTrigger value="manual" className="data-[state=active]:bg-slate-700">
手动安装
</TabsTrigger>
@@ -195,6 +240,47 @@ export function AgentWizard({ open, onOpenChange }: AgentWizardProps) {
</div>
</TabsContent>
{/* SSH 一键安装 — 仅当从服务器列表传入时显示 */}
{server && (
<TabsContent value="ssh" className="mt-4 space-y-4">
<div className="rounded-lg bg-slate-950 border border-slate-800 p-4">
<div className="flex items-center gap-3 mb-3">
<Server className="h-5 w-5 text-blue-400" />
<div>
<p className="text-sm font-medium text-slate-200">{server.hostname}</p>
<code className="text-xs text-slate-400">{server.ip}</code>
</div>
</div>
<p className="text-sm text-slate-400 mb-4">
通过 SSH 远程连接到目标主机,自动下载并安装 Agent,完成后立即启动运行。
</p>
<Button
onClick={handleSshInstall}
disabled={sshInstalling}
className="w-full bg-blue-600 hover:bg-blue-700 text-white"
>
{sshInstalling ? (
<>
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
SSH 连接中,正在安装...
</>
) : (
<>
<Zap className="h-4 w-4 mr-2" />
一键安装 Agent
</>
)}
</Button>
</div>
<div className="flex items-start gap-2 text-xs text-slate-500">
<Terminal className="h-3.5 w-3.5 mt-0.5 shrink-0" />
<span>
系统将通过 SSH 连接 {server.ip},执行安装脚本。请确保服务器 SSH 凭据已正确配置(编辑服务器可修改密码/密钥)。
</span>
</div>
</TabsContent>
)}
{/* 手动安装 */}
<TabsContent value="manual" className="mt-4 space-y-4">
<div className="max-h-[420px] overflow-y-auto space-y-3 pr-1">