Initial commit

This commit is contained in:
dushixiang committed 2025-11-10 22:11:46 +08:00
commit 37ba35a2f3
106 files changed
+26873

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Pika Agent 配置文件示例
# 配置文件默认路径: ~/.pika/agent.yaml
# 服务器配置
server:
# 服务器地址(不需要指定协议路径,会自动拼接)
# 例如: http://localhost:18888 或 https://your-server.com
endpoint: http://localhost:18888
# API Key(必填,从服务端获取)
api_key: "your-api-key-here"
# Agent 配置
agent:
# Agent 名称(可选,默认使用主机名)
# 用于在服务端区分不同的探针
name: ""
# 采集器配置
collector:
# 数据采集间隔(秒)
# 建议: 5-60 秒,太短会增加服务器负载
interval: 5
# 心跳间隔(秒)
# 建议: 30-120 秒
heartbeat_interval: 30
# 网络采集排除的网卡列表(可选,支持正则表达式)
# 如果不配置,默认只排除回环地址(lo, lo0)
# 支持正则表达式匹配网卡名称
network_exclude:
- "^lo$" # 排除 lo 接口(回环地址)
- "^lo0$" # 排除 lo0 接口(回环地址)
- "^docker.*" # 排除所有 docker 开头的接口
- "^veth.*" # 排除所有 veth 开头的虚拟接口
- "^br-.*" # 排除所有 br- 开头的网桥接口
# 自动更新配置
auto_update:
# 是否启用自动更新
# 启用后会定期检查服务端版本,有新版本时自动下载并更新
# 更新地址会自动从 server.endpoint 获取
enabled: false
# 检查更新间隔(小时)
# 建议: 6-24 小时
check_interval: 24
+545
View File
@@ -0,0 +1,545 @@
package main
import (
"bufio"
"fmt"
"log"
"os"
"runtime"
"strings"
"github.com/dushixiang/pika/pkg/agent/config"
"github.com/dushixiang/pika/pkg/agent/service"
"github.com/dushixiang/pika/pkg/agent/updater"
"github.com/spf13/cobra"
)
var (
configPath string
)
// rootCmd 根命令
var rootCmd = &cobra.Command{
Use: "agent",
Short: "Pika 监控探针",
Long: `Pika Agent 是一个轻量级的系统监控探针,用于采集服务器的各项性能指标并上报到 Pika 服务端。`,
Run: func(cmd *cobra.Command, args []string) {
_ = cmd.Help()
},
}
// versionCmd 版本命令
var versionCmd = &cobra.Command{
Use: "version",
Short: "显示版本信息",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Pika Agent v%s\n", service.GetVersion())
fmt.Printf("OS: %s\n", runtime.GOOS)
fmt.Printf("Arch: %s\n", runtime.GOARCH)
fmt.Printf("Go Version: %s\n", runtime.Version())
},
}
// runCmd 运行命令
var runCmd = &cobra.Command{
Use: "run",
Short: "运行探针",
Long: `启动探针并连接到服务器,开始采集和上报监控数据`,
Run: runAgent,
}
// installCmd 安装服务命令
var installCmd = &cobra.Command{
Use: "install",
Short: "安装为系统服务",
Long: `将 Agent 安装为系统服务(systemd/launchd),开机自动启动`,
Run: installService,
}
// uninstallCmd 卸载服务命令
var uninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "卸载系统服务",
Long: `从系统中卸载 Agent 服务`,
Run: uninstallService,
}
// startCmd 启动服务命令
var startCmd = &cobra.Command{
Use: "start",
Short: "启动服务",
Long: `启动已安装的 Agent 服务`,
Run: startService,
}
// stopCmd 停止服务命令
var stopCmd = &cobra.Command{
Use: "stop",
Short: "停止服务",
Long: `停止正在运行的 Agent 服务`,
Run: stopService,
}
// restartCmd 重启服务命令
var restartCmd = &cobra.Command{
Use: "restart",
Short: "重启服务",
Long: `重启 Agent 服务`,
Run: restartService,
}
// statusCmd 查看服务状态命令
var statusCmd = &cobra.Command{
Use: "status",
Short: "查看服务状态",
Long: `查看 Agent 服务的运行状态`,
Run: statusService,
}
// configCmd 配置命令
var configCmd = &cobra.Command{
Use: "config",
Short: "配置管理",
Long: `管理 Agent 配置文件`,
}
// configInitCmd 初始化配置命令
var configInitCmd = &cobra.Command{
Use: "init",
Short: "初始化配置文件",
Long: `创建默认配置文件`,
Run: initConfig,
}
// configShowCmd 显示配置命令
var configShowCmd = &cobra.Command{
Use: "show",
Short: "显示配置文件路径",
Long: `显示当前配置文件的路径`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("配置文件路径: %s\n", configPath)
},
}
// updateCmd 更新命令
var updateCmd = &cobra.Command{
Use: "update",
Short: "检查并更新",
Long: `检查是否有新版本可用,并进行更新`,
Run: updateAgent,
}
// registerCmd 注册命令
var registerCmd = &cobra.Command{
Use: "register",
Short: "注册并安装探针",
Long: `交互式引导注册探针:配置服务端地址、Token、名称,然后自动安装为系统服务并启动`,
Run: registerAgent,
}
var (
serverEndpoint string
serverAPIKey string
agentName string
)
func init() {
// 全局参数
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "配置文件路径(默认: ~/.pika/agent.yaml)")
// 注册命令的参数
registerCmd.Flags().StringVarP(&serverEndpoint, "endpoint", "e", "", "服务端地址 (例如: http://your-server.com:18888)")
registerCmd.Flags().StringVarP(&serverAPIKey, "token", "t", "", "API Token")
registerCmd.Flags().StringVarP(&agentName, "name", "n", "", "探针名称(默认使用主机名)")
// 添加子命令
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(registerCmd) // 注册命令放在前面,方便用户发现
rootCmd.AddCommand(runCmd)
rootCmd.AddCommand(installCmd)
rootCmd.AddCommand(uninstallCmd)
rootCmd.AddCommand(startCmd)
rootCmd.AddCommand(stopCmd)
rootCmd.AddCommand(restartCmd)
rootCmd.AddCommand(statusCmd)
rootCmd.AddCommand(updateCmd)
// 配置命令
configCmd.AddCommand(configInitCmd)
configCmd.AddCommand(configShowCmd)
rootCmd.AddCommand(configCmd)
if configPath == "" {
configPath = config.GetDefaultConfigPath()
}
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "错误: %v\n", err)
os.Exit(1)
}
}
// runAgent 运行探针
func runAgent(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 运行服务
if err := mgr.Run(); err != nil {
log.Fatalf("❌ 运行失败: %v", err)
}
}
// installService 安装服务
func installService(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 安装服务
if err := mgr.Install(); err != nil {
log.Fatalf("❌ 安装服务失败: %v", err)
}
log.Println("✅ 服务安装成功")
log.Println(" 使用 'agent start' 启动服务")
}
// uninstallService 卸载服务
func uninstallService(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 卸载服务
if err := mgr.Uninstall(); err != nil {
log.Fatalf("❌ 卸载服务失败: %v", err)
}
log.Println("✅ 服务卸载成功")
}
// startService 启动服务
func startService(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 启动服务
if err := mgr.Start(); err != nil {
log.Fatalf("❌ 启动服务失败: %v", err)
}
log.Println("✅ 服务启动成功")
}
// stopService 停止服务
func stopService(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 停止服务
if err := mgr.Stop(); err != nil {
log.Fatalf("❌ 停止服务失败: %v", err)
}
log.Println("✅ 服务停止成功")
}
// restartService 重启服务
func restartService(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 重启服务
if err := mgr.Restart(); err != nil {
log.Fatalf("❌ 重启服务失败: %v", err)
}
log.Println("✅ 服务重启成功")
}
// statusService 查看服务状态
func statusService(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
// 创建服务管理器
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
// 查看服务状态
status, err := mgr.Status()
if err != nil {
log.Printf("⚠️ 获取服务状态失败: %v", err)
}
fmt.Println(status)
}
// initConfig 初始化配置文件
func initConfig(cmd *cobra.Command, args []string) {
if configPath == "" {
configPath = config.GetDefaultConfigPath()
}
// 创建默认配置
cfg := config.DefaultConfig()
// 保存配置
if err := cfg.Save(configPath); err != nil {
log.Fatalf("❌ 保存配置文件失败: %v", err)
}
log.Printf("✅ 配置文件已创建: %s", configPath)
log.Println(" 请编辑配置文件,设置 server.api_key 等必要参数")
}
// updateAgent 检查并更新
func updateAgent(cmd *cobra.Command, args []string) {
// 加载配置
cfg, err := config.Load(configPath)
if err != nil {
log.Fatalf("❌ 加载配置失败: %v", err)
}
log.Println("🔍 检查更新...")
// 检查更新
versionInfo, err := updater.CheckUpdate(cfg.GetUpdateURL(), service.GetVersion())
if err != nil {
log.Fatalf("❌ 检查更新失败: %v", err)
}
// 比较版本
if versionInfo.Version == service.GetVersion() {
log.Printf("✅ 当前已是最新版本: %s", service.GetVersion())
return
}
log.Printf("🆕 发现新版本: %s (当前版本: %s)", versionInfo.Version, service.GetVersion())
// 下载并更新
downloadURL := cfg.GetDownloadURL()
if err := updater.Update(downloadURL); err != nil {
log.Fatalf("❌ 更新失败: %v", err)
}
log.Println("✅ 更新成功")
log.Println(" 请重启服务以使用新版本")
}
// registerAgent 注册探针
func registerAgent(cmd *cobra.Command, args []string) {
reader := bufio.NewReader(os.Stdin)
log.Println("═══════════════════════════════════════")
log.Println(" 🚀 Pika Agent 注册向导")
log.Println("═══════════════════════════════════════")
log.Println()
// 1. 获取服务端地址(优先使用命令行参数)
var endpoint string
if serverEndpoint != "" {
endpoint = serverEndpoint
log.Printf("📡 服务端地址: %s (来自命令行参数)", endpoint)
} else {
for {
fmt.Print("📡 请输入服务端地址 (例如: http://your-server.com:18888): ")
input, _ := reader.ReadString('\n')
endpoint = strings.TrimSpace(input)
if endpoint != "" {
break
}
log.Println(" ❌ 服务端地址不能为空,请重新输入")
}
}
// 2. 获取 API Token(优先使用命令行参数)
var apiKey string
if serverAPIKey != "" {
apiKey = serverAPIKey
log.Printf("🔑 API Token: %s (来自命令行参数)", maskToken(apiKey))
} else {
for {
fmt.Print("🔑 请输入 API Token: ")
input, _ := reader.ReadString('\n')
apiKey = strings.TrimSpace(input)
if apiKey != "" {
break
}
log.Println(" ❌ API Token 不能为空,请重新输入")
}
}
// 3. 获取探针名称(优先使用命令行参数,否则询问用户,默认使用主机名)
hostname, _ := os.Hostname()
var name string
if agentName != "" {
name = agentName
log.Printf("📝 探针名称: %s (来自命令行参数)", name)
} else {
fmt.Printf("📝 请输入探针名称 (留空使用主机名 '%s'): ", hostname)
nameInput, _ := reader.ReadString('\n')
name = strings.TrimSpace(nameInput)
if name == "" {
name = hostname
}
}
log.Println()
log.Println("─────────────────────────────────────")
log.Println("📋 配置信息:")
log.Printf(" 服务端地址: %s", endpoint)
log.Printf(" API Token: %s", maskToken(apiKey))
log.Printf(" 探针名称: %s", name)
log.Println("─────────────────────────────────────")
log.Println()
// 4. 确认
fmt.Print("❓ 确认以上配置并继续安装? (y/N): ")
confirmInput, _ := reader.ReadString('\n')
confirm := strings.ToLower(strings.TrimSpace(confirmInput))
if confirm != "y" && confirm != "yes" {
log.Println("❌ 已取消注册")
return
}
log.Println()
log.Println("🔧 开始配置...")
// 5. 创建配置
if configPath == "" {
configPath = config.GetDefaultConfigPath()
}
cfg := &config.Config{
Path: configPath,
Server: config.ServerConfig{
Endpoint: endpoint,
APIKey: apiKey,
},
Agent: config.AgentConfig{
Name: name,
},
Collector: config.CollectorConfig{
Interval: 5,
HeartbeatInterval: 30,
NetworkExclude: []string{
"^lo$",
"^lo0$",
"^docker.*",
"^veth.*",
"^br-.*",
},
},
AutoUpdate: config.AutoUpdateConfig{
Enabled: true,
CheckInterval: "10m",
},
}
// 6. 保存配置
if err := cfg.Save(configPath); err != nil {
log.Fatalf("❌ 保存配置文件失败: %v", err)
}
log.Printf("✅ 配置文件已保存: %s", configPath)
// 7. 安装为系统服务
log.Println("📦 安装系统服务...")
mgr, err := service.NewServiceManager(cfg)
if err != nil {
log.Fatalf("❌ 创建服务管理器失败: %v", err)
}
if err := mgr.Install(); err != nil {
log.Fatalf("❌ 安装服务失败: %v", err)
}
log.Println("✅ 系统服务安装成功")
// 8. 启动服务
log.Println("🚀 启动服务...")
if err := mgr.Start(); err != nil {
log.Fatalf("❌ 启动服务失败: %v", err)
}
log.Println("✅ 服务启动成功")
log.Println()
log.Println("═══════════════════════════════════════")
log.Println(" 🎉 探针注册完成!")
log.Println("═══════════════════════════════════════")
log.Println()
log.Println("📌 常用命令:")
log.Println(" 查看状态: agent status")
log.Println(" 停止服务: agent stop")
log.Println(" 启动服务: agent start")
log.Println(" 重启服务: agent restart")
log.Println(" 卸载服务: agent uninstall")
log.Println()
}
// maskToken 对 Token 进行部分遮蔽显示
func maskToken(token string) string {
if len(token) <= 8 {
return "****"
}
return token[:4] + "****" + token[len(token)-4:]
}
+7
View File
@@ -0,0 +1,7 @@
package main
import "github.com/dushixiang/pika/internal"
func main() {
internal.Run("./config.yaml")
}