155 lines
4.4 KiB
Go
155 lines
4.4 KiB
Go
package controller
|
|
|
|
import (
|
|
"time"
|
|
|
|
"ezops/model"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func (h *KubernetesHandler) GetMultiClusterComparison(c *gin.Context) {
|
|
// 1. 获取所有集群
|
|
var clusters []model.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 k8s_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 []model.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, model.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
|