diff --git a/internal/app.go b/internal/app.go index 7663764..f658b93 100644 --- a/internal/app.go +++ b/internal/app.go @@ -135,6 +135,7 @@ func setupApi(app *orz.App, components *AppComponents) { // Agent 版本和下载(完全公开,无需任何认证) publicApi.GET("/agent/version", components.AgentHandler.GetAgentVersion) publicApi.GET("/agent/downloads/:filename", components.AgentHandler.DownloadAgent) + publicApi.GET("/agent/install.sh", components.AgentHandler.GetInstallScript) } // 公开接口(支持可选认证)- 已登录返回全部数据,未登录只返回公开数据 diff --git a/internal/handler/agent_handler.go b/internal/handler/agent_handler.go index f2fd76c..d0f6bd6 100644 --- a/internal/handler/agent_handler.go +++ b/internal/handler/agent_handler.go @@ -802,3 +802,148 @@ func (h *AgentHandler) GetTags(c echo.Context) error { "tags": tags, }) } + +// GetInstallScript 生成自动安装脚本 +func (h *AgentHandler) GetInstallScript(c echo.Context) error { + token := c.QueryParam("token") + if token == "" { + return orz.NewError(400, "token不能为空") + } + + serverUrl := c.Scheme() + "://" + c.Request().Host + + script := `#!/bin/bash +set -e + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +echo_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +echo_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +# 检查是否为 root 用户 +if [ "$EUID" -ne 0 ]; then + echo_error "请使用 root 权限运行此脚本" + echo_info "使用方式: sudo bash install.sh" + exit 1 +fi + +# 检测操作系统和架构 +detect_platform() { + OS=$(uname -s | tr '[:upper:]' '[:lower:]') + ARCH=$(uname -m) + + case "$ARCH" in + x86_64) + ARCH="amd64" + ;; + aarch64|arm64) + ARCH="arm64" + ;; + *) + echo_error "不支持的架构: $ARCH" + exit 1 + ;; + esac + + case "$OS" in + linux) + PLATFORM="linux-$ARCH" + AGENT_NAME="pika-agent" + ;; + darwin) + PLATFORM="darwin-$ARCH" + AGENT_NAME="pika-agent" + ;; + *) + echo_error "不支持的操作系统: $OS" + exit 1 + ;; + esac + + echo_info "检测到平台: $PLATFORM" +} + +# 下载探针 +download_agent() { + local download_url="` + serverUrl + `/api/agent/downloads/agent-$PLATFORM" + local temp_file="/tmp/pika-agent-download" + + echo_info "正在下载探针..." + + if command -v wget &> /dev/null; then + wget -q --show-progress "$download_url" -O "$temp_file" + elif command -v curl &> /dev/null; then + curl -# -L "$download_url" -o "$temp_file" + else + echo_error "未找到 wget 或 curl 命令,请先安装其中之一" + exit 1 + fi + + if [ ! -f "$temp_file" ]; then + echo_error "下载失败" + exit 1 + fi + + # 移动到目标位置 + mv "$temp_file" "/usr/local/bin/$AGENT_NAME" + chmod +x "/usr/local/bin/$AGENT_NAME" + + echo_info "探针下载完成: /usr/local/bin/$AGENT_NAME" +} + +# 注册并启动服务 +register_agent() { + local endpoint="` + serverUrl + `" + local token="` + token + `" + + echo_info "正在注册探针..." + + if /usr/local/bin/$AGENT_NAME register --endpoint "$endpoint" --token "$token"; then + echo_info "探针注册成功" + else + echo_error "探针注册失败" + exit 1 + fi +} + +# 主流程 +main() { + echo_info "开始安装 Pika Agent..." + echo "" + + detect_platform + download_agent + register_agent + + echo "" + echo_info "==========================================" + echo_info "安装完成!" + echo_info "==========================================" + echo "" + echo_info "常用命令:" + echo " 查看状态: pika-agent status" + echo " 启动服务: pika-agent start" + echo " 停止服务: pika-agent stop" + echo " 重启服务: pika-agent restart" + echo " 卸载服务: pika-agent uninstall" + echo "" +} + +main` + + c.Response().Header().Set("Content-Type", "text/plain; charset=utf-8") + return c.String(http.StatusOK, script) +} diff --git a/web/src/pages/AdminLayout/index.tsx b/web/src/pages/AdminLayout/index.tsx index 80e2001..8f5d6a3 100644 --- a/web/src/pages/AdminLayout/index.tsx +++ b/web/src/pages/AdminLayout/index.tsx @@ -2,7 +2,7 @@ import {type JSX, useEffect, useMemo, useState} from 'react'; import {Outlet, useLocation, useNavigate} from 'react-router-dom'; import type {MenuProps} from 'antd'; import {App, Avatar, Button, Dropdown, Space} from 'antd'; -import {Activity, Eye, Key, LogOut, Server, Settings, User as UserIcon} from 'lucide-react'; +import {Activity, BookOpen, Eye, Key, LogOut, Server, Settings, User as UserIcon} from 'lucide-react'; import {logout} from '../../api/auth'; import {getServerVersion} from '../../api/agent'; import type {User} from '../../types'; @@ -131,6 +131,14 @@ const AdminLayout = () => { > 公共页面 + } + onClick={() => navigate('/admin/agents-install')} + className="!h-9 !items-center !rounded-full !px-3 !text-xs !text-white hover:!bg-blue-500/10" + > + 部署指南 + { - const [selectedOS, setSelectedOS] = useState('linux-amd64'); + const [selectedOS, setSelectedOS] = useState('linux'); const [apiKeys, setApiKeys] = useState([]); const [selectedApiKey, setSelectedApiKey] = useState(''); @@ -44,8 +44,8 @@ const AgentInstall = () => { }, []); const osConfigs: Record = { - 'linux-amd64': { - name: 'Linux (AMD64)', + 'linux': { + name: 'Linux', icon: , downloadUrl: '/api/agent/downloads/agent-linux-amd64', }, @@ -64,13 +64,8 @@ const AgentInstall = () => { icon: , downloadUrl: '/api/agent/downloads/agent-darwin-amd64', }, - 'darwin-arm64': { - name: 'macOS (Apple Silicon)', - icon: , - downloadUrl: '/api/agent/downloads/agent-darwin-arm64', - }, - 'windows-amd64': { - name: 'Windows (AMD64)', + 'windows': { + name: 'Windows', icon: , downloadUrl: '/api/agent/downloads/agent-windows-amd64.exe', }, @@ -81,36 +76,24 @@ const AgentInstall = () => { message.success('已复制到剪贴板'); }; - // 一键注册命令 - const getRegisterCommand = (os: string) => { - const config = osConfigs[os]; - const agentName = os.startsWith('windows') ? 'pika-agent.exe' : 'pika-agent'; + // 获取一键安装命令 + const getInstallCommand = (os: string) => { const token = selectedApiKey; if (os.startsWith('windows')) { - return `# 1. 下载探针 + // Windows 使用 PowerShell 手动安装 + const config = osConfigs[os]; + const agentName = 'pika-agent.exe'; + return `# Windows 安装方式(需要管理员权限) + +# 1. 下载探针 Invoke-WebRequest -Uri "${serverUrl}${config.downloadUrl}" -OutFile "${agentName}" -# 2. 运行注册命令(需要管理员权限) +# 2. 运行注册命令 .\\${agentName} register --endpoint "${serverUrl}" --token "${token}"`; - } else if (os.startsWith('linux')) { - return `# 1. 下载探针 -wget ${serverUrl}${config.downloadUrl} -O ${agentName} - -# 2. 添加执行权限 -chmod +x ${agentName} - -# 3. 运行注册命令(需要 root 权限) -sudo ./${agentName} register --endpoint "${serverUrl}" --token "${token}"`; - } else { // macOS - return `# 1. 下载探针 -curl -L ${serverUrl}${config.downloadUrl} -o ${agentName} - -# 2. 添加执行权限 -chmod +x ${agentName} - -# 3. 运行注册命令(需要 root 权限) -sudo ./${agentName} register --endpoint "${serverUrl}" --token "${token}"`; + } else { + // Linux/macOS 使用一键安装脚本 + return `curl -fsSL ${serverUrl}/api/agent/install.sh?token=${token} | sudo bash`; } }; @@ -195,14 +178,19 @@ ${agentCmd} version`; key={key} > - - - {getRegisterCommand(key)} - + + {!key.startsWith('windows') && ( + + 脚本会自动检测系统架构并下载对应版本的探针,然后完成注册和安装。 + + )} + + {getInstallCommand(key)} + { - copyToClipboard(getRegisterCommand(key)); + copyToClipboard(getInstallCommand(key)); }} icon={} style={{margin: 0, padding: 0}}
- {getRegisterCommand(key)} -
{getRegisterCommand(key)}
+ {getInstallCommand(key)} +
{getInstallCommand(key)}