Files
aiops/backend/internal/api/routes/routes.go
T
attacker 4f1ffd1275 feat(k8s): M2 Pod Metrics 详情页接入 — ListPods 注入 metrics
后端:
- 新增 buildPodMetricsMap() 公共辅助函数,聚合多容器 CPU/Memory
- ListPods / listPodsWithNS / ListPodsAllNS 三个 handler 全部注入
- PodSummary 增加 cpu_usage_m / mem_usage_mi 字段

前端:
- KubernetesWorkloads Pod 表格增加 CPU/内存列
- NamespaceResourcePage Pod 表格增加 CPU/内存列

验证:
- 17 个 Pod 全部返回真实 metrics (argocd/demo-jar)
- curl /kubernetes-clusters/1/pods → cpu_usage_m='2m' mem_usage_mi='61Mi'

文档:
- ROADMAP M1→done, M2→done, 验收标准全部勾选
- TDD_PLAN M2 通过标准补充
- PROJECT_EVALUATION P0 缺失项移除
2026-06-23 00:54:54 +08:00

782 lines
34 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package routes
import (
"ezops/internal/api/handlers"
"ezops/internal/api/middleware"
"ezops/internal/config"
ezredis "ezops/pkg/redis"
"ezops/pkg/toolinstaller"
"fmt"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"gorm.io/gorm"
"time"
)
// Register 注册所有路由 // Logan.Li
// cache 参数为可选 Redis 缓存实例(支持 redka/redis 双后端)
func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, cache interface{}) {
// 提取 Redis 缓存实例(供流水线 WebSocket 等使用)
redisCache, _ := cache.(ezredis.Cache)
// API版本前缀
api := r.Group("/api/v1")
// 健康检查
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// Agent 二进制下载 + 一键安装脚本(无需鉴权,方便 curl|bash)
r.Static("/agent/bin", "./agent/bin")
r.StaticFile("/agent/install.sh", "./agent/deploy/install.sh")
r.StaticFile("/agent/aiops-agent-linux-amd64", "./agent/bin/aiops-agent-linux-amd64")
r.StaticFile("/agent/aiops-agent-linux-arm64", "./agent/bin/aiops-agent-linux-arm64")
r.StaticFile("/agent/aiops-agent-darwin-arm64", "./agent/bin/aiops-agent-darwin-arm64") // macOS Apple Silicon // Logan.Li
r.GET("/agent/arch", func(c *gin.Context) {
// 动态构建安装命令 URL(根据请求来源,兼容 nginx 反代)
scheme := "http"
if c.Request.TLS != nil {
scheme = "https"
}
if proto := c.GetHeader("X-Forwarded-Proto"); proto != "" {
scheme = proto
}
host := c.Request.Host
if host == "" {
host = "localhost:8080"
}
base := fmt.Sprintf("%s://%s", scheme, host)
c.JSON(200, gin.H{
"version": "1.0.0",
"downloads": gin.H{
"linux-amd64": "/agent/aiops-agent-linux-amd64",
"linux-arm64": "/agent/aiops-agent-linux-arm64",
"darwin-arm64": "/agent/aiops-agent-darwin-arm64",
},
"install": fmt.Sprintf("curl -fsSL %s/agent/install.sh | sudo bash -s -- --server %s --token <token>", base, base),
})
})
// WebSocket终端 (JWT 鉴权,支持 ?token= 查询参数;终端会话录制) // Logan.Li
webShellHandler := handlers.NewWebShellHandler(db)
r.GET("/ws/terminal", middleware.JWTAuth(&cfg.JWT), webShellHandler.Terminal)
// WebSocket 实时指标推送(JWT 鉴权) // Logan.Li
metricsHub := handlers.NewMetricsHub()
metricsWSHandler := handlers.NewMetricsWSHandler(metricsHub)
r.GET("/ws/metrics", middleware.JWTAuth(&cfg.JWT), metricsWSHandler.ServeWS)
// WebSocket 流水线日志推流
wsLogHandler := handlers.NewWSPipelineLogHandler(db, redisCache)
r.GET("/ws/pipeline/:runId/log", wsLogHandler.StreamLog)
r.GET("/api/v1/pipelines/runs/:runId/log-stream", wsLogHandler.GetLogHistory)
// 工作区文件浏览器(浏览/下载流水线构建目录文件)
workspaceFilesHandler := handlers.NewWorkspaceFilesHandler(db)
r.GET("/api/v1/pipelines/runs/:runId/files", workspaceFilesHandler.ListFiles)
r.GET("/api/v1/pipelines/runs/:runId/files/download", workspaceFilesHandler.DownloadFile)
// WebSocket K8s exec 交互终端 // Logan.Li
k8sHandler := handlers.NewKubernetesHandler(db)
r.GET("/ws/kubernetes-exec/:id/namespaces/:namespace/pods/:podName", middleware.JWTAuth(&cfg.JWT), k8sHandler.ExecTerminal)
// ToolInstaller(工具懒加载服务 — kubectl/maven/node/helm)// Logan.Li
ti := toolinstaller.New(db)
// WebSocket kubectl 命令行终端 // Logan.Li
kubectlShellHandler := handlers.NewKubectlShellHandler(db, ti)
r.GET("/ws/kubectl", middleware.JWTAuth(&cfg.JWT), kubectlShellHandler.Terminal)
// 公开路由
authHandler := handlers.NewUserHandler(db, cfg)
api.POST("/auth/login", authHandler.Login)
api.POST("/auth/register", authHandler.Register)
// Webhook 触发路由(无需 JWT,由 Webhook Token 签名验证)
pipelineHandler := handlers.NewPipelineHandler(db, redisCache)
webhookGroup := api.Group("/webhook")
{
webhookGroup.POST("/job/:jobName", pipelineHandler.WebhookTrigger)
webhookGroup.POST("/pipeline/:code", pipelineHandler.WebhookTrigger)
}
// Agent 安装处理器(在 servers 和 agent 路由中共享)
agentInstallHandler := handlers.NewAgentInstallHandler(db)
// 需要认证的路由
authorized := api.Group("")
authorized.Use(middleware.JWTAuth(&cfg.JWT))
// 用户路由
user := authorized.Group("/user")
{
user.GET("/profile", authHandler.GetProfile)
user.PUT("/profile", authHandler.UpdateProfile)
user.POST("/change-password", authHandler.ChangePassword)
user.GET("/roles", authHandler.ListRoles)
}
// 管理员路由
admin := authorized.Group("/admin")
admin.Use(middleware.AdminAuth())
{
admin.GET("/users", authHandler.ListUsers)
admin.GET("/users/:id", authHandler.GetUser)
admin.POST("/users", authHandler.CreateUser)
admin.PUT("/users/:id", authHandler.UpdateUser)
admin.DELETE("/users/:id", authHandler.DeleteUser)
admin.POST("/users/batch-import", authHandler.BatchImportUsers)
admin.GET("/users/import-template", authHandler.ImportTemplate)
// 角色管理路由 // Logan.Li
admin.GET("/roles", authHandler.ListRoles)
admin.POST("/roles", authHandler.CreateRole)
admin.PUT("/roles/:id", authHandler.UpdateRole)
admin.DELETE("/roles/:id", authHandler.DeleteRole)
// 权限列表(供角色权限选择)
admin.GET("/permissions", authHandler.ListPermissions)
// Item Role 管理(Jenkins-style regex pipeline matching) // Logan.Li
itemRoleHandler := handlers.NewItemRoleHandler(db)
admin.GET("/item-roles", itemRoleHandler.ListItemRoles)
admin.POST("/item-roles", itemRoleHandler.CreateItemRole)
admin.PUT("/item-roles/:id", itemRoleHandler.UpdateItemRole)
admin.DELETE("/item-roles/:id", itemRoleHandler.DeleteItemRole)
admin.GET("/users/:id/item-roles", itemRoleHandler.ListUserItemRoles)
admin.POST("/users/:id/item-roles", itemRoleHandler.AssignItemRole)
admin.DELETE("/users/:id/item-roles/:roleId", itemRoleHandler.RemoveItemRole)
}
// LDAP 配置路由
ldapHandler := handlers.NewLDAPHandler(db)
ldapGroup := authorized.Group("/admin/ldap-config")
ldapGroup.Use(middleware.AdminAuth())
{
ldapGroup.GET("", ldapHandler.GetLDAPConfig)
ldapGroup.PUT("", ldapHandler.UpdateLDAPConfig)
ldapGroup.POST("/test", ldapHandler.TestLDAPConnection)
ldapGroup.POST("/users", ldapHandler.ListLDAPUsers)
ldapGroup.POST("/import", ldapHandler.BatchImportLDAP)
ldapGroup.POST("/ou-list", ldapHandler.ListLDAPOUs)
ldapGroup.POST("/create-ou", ldapHandler.CreateLDAPOU)
ldapGroup.POST("/create-user", ldapHandler.CreateLDAPUser)
ldapGroup.POST("/delete-user", ldapHandler.DeleteLDAPUser)
ldapGroup.POST("/update-user", ldapHandler.UpdateLDAPUser)
}
// 仪表盘路由
dashboardHandler := handlers.NewDashboardHandler(db)
dashboard := authorized.Group("/dashboard")
{
dashboard.GET("/stats", dashboardHandler.GetStats)
dashboard.GET("/recent-alerts", dashboardHandler.GetRecentAlerts)
dashboard.GET("/recent-releases", dashboardHandler.GetRecentReleases)
dashboard.GET("/metrics", dashboardHandler.GetMetrics)
}
// 服务器路由
serverHandler := handlers.NewServerHandler(db, cfg.JWT.Secret)
servers := authorized.Group("/servers")
{
servers.GET("", serverHandler.ListServers)
servers.GET("/stats", serverHandler.GetServerStats)
servers.GET("/:id", serverHandler.GetServer)
servers.POST("", serverHandler.CreateServer)
servers.PUT("/:id", serverHandler.UpdateServer)
servers.DELETE("/:id", serverHandler.DeleteServer)
servers.POST("/batch-delete", serverHandler.BatchDeleteServers)
servers.POST("/batch", serverHandler.BatchCreateServers)
// Agent 远程安装 // Logan.Li
servers.POST("/:id/install-agent", agentInstallHandler.InstallAgent)
servers.POST("/install-agent", agentInstallHandler.BatchInstallAgent)
}
// 云账号路由
cloudAccountHandler := handlers.NewCloudAccountHandler(db)
cloudAccounts := authorized.Group("/cloud-accounts")
{
cloudAccounts.GET("", cloudAccountHandler.ListCloudAccounts)
cloudAccounts.POST("", cloudAccountHandler.CreateCloudAccount)
cloudAccounts.PUT("/:id", cloudAccountHandler.UpdateCloudAccount)
cloudAccounts.DELETE("/:id", cloudAccountHandler.DeleteCloudAccount)
// 云同步路由 — 区域同步 / 主机发现 / 导入主机 // Logan.Li
syncHandler := handlers.NewCloudSyncHandler(db)
cloudAccounts.POST("/:id/sync-regions", syncHandler.SyncRegions)
cloudAccounts.GET("/:id/regions", syncHandler.GetAccountRegions)
cloudAccounts.POST("/:id/discover-instances", syncHandler.DiscoverInstances)
cloudAccounts.POST("/:id/import-instances", syncHandler.ImportInstances)
}
// 域名路由
domainHandler := handlers.NewDomainHandler(db)
domains := authorized.Group("/domains")
{
domains.GET("", domainHandler.ListDomains)
domains.POST("", domainHandler.CreateDomain)
domains.PUT("/:id", domainHandler.UpdateDomain)
domains.DELETE("/:id", domainHandler.DeleteDomain)
}
// 云平台路由
platformHandler := handlers.NewPlatformHandler(db)
platforms := authorized.Group("/platforms")
{
platforms.GET("", platformHandler.ListPlatforms)
platforms.POST("", platformHandler.CreatePlatform)
platforms.PUT("/:id", platformHandler.UpdatePlatform)
platforms.DELETE("/:id", platformHandler.DeletePlatform)
}
// 区域路由
regionHandler := handlers.NewRegionHandler(db)
regions := authorized.Group("/regions")
{
regions.GET("", regionHandler.ListRegions)
regions.POST("", regionHandler.CreateRegion)
regions.PUT("/:id", regionHandler.UpdateRegion)
regions.DELETE("/batch-delete", regionHandler.BatchDeleteRegions) // Logan.Li
regions.DELETE("/:id", regionHandler.DeleteRegion)
}
// 云账单路由
billingHandler := handlers.NewBillingHandler(db)
billings := authorized.Group("/cloud-billings")
{
billings.GET("", billingHandler.ListBillings)
billings.POST("", billingHandler.CreateBilling)
billings.POST("/batch", billingHandler.BatchCreateBillings)
billings.DELETE("/:id", billingHandler.DeleteBilling)
billings.GET("/stats", billingHandler.GetBillingStats)
billings.GET("/providers", billingHandler.GetProviderOptions)
}
billingAlerts := authorized.Group("/billing-alerts")
{
billingAlerts.GET("", billingHandler.ListAlertRules)
billingAlerts.POST("", billingHandler.CreateAlertRule)
billingAlerts.PUT("/:id", billingHandler.UpdateAlertRule)
billingAlerts.DELETE("/:id", billingHandler.DeleteAlertRule)
billingAlerts.POST("/:id/toggle", billingHandler.ToggleAlertRule)
}
// 资源模型路由
resourceModelHandler := handlers.NewResourceModelHandler(db)
resourceModels := authorized.Group("/resource-models")
{
resourceModels.GET("", resourceModelHandler.ListResourceModels)
resourceModels.POST("", resourceModelHandler.CreateResourceModel)
resourceModels.PUT("/:id", resourceModelHandler.UpdateResourceModel)
resourceModels.DELETE("/:id", resourceModelHandler.DeleteResourceModel)
}
// K8s集群路由
clusters := authorized.Group("/kubernetes-clusters")
{
clusters.GET("", k8sHandler.ListClusters)
clusters.GET("/:id", k8sHandler.GetCluster)
clusters.GET("/:id/detail", k8sHandler.GetClusterDetail) // 编辑用详情(含 has_token 标记) // Logan.Li
clusters.POST("", k8sHandler.CreateCluster)
clusters.PUT("/:id", k8sHandler.UpdateCluster)
clusters.DELETE("/:id", k8sHandler.DeleteCluster)
clusters.POST("/:id/sync", k8sHandler.SyncCluster) // 同步集群资源 // Logan.Li
clusters.GET("/:id/nodes", k8sHandler.ListNodes)
clusters.GET("/:id/pods", k8sHandler.ListPods)
clusters.GET("/:id/deployments", k8sHandler.ListDeployments)
clusters.GET("/:id/services", k8sHandler.ListServices)
clusters.GET("/:id/ingresses", k8sHandler.ListIngresses)
clusters.GET("/:id/topology", k8sHandler.GetTopology) // 获取拓扑布局 // Logan.Li
clusters.PUT("/:id/topology", k8sHandler.SaveTopology) // 保存拓扑布局 // Logan.Li
// Pod 日志 // Logan.Li
clusters.GET("/:id/namespaces/:namespace/pods/:podName/logs", k8sHandler.GetPodLogs)
// Pod 终端 exec (命令执行 / 文件浏览) // Logan.Li
clusters.POST("/:id/namespaces/:namespace/pods/:podName/exec", k8sHandler.ExecInPod)
// Deployment 扩缩容 & 重启 // Logan.Li
clusters.POST("/:id/namespaces/:namespace/deployments/:name/scale", k8sHandler.ScaleDeployment)
clusters.POST("/:id/namespaces/:namespace/deployments/:name/restart", k8sHandler.RestartDeployment)
// Deployment CI 集成 (Webhook 更新镜像) // Logan.Li
clusters.POST("/:id/namespaces/:namespace/deployments/:name/update-image", k8sHandler.UpdateDeploymentImage)
// HPA 管理 // Logan.Li
clusters.GET("/:id/hpas", k8sHandler.ListHPAs)
clusters.POST("/:id/hpas", k8sHandler.CreateHPA)
clusters.DELETE("/:id/namespaces/:namespace/hpas/:name", k8sHandler.DeleteHPA)
// CronJob 管理 // Logan.Li
clusters.GET("/:id/cronjobs", k8sHandler.ListCronJobs)
clusters.POST("/:id/cronjobs", k8sHandler.CreateCronJob)
clusters.POST("/:id/namespaces/:namespace/cronjobs/:name/suspend", k8sHandler.SuspendCronJob)
clusters.POST("/:id/namespaces/:namespace/cronjobs/:name/trigger", k8sHandler.TriggerCronJob)
clusters.DELETE("/:id/namespaces/:namespace/cronjobs/:name", k8sHandler.DeleteCronJob)
// ReplicaSet 列表 / Deployment 回滚 / 历史版本 // Logan.Li
clusters.GET("/:id/namespaces/:namespace/replicasets", k8sHandler.ListReplicaSetsNS)
clusters.GET("/:id/namespaces/:namespace/deployments/:name/revisions", k8sHandler.ListDeploymentRevisionsNS)
clusters.POST("/:id/namespaces/:namespace/deployments/:name/rollback", k8sHandler.RollbackDeploymentNS)
// Pod 文件浏览 / 下载 / 删除 // Logan.Li
clusters.POST("/:id/namespaces/:namespace/pods/:podName/files/list", k8sHandler.ListPodFilesNS)
clusters.GET("/:id/namespaces/:namespace/pods/:podName/files/download", k8sHandler.DownloadPodFileNS)
clusters.DELETE("/:id/namespaces/:namespace/pods/:podName", k8sHandler.DeletePodNS)
// Namespace // Logan.Li
clusters.GET("/:id/namespaces", k8sHandler.ListNamespaces)
}
// ============================================================================
// Kuboard-style namespace-scoped routes (/kubernetes/{clusterCode}/namespace/{ns}/...)
// ============================================================================
kubernetesRouter := authorized.Group("/kubernetes")
{
// Namespace overview
kubernetesRouter.GET("/:clusterCode/namespace/:namespace", func(c *gin.Context) {
k8sHandler.ListDeploymentsNS(c)
})
// Deployments
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/deployments", k8sHandler.ListDeploymentsNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/scale", k8sHandler.ScaleDeploymentNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/restart", k8sHandler.RestartDeploymentNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/update-image", k8sHandler.UpdateDeploymentImageNS)
// Pods
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/pods", k8sHandler.ListPodsNS)
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/pods/:podName/logs", k8sHandler.GetPodLogsNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/pods/:podName/exec", k8sHandler.ExecInPodNS)
// Services
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/services", k8sHandler.ListServicesNS)
// Ingresses
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/ingresses", k8sHandler.ListIngressesNS)
// HPA
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/hpas", k8sHandler.ListHPAsNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/hpas", k8sHandler.CreateHPANS)
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/hpas/:name", k8sHandler.DeleteHPANS)
// CronJob
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/cronjobs", k8sHandler.ListCronJobsNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/cronjobs", k8sHandler.CreateCronJobNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/cronjobs/:name/suspend", k8sHandler.SuspendCronJobNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/cronjobs/:name/trigger", k8sHandler.TriggerCronJobNS)
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/cronjobs/:name", k8sHandler.DeleteCronJobNS)
// 🆕 ReplicaSet 列表 // Logan.Li
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/replicasets", k8sHandler.ListReplicaSetsNS)
// 🆕 Deployment 回滚 / 发布历史 // Logan.Li
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/deployments/:name/revisions", k8sHandler.ListDeploymentRevisionsNS)
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/deployments/:name/rollback", k8sHandler.RollbackDeploymentNS)
// 🆕 Pod 文件浏览 / 下载 / 删除 // Logan.Li
kubernetesRouter.POST("/:clusterCode/namespace/:namespace/pods/:podName/files/list", k8sHandler.ListPodFilesNS)
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/pods/:podName/files/download", k8sHandler.DownloadPodFileNS)
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/pods/:podName", k8sHandler.DeletePodNS)
// ConfigMap / Secret
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/configmaps", k8sHandler.ListConfigMaps)
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/secrets", k8sHandler.ListSecrets)
// Namespace list
kubernetesRouter.GET("/:clusterCode/namespaces", k8sHandler.ListNamespaces)
// All-namespace listing (no ns filter)
kubernetesRouter.GET("/:clusterCode/deployments", k8sHandler.ListDeploymentsAllNS)
kubernetesRouter.GET("/:clusterCode/pods", k8sHandler.ListPodsAllNS)
kubernetesRouter.GET("/:clusterCode/hpas", k8sHandler.ListHPAsAllNS)
// 🆕 Pod Metrics (kubectl top pods)
kubernetesRouter.GET("/:clusterCode/metrics/pods", k8sHandler.GetPodMetrics)
// 🆕 Events
kubernetesRouter.GET("/:clusterCode/events", k8sHandler.ListEvents)
// 🆕 Capacity Analysis
kubernetesRouter.GET("/:clusterCode/capacity", k8sHandler.GetCapacityAnalysis)
// 🆕 YAML Apply
kubernetesRouter.POST("/:clusterCode/yaml/apply", k8sHandler.ApplyYAML)
// PVC (存储)
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/pvcs", k8sHandler.ListPVCsNS)
kubernetesRouter.DELETE("/:clusterCode/namespace/:namespace/pvcs/:name", k8sHandler.DeletePVCNS)
// StatefulSet / DaemonSet
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/statefulsets", k8sHandler.ListStatefulSetsNS)
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/daemonsets", k8sHandler.ListDaemonSetsNS)
// YAML view/edit
kubernetesRouter.GET("/:clusterCode/namespace/:namespace/:resource/:name/yaml", k8sHandler.GetResourceYAMLNS)
kubernetesRouter.PUT("/:clusterCode/namespace/:namespace/:resource/:name/yaml", k8sHandler.UpdateResourceYAMLNS)
}
// 告警路由
alertHandler := handlers.NewAlertHandler(db)
alerts := authorized.Group("/alerts")
{
alerts.GET("", alertHandler.ListAlerts)
alerts.GET("/rules", alertHandler.ListRules)
alerts.POST("/rules", alertHandler.CreateRule)
alerts.PUT("/rules/:id", alertHandler.UpdateRule)
alerts.DELETE("/rules/batch-delete", alertHandler.BatchDeleteRules)
alerts.DELETE("/rules/:id", alertHandler.DeleteRule)
alerts.POST("/rules/:id/toggle", alertHandler.ToggleRule)
alerts.POST("/:id/ack", alertHandler.AcknowledgeAlert)
alerts.GET("/notify-channels", alertHandler.ListNotifyChannels)
alerts.POST("/notify-channels", alertHandler.CreateNotifyChannel)
alerts.PUT("/notify-channels/:id", alertHandler.UpdateNotifyChannel)
alerts.DELETE("/notify-channels/:id", alertHandler.DeleteNotifyChannel)
alerts.POST("/notify-channels/:id/test", alertHandler.TestNotifyChannel)
}
// 流水线路由
pipelines := authorized.Group("/pipelines")
{
pipelines.GET("", pipelineHandler.ListPipelines)
pipelines.POST("", pipelineHandler.CreatePipeline)
// 需要流水线权限的路由
pipelineScoped := pipelines.Group("/:code")
pipelineScoped.Use(middleware.PipelineAccess(db))
{
pipelineScoped.GET("", pipelineHandler.GetPipeline)
pipelineScoped.PUT("", pipelineHandler.UpdatePipeline)
pipelineScoped.DELETE("", pipelineHandler.DeletePipeline)
pipelineScoped.POST("/trigger", pipelineHandler.TriggerPipeline)
pipelineScoped.GET("/runs", pipelineHandler.ListRuns)
pipelineScoped.POST("/runs/:runId/stop", pipelineHandler.StopPipelineRun)
pipelineScoped.POST("/runs/batch-delete", pipelineHandler.BatchDeleteRuns)
pipelineScoped.GET("/runs/:runId/log", pipelineHandler.GetRunLog)
// 成员管理
pipelineScoped.GET("/members", pipelineHandler.ListPipelineMembers)
pipelineScoped.POST("/members", pipelineHandler.AddPipelineMember)
pipelineScoped.DELETE("/members/:memberId", pipelineHandler.RemovePipelineMember)
// 组授权
pipelineScoped.POST("/groups", pipelineHandler.AssignGroupToPipeline)
}
}
// 用户组管理路由
groups := authorized.Group("/deploy/groups")
{
groups.GET("", pipelineHandler.ListGroups)
groups.POST("", pipelineHandler.CreateGroup)
groups.PUT("/:id", pipelineHandler.UpdateGroup)
groups.DELETE("/:id", pipelineHandler.DeleteGroup)
groups.GET("/:id/members", pipelineHandler.ListGroupMembers)
groups.POST("/:id/members", pipelineHandler.AddGroupMember)
groups.DELETE("/:id/members/:memberId", pipelineHandler.RemoveGroupMember)
}
// 环境管理路由
environments := authorized.Group("/deploy/environments")
{
environments.GET("", pipelineHandler.ListEnvironments)
environments.POST("", pipelineHandler.CreateEnvironment)
environments.PUT("/:id", pipelineHandler.UpdateEnvironment)
environments.DELETE("/:id", pipelineHandler.DeleteEnvironment)
}
// 应用发布路由
releases := authorized.Group("/releases")
{
releases.GET("", pipelineHandler.ListReleases)
releases.POST("", pipelineHandler.CreateRelease)
releases.POST("/:id/approve", pipelineHandler.ApproveRelease)
releases.POST("/:id/reject", pipelineHandler.RejectRelease) // 驳回发布 // Logan.Li
releases.POST("/:id/deploy", pipelineHandler.DeployRelease)
releases.POST("/:id/rollback", pipelineHandler.RollbackRelease)
}
// 仓库认证 & 镜像仓库认证路由
deployHandler := handlers.NewDeployHandler(db)
{
repos := authorized.Group("/deploy/repos")
repos.GET("", deployHandler.ListRepos)
repos.POST("", deployHandler.CreateRepo)
repos.GET("/:id", deployHandler.GetRepo)
repos.PUT("/:id", deployHandler.UpdateRepo)
repos.DELETE("/:id", deployHandler.DeleteRepo)
registries := authorized.Group("/deploy/registries")
registries.GET("", deployHandler.ListRegistries)
registries.POST("", deployHandler.CreateRegistry)
registries.GET("/:id", deployHandler.GetRegistry)
registries.PUT("/:id", deployHandler.UpdateRegistry)
registries.DELETE("/:id", deployHandler.DeleteRegistry)
}
// 工具配置路由(发布配置 Tab ④)// Logan.Li
toolConfigHandler := handlers.NewToolConfigHandler(db)
tools := authorized.Group("/deploy/tools")
{
tools.GET("", toolConfigHandler.ListTools)
tools.GET("/:id", toolConfigHandler.GetTool)
tools.PUT("/:id", toolConfigHandler.UpdateTool)
tools.POST("/:id/install", toolConfigHandler.InstallTool)
tools.POST("/:id/check", toolConfigHandler.CheckToolStatus)
}
// 自动化运维路由
automationHandler := handlers.NewAutomationHandler(db)
cronJobs := authorized.Group("/cron-jobs")
{
cronJobs.GET("", automationHandler.ListCronJobs)
cronJobs.POST("", automationHandler.CreateCronJob)
cronJobs.GET("/:id", automationHandler.GetCronJob)
cronJobs.PUT("/:id", automationHandler.UpdateCronJob)
cronJobs.DELETE("/batch-delete", automationHandler.BatchDeleteCronJobs)
cronJobs.DELETE("/:id", automationHandler.DeleteCronJob)
cronJobs.POST("/:id/toggle", automationHandler.ToggleCronJob)
cronJobs.POST("/:id/execute", automationHandler.ExecuteCronJob)
}
scripts := authorized.Group("/scripts")
{
scripts.GET("", automationHandler.ListScripts)
scripts.POST("", automationHandler.CreateScript)
scripts.GET("/:id", automationHandler.GetScript)
scripts.PUT("/:id", automationHandler.UpdateScript)
scripts.POST("/batch-delete", automationHandler.BatchDeleteScripts)
scripts.DELETE("/:id", automationHandler.DeleteScript)
scripts.POST("/:id/execute", automationHandler.ExecuteScript)
}
// 远程执行路由 — Go 原生 SSH 批量执行替代 Ansible // Logan.Li
remoteExecHandler := handlers.NewRemoteExecHandler(db)
remoteExec := authorized.Group("/remote-exec")
{
remoteExec.POST("/execute", remoteExecHandler.BatchExec)
remoteExec.POST("/upload", remoteExecHandler.BatchUpload)
remoteExec.GET("/hosts", remoteExecHandler.MatchHosts)
remoteExec.POST("/server/:id/exec", remoteExecHandler.ExecOnServer)
}
// 任务执行记录(脚本/定时任务执行历史,不含 Ansible)
authorized.GET("/task-executions", automationHandler.ListExecutions)
// 日志监控路由 // Logan.Li
logHandler := handlers.NewLogHandler(db)
logs := authorized.Group("/logs")
{
logs.GET("", logHandler.QueryLogs)
logs.GET("/sources", logHandler.ListSources)
logs.POST("/sources", logHandler.CreateSource)
logs.DELETE("/sources/:id", logHandler.DeleteSource)
}
// 审批流程路由
approvalHandler := handlers.NewApprovalHandler(db)
approvals := authorized.Group("/approvals")
{
approvals.GET("/templates", approvalHandler.ListTemplates)
approvals.POST("/templates", approvalHandler.CreateTemplate)
approvals.GET("/templates/:id", approvalHandler.GetTemplate)
approvals.PUT("/templates/:id", approvalHandler.UpdateTemplate)
approvals.DELETE("/templates/:id", approvalHandler.DeleteTemplate)
approvals.GET("/processes", approvalHandler.ListProcesses)
approvals.POST("/processes", approvalHandler.CreateProcess)
approvals.GET("/processes/:id", approvalHandler.GetProcess)
approvals.POST("/processes/:id/approve", approvalHandler.ApproveProcess)
approvals.POST("/processes/:id/reject", approvalHandler.RejectProcess)
}
// 导航路由
navHandler := handlers.NewNavigationHandler(db)
navigations := authorized.Group("/navigations")
{
navigations.GET("/groups", navHandler.ListGroups)
navigations.POST("/groups", navHandler.CreateGroup)
navigations.PUT("/groups/:id", navHandler.UpdateGroup)
navigations.DELETE("/groups/:id", navHandler.DeleteGroup)
navigations.GET("/links", navHandler.ListLinks)
navigations.POST("/links", navHandler.CreateLink)
navigations.PUT("/links/:id", navHandler.UpdateLink)
navigations.DELETE("/links/:id", navHandler.DeleteLink)
navigations.POST("/links/:id/favorite", navHandler.ToggleFavorite)
}
// 审计日志路由
auditHandler := handlers.NewAuditHandler(db)
audit := authorized.Group("/audit")
{
audit.GET("/logs", auditHandler.ListAuditLogs)
audit.GET("/logs/:id", auditHandler.GetAuditLogDetail)
audit.GET("/modules", auditHandler.GetAuditModules)
audit.GET("/actions", auditHandler.GetAuditActions)
audit.GET("/logs/export", auditHandler.ExportAuditLogs)
audit.GET("/statistics", auditHandler.GetAuditStatistics)
audit.POST("/logs/clear", auditHandler.ClearAuditLogs)
}
// 终端会话审计路由(WebSSH 录制回放) // Logan.Li
terminalSessionHandler := handlers.NewTerminalSessionHandler(db)
ts := authorized.Group("/terminal-sessions")
{
ts.GET("", terminalSessionHandler.ListTerminalSessions)
ts.POST("/batch-delete", terminalSessionHandler.BatchDeleteTerminalSessions)
ts.GET("/:id", terminalSessionHandler.GetTerminalSession)
ts.GET("/:id/record", terminalSessionHandler.GetTerminalRecord)
ts.DELETE("/:id", terminalSessionHandler.DeleteTerminalSession)
}
// Agent 上报路由(无需 JWT)
agentHandler := handlers.NewAgentHandler(db, redisCache, metricsHub)
taskHandler := handlers.NewAgentTaskHandler(db)
agentGroup := api.Group("/agent")
{
agentGroup.POST("/report", agentHandler.ReceiveReport)
agentGroup.GET("/tasks/poll", taskHandler.PollTasks)
agentGroup.POST("/tasks/:task_id/result", taskHandler.SubmitResult)
agentGroup.POST("/aggregate", agentHandler.AggregateMetrics)
agentGroup.POST("/exec", agentInstallHandler.RemoteExec)
}
// Agent 数据查询 + 任务管理(需要 JWT)
agentQuery := authorized.Group("/agent")
{
agentQuery.GET("/latest", agentHandler.GetLatestReports)
agentQuery.GET("/history/:hostname", agentHandler.GetHostHistory)
agentQuery.GET("/aggregate", agentHandler.GetAggregate)
// 远程任务
agentQuery.POST("/tasks", taskHandler.CreateTask)
agentQuery.GET("/tasks", taskHandler.ListTasks)
agentQuery.GET("/tasks/:id", taskHandler.GetTask)
// 告警规则
agentQuery.GET("/rules", taskHandler.ListRules)
agentQuery.POST("/rules/quick-setup", taskHandler.QuickSetupRules)
agentQuery.POST("/rules", taskHandler.CreateRule)
agentQuery.PUT("/rules/:id", taskHandler.UpdateRule)
agentQuery.DELETE("/rules/:id", taskHandler.DeleteRule)
// 告警事件
agentQuery.GET("/alerts", taskHandler.ListAlerts)
agentQuery.POST("/alerts/:id/resolve", taskHandler.ResolveAlert)
// Agent 安装/卸载
agentQuery.POST("/uninstall", agentInstallHandler.UninstallAgent)
agentQuery.POST("/batch-uninstall", agentInstallHandler.BatchUninstallAgent)
agentQuery.POST("/batch-upgrade", agentInstallHandler.BatchUpgradeAgent)
}
// Agent 二进制下载(无需鉴权,Agent 升级时使用)
r.Static("/api/agent/bin", "/app/agent/bin")
// AI 智能助手 - LLM 配置 + 对话代理(OpenAI 兼容) // Logan.Li
llmHandler := handlers.NewLLMHandler(db)
aiopsGroup := authorized.Group("/aiops")
{
aiopsGroup.GET("/llm-config", llmHandler.GetLLMConfig)
aiopsGroup.PUT("/llm-config", llmHandler.SaveLLMConfig)
aiopsGroup.POST("/llm-config/test", llmHandler.TestLLMConnection)
aiopsGroup.POST("/chat", llmHandler.Chat)
aiopsGroup.POST("/chat/stream", llmHandler.ChatStream)
aiopsGroup.GET("/chat-history", llmHandler.GetChatHistory)
aiopsGroup.DELETE("/chat-history", llmHandler.ClearChatHistory)
}
// 指标浏览器 — 监控指标元数据 + 时序查询 // Logan.Li
metricsHandler := handlers.NewMetricsHandler(db)
metricsGroup := authorized.Group("/metrics")
{
metricsGroup.GET("/targets", metricsHandler.ListTargets)
metricsGroup.GET("/list", metricsHandler.ListMetrics)
metricsGroup.GET("/query", metricsHandler.QueryValues)
metricsGroup.GET("/names", metricsHandler.ListMetricNames)
metricsGroup.GET("/top", metricsHandler.TopHosts)
}
// SNMP 设备管理 — 网络设备/服务器硬件 // Logan.Li
snmpHandler := handlers.NewSNMPHandler(db)
snmpGroup := authorized.Group("/snmp")
{
snmpGroup.GET("/devices", snmpHandler.ListDevices)
snmpGroup.POST("/devices", snmpHandler.CreateDevice)
snmpGroup.PUT("/devices/:id", snmpHandler.UpdateDevice)
snmpGroup.DELETE("/devices/:id", snmpHandler.DeleteDevice)
snmpGroup.DELETE("/devices/batch-delete", snmpHandler.BatchDeleteDevices)
snmpGroup.GET("/templates", snmpHandler.ListTemplates)
snmpGroup.POST("/templates", snmpHandler.CreateTemplate)
snmpGroup.GET("/stats", snmpHandler.GetSNMPStats)
}
// Zabbix 代理 — 镜像 Zabbix API 为前端面板可用格式 // Logan.Li
zabbixHandler := handlers.NewZabbixProxyHandler()
zabbixGroup := authorized.Group("/zabbix")
{
zabbixGroup.POST("/connect", zabbixHandler.Connect)
zabbixGroup.GET("/host/:hostid", zabbixHandler.GetHostDetail)
}
// Prometheus 代理 — 转发 PromQL 查询到 Prometheus 服务器 // Logan.Li
promHandler := handlers.NewPrometheusProxyHandler()
promGroup := authorized.Group("/prometheus")
{
promGroup.POST("/connect", promHandler.Connect)
promGroup.POST("/query", promHandler.Query)
promGroup.POST("/query_range", promHandler.QueryRange)
promGroup.POST("/dashboard", promHandler.Dashboard)
}
// Prometheus 数据源管理 — CRUD + 连接测试 // Logan.Li
promDSHandler := handlers.NewPromDSHandler(db)
promDSGroup := authorized.Group("/prometheus-datasources")
{
promDSGroup.GET("", promDSHandler.List)
promDSGroup.GET("/:id", promDSHandler.Get)
promDSGroup.POST("", promDSHandler.Create)
promDSGroup.PUT("/:id", promDSHandler.Update)
promDSGroup.DELETE("/:id", promDSHandler.Delete)
promDSGroup.POST("/:id/default", promDSHandler.SetDefault)
promDSGroup.POST("/test", promDSHandler.TestConnection)
}
// Zabbix 数据源管理 — CRUD + 连接测试 // Logan.Li
zabbixDSHandler := handlers.NewZabbixDSHandler(db)
zabbixDSGroup := authorized.Group("/zabbix-datasources")
{
zabbixDSGroup.GET("", zabbixDSHandler.List)
zabbixDSGroup.GET("/:id", zabbixDSHandler.Get)
zabbixDSGroup.POST("", zabbixDSHandler.Create)
zabbixDSGroup.PUT("/:id", zabbixDSHandler.Update)
zabbixDSGroup.DELETE("/:id", zabbixDSHandler.Delete)
zabbixDSGroup.POST("/:id/default", zabbixDSHandler.SetDefault)
zabbixDSGroup.POST("/test", zabbixDSHandler.TestConnection)
}
// 凭据管理 — SSH密钥/API Token/密码统一加密管理 // Logan.Li
credentialHandler := handlers.NewCredentialHandler(db, cfg.JWT.Secret)
credGroup := authorized.Group("/credentials")
{
credGroup.GET("", credentialHandler.ListCredentials)
credGroup.GET("/tags", credentialHandler.GetTags)
credGroup.POST("", credentialHandler.CreateCredential)
credGroup.GET("/:id", credentialHandler.GetCredential)
credGroup.PUT("/:id", credentialHandler.UpdateCredential)
credGroup.PATCH("/:id", credentialHandler.PatchCredential)
credGroup.DELETE("/:id", credentialHandler.DeleteCredential)
}
// 服务器凭据关联 // Logan.Li
authorized.POST("/servers/:id/assign-credential", credentialHandler.AssignCredential)
// 站点拨测 — HTTP/TCP/DNS/PING 主动监控 // Logan.Li
siteHandler := handlers.NewSiteHandler(db)
siteGroup := authorized.Group("/site")
{
siteGroup.GET("/tasks", siteHandler.ListTasks)
siteGroup.POST("/tasks", siteHandler.CreateTask)
siteGroup.PUT("/tasks/:id", siteHandler.UpdateTask)
siteGroup.DELETE("/tasks/:id", siteHandler.DeleteTask)
siteGroup.DELETE("/tasks/batch-delete", siteHandler.BatchDeleteTasks)
siteGroup.GET("/results", siteHandler.ListResults)
siteGroup.GET("/stats", siteHandler.GetSiteStats)
}
// 启动告警引擎(每 30 秒检查一次)
alertEngine := handlers.NewAlertEngine(db)
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
alertEngine.Check()
}
}()
}