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 缺失项移除
This commit is contained in:
attacker committed 2026-06-23 00:54:54 +08:00
1 parent 8c272a6fa6
commit 4f1ffd1275
27 files changed
+2617 -352

No files matched your search

+44 -2
View File
@@ -61,6 +61,16 @@ func NewPipelineHandler(db *gorm.DB, cache ezredis.Cache) *PipelineHandler {
return &PipelineHandler{db: db, cache: cache}
}
// PipelineListItem 列表项(含最近一次运行摘要)// Logan.Li
type PipelineListItem struct {
models.Pipeline
LastRunStages string `json:"last_run_stages,omitempty"` // JSON: [{name,status}]
LastImageTag string `json:"last_image_tag,omitempty"`
LastCommitID string `json:"last_commit_id,omitempty"`
LastRunDuration int `json:"last_duration,omitempty"`
LastRunBranch string `json:"last_run_branch,omitempty"`
}
// ListPipelines 获取流水线列表
// @Summary 获取流水线列表
// @Description 获取所有流水线列表
@@ -99,9 +109,41 @@ func (h *PipelineHandler) ListPipelines(c *gin.Context) {
var pipelines []models.Pipeline
db.Preload("Environment").Offset(query.GetOffset()).Limit(query.GetLimit()).Order("updated_at DESC").Find(&pipelines)
// 批量获取每个流水线最近一次运行的摘要(阶段状态 + 镜像 + 耗时)// Logan.Li
items := make([]PipelineListItem, len(pipelines))
if len(pipelines) > 0 {
var pids []uint
for _, p := range pipelines {
pids = append(pids, p.ID)
}
// 子查询:每个 pipeline_id 的最新 run id
var latestRuns []models.PipelineRun
h.db.Where("id IN (SELECT MAX(id) FROM ops_pipeline_runs WHERE pipeline_id IN ? AND status IN ('success','failed','running','pending') GROUP BY pipeline_id)", pids).
Find(&latestRuns)
runMap := map[uint]*models.PipelineRun{}
for i := range latestRuns {
runMap[latestRuns[i].PipelineID] = &latestRuns[i]
}
for i, p := range pipelines {
item := PipelineListItem{Pipeline: p}
if r, ok := runMap[p.ID]; ok {
item.LastRunStages = r.Stages
item.LastImageTag = r.ImageTag
item.LastCommitID = r.CommitID
item.LastRunDuration = r.Duration
item.LastRunBranch = r.Branch
}
items[i] = item
}
} else {
for i, p := range pipelines {
items[i] = PipelineListItem{Pipeline: p}
}
}
c.JSON(http.StatusOK, models.Response{
Code: 200,
Data: models.ListResponse{List: pipelines, Total: total},
Data: models.ListResponse{List: items, Total: total},
})
}
@@ -122,7 +164,7 @@ func (h *PipelineHandler) GetPipeline(c *gin.Context) {
}
var pipeline models.Pipeline
if err := h.db.First(&pipeline, id).Error; err != nil {
if err := h.db.Preload("Environment").First(&pipeline, id).Error; err != nil {
c.JSON(http.StatusNotFound, models.Response{
Code: 404,
Message: "流水线不存在",