Files
aiops/backend/internal/api/handlers/k8s_compare.go
T
attacker 4dd5e10b46 refactor(k8s): Q2 kubernetes.go 模块化拆分 — 4204行单文件→12个域文件
将 handlers/kubernetes.go (4204行/134函数) 按业务域拆分为:
- kubernetes.go (106L): struct + constructor + 共享helpers
- k8s_cluster.go (642L): 集群CRUD + 同步 + RBAC
- k8s_workload.go (696L): Deployment/STS/DS/ReplicaSet操作
- k8s_pod.go (653L): Pod日志/终端/exec/指标
- k8s_pod_files.go (206L): Pod文件浏览/上传/下载
- k8s_resource.go (351L): Service/Ingress/ConfigMap/Secret/PVC/Topology
- k8s_hpa_cronjob.go (384L): HPA + CronJob
- k8s_yaml.go (213L): YAML get/update/delete/apply
- k8s_namespace.go (305L): Namespace CRUD
- k8s_events.go (207L): 事件列表+聚合
- k8s_node.go (428L): Node详情+资源分配
- k8s_compare.go (146L): 多集群对比

验收: go build零错误, 425条路由不变, 26个K8s API端点回归测试全通过
2026-06-25 04:51:21 +08:00

147 lines
4.4 KiB
Go

package handlers
import (
"time"
"ezops/internal/models"
"github.com/gin-gonic/gin"
)
func (h *KubernetesHandler) GetMultiClusterComparison(c *gin.Context) {
// 1. 获取所有集群
var clusters []models.KubernetesCluster
h.db.Find(&clusters)
type ClusterComparison struct {
ID uint `json:"id"`
Name string `json:"name"`
Code string `json:"code"`
Status string `json:"status"`
Version string `json:"version"`
NodeCount int `json:"node_count"`
PodCount int `json:"pod_count"`
DeploymentCount int `json:"deployment_count"`
ServiceCount int `json:"service_count"`
CPUUsage float64 `json:"cpu_usage"`
MemoryUsage float64 `json:"memory_usage"`
APIServer string `json:"api_server"`
LastSyncAt *time.Time `json:"last_sync_at"`
// Node-level aggregated data from kubernetes_nodes table
TotalCPUCores int `json:"total_cpu_cores"`
TotalMemoryMB int64 `json:"total_memory_mb"`
MasterCount int `json:"master_count"`
WorkerCount int `json:"worker_count"`
HealthyNodes int `json:"healthy_nodes"`
UnhealthyNodes int `json:"unhealthy_nodes"`
}
// 2. 获取所有节点的聚合数据(按 cluster_id 分组)
type NodeAgg struct {
ClusterID uint
NodeCount int
MasterCount int
WorkerCount int
HealthyNodes int
UnhealthyNodes int
TotalCPU int
TotalMemory int64
AvgCPUUsage float64
AvgMemUsage float64
}
nodeAggMap := map[uint]*NodeAgg{}
{
var nodes []models.KubernetesNode
h.db.Find(&nodes)
for _, n := range nodes {
agg, ok := nodeAggMap[n.ClusterID]
if !ok {
agg = &NodeAgg{ClusterID: n.ClusterID}
nodeAggMap[n.ClusterID] = agg
}
agg.NodeCount++
agg.TotalCPU += n.CPU
agg.TotalMemory += n.Memory
if n.CPUUsage > 0 || n.MemoryUsage > 0 {
if agg.AvgCPUUsage == 0 { agg.AvgCPUUsage = n.CPUUsage } else { agg.AvgCPUUsage = (agg.AvgCPUUsage*float64(agg.NodeCount-1) + n.CPUUsage) / float64(agg.NodeCount) }
if agg.AvgMemUsage == 0 { agg.AvgMemUsage = n.MemoryUsage } else { agg.AvgMemUsage = (agg.AvgMemUsage*float64(agg.NodeCount-1) + n.MemoryUsage) / float64(agg.NodeCount) }
}
if n.Role == "master" {
agg.MasterCount++
} else {
agg.WorkerCount++
}
if n.Status == "Ready" {
agg.HealthyNodes++
} else {
agg.UnhealthyNodes++
}
}
}
// 3. 构建对比数据
comparisons := []ClusterComparison{}
totalNodes, totalPods, totalDeployments, totalServices := 0, 0, 0, 0
for _, cl := range clusters {
cc := ClusterComparison{
ID: cl.ID,
Name: cl.Name,
Code: cl.Code,
Status: cl.Status,
Version: cl.Version,
NodeCount: cl.NodeCount,
PodCount: cl.PodCount,
DeploymentCount: cl.DeploymentCount,
ServiceCount: cl.ServiceCount,
CPUUsage: cl.CPUUsage,
MemoryUsage: cl.MemoryUsage,
APIServer: cl.APIServer,
LastSyncAt: cl.LastSyncAt,
}
// 优先用 node 级别的实时聚合数据
if agg, ok := nodeAggMap[cl.ID]; ok && agg.NodeCount > 0 {
cc.TotalCPUCores = agg.TotalCPU
cc.TotalMemoryMB = agg.TotalMemory
cc.MasterCount = agg.MasterCount
cc.WorkerCount = agg.WorkerCount
cc.HealthyNodes = agg.HealthyNodes
cc.UnhealthyNodes = agg.UnhealthyNodes
// 如果集群级别的 cpu_usage 为 0,使用节点平均值
if cc.CPUUsage == 0 && agg.AvgCPUUsage > 0 {
cc.CPUUsage = agg.AvgCPUUsage
}
if cc.MemoryUsage == 0 && agg.AvgMemUsage > 0 {
cc.MemoryUsage = agg.AvgMemUsage
}
}
totalNodes += cc.NodeCount
totalPods += cc.PodCount
totalDeployments += cc.DeploymentCount
totalServices += cc.ServiceCount
comparisons = append(comparisons, cc)
}
// 4. 返回结果
c.JSON(200, models.Response{
Code: 200,
Message: "success",
Data: gin.H{
"clusters": comparisons,
"totals": gin.H{
"cluster_count": len(clusters),
"node_count": totalNodes,
"pod_count": totalPods,
"deployment_count": totalDeployments,
"service_count": totalServices,
},
},
})
}
// ============================================================================
// RBAC — ServiceAccount / Role / RoleBinding (code-based)
// ============================================================================
// ListServiceAccountsNS lists ServiceAccounts in a namespace