Files
aiops/TDD_PLAN.md
T
attacker 7192f58b72 feat(k8s): M12 事件聚合 + 告警联动 — EventsPage 聚合看板
- 后端: 新增 GetEventsSummary handler — 按 Reason/Namespace/Kind 三维度聚合 + 时间窗口过滤
- 后端: 注册 GET /:clusterCode/events/summary 路由
- 前端: EventsPage 完整重写(~480行) — 概览卡片 + 三维度柱状图(recharts) + 图表联动过滤 + 最新告警面板 + 可展开事件行 + 时间窗口选择器
- 前端: api.ts 新增 getEventsSummary 方法
- 验证: API 返回完整聚合数据(total=3, warning_count=613, BackOff top reason), SPA 200, TS零错误, Vite构建成功
2026-06-24 02:50:06 +08:00

436 lines
16 KiB
Markdown
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.
# TDD 验证计划 — K8s 管理功能
> 每个模块实现前先写验证用例,实现后必须跑通,不能只编译通过。
## 通用验证流程
```bash
# 1. 重建后端镜像
cd /srv/aiops && docker-compose up -d --build backend
# 2. 等待 healthy
sleep 10 && docker ps --format '{{.Names}} {{.Status}}' | grep aiops-backend
# 3. 获取 JWT Token
TOKEN=$(curl -s http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"CHANGE_ME"}' | jq -r '.data.token')
# 4. 验证 API
curl -s http://127.0.0.1:8080/api/v1/kubernetes-clusters \
-H "Authorization: Bearer $TOKEN" | jq '.'
```
---
## M1: SyncCluster metrics 采集
### 验证用例
```bash
# U1: 同步前 — 确认 DB 里 cpu_usage 为 0
docker exec aiops-mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" aiops \
-e "SELECT name, cpu_usage, memory_usage FROM kubernetes_nodes WHERE cluster_id=1"
# U2: 触发同步
curl -X POST http://127.0.0.1:8080/api/v1/kubernetes-clusters/1/sync \
-H "Authorization: Bearer $TOKEN"
# U3: 同步后 — 确认 cpu_usage/memory_usage 非零
docker exec aiops-mysql mysql -uroot -p"$MYSQL_ROOT_PASSWORD" aiops \
-e "SELECT name, cpu_usage, memory_usage FROM kubernetes_nodes WHERE cluster_id=1"
# 期望: cpu_usage > 0 AND memory_usage > 0
# U4: 集群详情页 API — 无硬编码
curl -s http://127.0.0.1:8080/api/v1/kubernetes-clusters/1 \
-H "Authorization: Bearer $TOKEN" | jq '.data.node_count, .data.pod_count'
# 期望: node_count=2, pod_count>0
# U5: 前端构建无报错
cd /srv/aiops/frontend && npm run build 2>&1 | tail -5
# 期望: vite build 成功
```
### 通过标准
- [x] U1: 同步前 cpu_usage=0
- [x] U2: 同步 API 200
- [x] U3: 同步后 cpu_usage>0
- [x] U4: 集群计数正确
- [x] U5: 前端构建成功
---
## M2: Pod Metrics
### 验证用例
```bash
# 同步后 Pod 列表含 CPU/内存
curl -s "http://127.0.0.1:8080/api/v1/kubernetes-clusters/1/pods" \
-H "Authorization: Bearer ***" | jq '.data[0]'
# 期望: 含 cpu_usage_m / mem_usage_mi 字段
```
### 通过标准
- [x] Pod 列表 API 返回 cpu_usage_m / mem_usage_mi 字段
- [x] 前端 Pod 列表表格显示 CPU/内存列(KubernetesWorkloads + NamespaceResourcePage)
- [x] 17 个 Pod 全部有真实 metrics 数据
---
## M3: Pod 文件上传
### 验证用例
```bash
# 上传文件
echo "test content" > /tmp/test-upload.txt
curl -X POST "http://127.0.0.1:8080/api/v1/kubernetes/1/namespace/devops/pods/aiops-xxx/files/upload?path=/tmp&container=aiops" \
-H "Authorization: Bearer ***" \
-F "file=@/tmp/test-upload.txt"
# 期望: 200 + 文件出现在列表中
```
### 通过标准
- [x] 上传 API 返回 200 + verify 字段匹配文件大小
- [x] 文件列表 (ls) 能看到上传的文件
- [x] ExecInPod 使用 WebSocket channel.k8s.io 协议(不再用 SPDY raw HTTP)
- [x] BusyBox ls 解析兼容(Mon DD HH:MM 格式)
---
## M5: Deployment 暂停更新 + CI/CD 集成
### 验证用例
```bash
# U1: 暂停前 — 确认 paused=false
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments" \
-H "Authorization: Bearer $TOKEN" | jq '.data[] | select(.name=="redis") | .paused'
# 期望: false
# U2: 暂停 Deployment
curl -X POST "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments/redis/pause" \
-H "Authorization: Bearer $TOKEN"
# 期望: code=200, msg="已暂停滚动更新"
# U3: 暂停后 — 确认 paused=true
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments" \
-H "Authorization: Bearer $TOKEN" | jq '.data[] | select(.name=="redis") | .paused'
# 期望: true
# U4: 恢复 Deployment
curl -X POST "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments/redis/resume" \
-H "Authorization: Bearer $TOKEN"
# 期望: code=200, msg="已恢复滚动更新"
# U5: 恢复后 — 确认 paused=false
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments" \
-H "Authorization: Bearer $TOKEN" | jq '.data[] | select(.name=="redis") | .paused'
# 期望: false
```
### 通过标准
- [x] U1: 暂停前 paused=false
- [x] U2: pause API 返回 200
- [x] U3: 暂停后 paused=true
- [x] U4: resume API 返回 200
- [x] U5: 恢复后 paused=false
- [x] ID 路由 + Kuboard code 路由均可用
- [x] 前端操作菜单显示「暂停更新/恢复更新」动态切换
- [x] CI/CD 发布按钮可跳转到流水线页面
---
## M6: 编辑器基础设施 + 基本信息 Tab + YAML编辑器
### 验证用例
```bash
# U1: 三模式路由 SPA fallback 200(非 301/404)
curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1/kubernetes/prod-cluster/namespace/devops/workload/yaml/Deployment/redis"
# 期望: 200
# U2: YAML GET API — CodeMirror 编辑器数据源
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments/redis/yaml" \
-H "Authorization: Bearer *** | head -5
# 期望: apiVersion: apps/v1 / kind: Deployment / metadata:
# U3: 前端构建含 CodeMirror 依赖
curl -s http://127.0.0.1/ | grep -oP 'index-[A-Za-z0-9]+\.js'
# 期望: 新 hash(每次构建变化)
# U4: TypeScript 编译无错误
cd frontend && npx tsc --noEmit
# 期望: 退出码 0
# U5: Vite 生产构建成功
cd frontend && npm run build 2>&1 | tail -3
# 期望: built in Ns
```
### 通过标准
- [x] U1: yaml 路由 SPA fallback 返回 200
- [x] U2: YAML API 返回有效 K8s manifest(apiVersion/kind/metadata 齐全)
- [x] U3: 前端 bundle 含 CodeMirror(codemirror 关键字在 JS chunk 中)
- [x] U4: TypeScript 零编译错误
- [x] U5: Vite 生产构建成功
- [x] YamlViewer 支持弹窗模式 + 内联模式(inline prop)
- [x] DeploymentEditBasic 可编辑 replicas/labels/annotations/selector
- [x] 编辑模式 Tab 导航系统就绪(基本信息可用 + M7-M9 预留)
---
## M7: 容器信息 Tab(工作容器 + 初始化容器)
### 验证用例
```bash
# U1: 登录获取 Token
TOKEN=$(curl -s http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' | jq -r '.data.token')
# 期望: code=200
# U2: YAML GET — 容器编辑器数据源
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/test-k8s/namespace/devops/deployments/aiops/yaml" \
-H "Authorization: Bearer $TOKEN" | head -5
# 期望: apiVersion: apps/v1 / kind: Deployment / containers:
# U3: PUT YAML 保存(容器编辑器保存路径)
curl -s -X PUT "http://127.0.0.1:8080/api/v1/kubernetes/test-k8s/namespace/devops/deployments/aiops/yaml" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/yaml" \
-d "$(curl -s .../aiops/yaml -H "Authorization: Bearer $TOKEN")"
# 期望: code=200
# U4: SPA fallback — edit 路由 200(非 301)
curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1/kubernetes/test-k8s/namespace/devops/workload/edit/Deployment/aiops"
# 期望: 200
# U5: TypeScript 编译 + Vite 构建无错误
cd frontend && npm run build 2>&1 | tail -3
# 期望: built in Ns
# U6: 前端 bundle 含 DeploymentEditContainers 组件(新 hash)
curl -s http://127.0.0.1/ | grep -oP 'index-[A-Za-z0-9]+\.js'
# 期望: 新 hash(每次构建变化)
```
### 通过标准
- [x] U1: 登录成功
- [x] U2: YAML API 返回含 containers 的有效 K8s manifest
- [x] U3: PUT 保存返回 code=200
- [x] U4: 编辑模式 SPA 路由返回 200(非 301)
- [x] U5: TypeScript 零编译错误 + Vite 构建成功
- [x] U6: 前端 bundle 已更新(含新组件)
- [x] DeploymentEditContainers 支持工作容器 + 初始化容器增删
- [x] 每个容器可编辑:镜像/拉取策略/命令/参数/环境变量/端口/资源/健康检查/生命周期/安全上下文/卷挂载
- [x] 镜像拉取凭证(imagePullSecrets) Pod 级别编辑
- [x] 三种探针类型(httpGet/tcpSocket/exec)可切换
---
## M8: 存储挂载 + 高级设置 Tab
### 验证用例
```bash
# U1: 登录获取 Token
TOKEN=$(curl -s http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' | jq -r '.data.token')
# U2: SPA fallback — edit 路由返回 200(非 301)
curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1/kubernetes/prod-cluster/namespace/devops/workload/edit/Deployment/redis"
# 期望: 200
# U3: YAML GET API — Storage/Advanced Tab 数据源
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments/redis/yaml" \
-H "Authorization: Bearer $TOKEN" | head -5
# 期望: apiVersion: apps/v1 / kind: Deployment / metadata:
# U4: TypeScript 编译 + Vite 构建
cd frontend && npx tsc --noEmit && npm run build 2>&1 | tail -3
# 期望: 零错误 + built in Ns
# U5: 前端 bundle 含 DeploymentEditStorage + DeploymentEditAdvanced 组件
curl -s http://127.0.0.1/ | grep -oP 'index-[A-Za-z0-9]+\.js'
# 期望: 新 hash(每次构建变化)
```
### 通过标准
- [x] U1: 登录成功
- [x] U2: edit 路由 SPA fallback 返回 200
- [x] U3: YAML API 返回含 spec.strategy/spec.template.spec 的有效 manifest
- [x] U4: TypeScript 零编译错误 + Vite 构建成功
- [x] U5: 前端 bundle 已更新
- [x] DeploymentEditStorage 支持 6 种 volume 类型(EmptyDir/HostPath/ConfigMap/Secret/PVC/NFS)
- [x] DeploymentEditAdvanced 支持更新策略/调度/nodeSelector/tolerations/DNS/安全上下文/主机设置/hostAliases/dnsConfig
- [x] 各 Tab 独立保存(PUT application/yaml 直通 K8s API)
---
## M10: Node 详情页(PID/容器运行时/分配率)
### 验证用例
```bash
# U1: 登录获取 Token
TOKEN=$(curl -s http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' | jq -r '.data.token')
# U2: Node detail API — Kuboard code route
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/test-k8s/nodes/k8s-master-01" \
-H "Authorization: Bearer *** | jq '.data.container_runtime'
# 期望: "containerd://2.1.4"
# U3: 资源分配率字段
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/test-k8s/nodes/k8s-master-01" \
-H "Authorization: Bearer *** | jq '.data | {cpu_alloc_pct, mem_alloc_pct, pod_alloc_pct, pod_count}'
# 期望: cpu_alloc_pct/mem_alloc_pct/pod_alloc_pct 均为数字 > 0
# U4: conditions + taints + pods 列表
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/test-k8s/nodes/k8s-master-01" \
-H "Authorization: Bearer *** | jq '.data | {conditions: (.conditions|length), taints: (.taints|length), pods: (.pods|length)}'
# 期望: conditions>=4, pods>=1
# U5: SPA fallback — node detail 路由 200
curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1/kubernetes/test-k8s/nodes/k8s-master-01"
# 期望: 200
# U6: TypeScript + Vite 构建
cd frontend && npx tsc --noEmit && npm run build 2>&1 | tail -3
# 期望: 零错误 + built in Ns
```
### 通过标准
- [x] U1: 登录成功
- [x] U2: Node detail API 返回 container_runtime/kubelet/os/kernel/architecture
- [x] U3: 资源分配率正确(cpu_alloc_pct/mem_alloc_pct/pod_alloc_pct 数字)
- [x] U4: conditions/taints/pods 列表非空
- [x] U5: SPA 路由 200(非 301)
- [x] U6: TypeScript 零错误 + Vite 构建成功
- [x] 前端节点名称可点击跳转详情页
---
## M9: 服务/应用路由 Tab + 整体联调
### 验证用例
```bash
# U1: 5 Tab 全部 available(检查 EditModeContainer)
# 验证方式: 浏览器打开 edit 模式,5 个 Tab 均可点击切换
# U2: TypeScript 编译
cd frontend && npx tsc --noEmit
# 期望: 退出码 0
# U3: Vite 构建成功
cd frontend && npm run build 2>&1 | tail -3
# 期望: built in Ns
```
### 通过标准
- [x] DeploymentEditService.tsx 组件存在且编译通过
- [x] DeploymentWorkload.tsx EditModeContainer 5 Tab 全部 available
- [x] Service Tab selector 双路径兼容(spec.selector.matchLabels || selector)
- [x] TypeScript 零编译错误 + Vite 构建成功
- [x] 前端 bundle 已更新
---
## M11: StatefulSet/DaemonSet 详情页
### 验证用例
```bash
# U1: 登录获取 Token
TOKEN=$(curl -s http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' | jq -r '.data.token')
# U2: DaemonSet YAML API(路由冲突修复验证)
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/kube-system/daemonsets/calico-node/yaml" \
-H "Authorization: Bearer *** | head -3
# 期望: apiVersion: apps/v1 / kind: DaemonSet / metadata:
# U3: DaemonSet Detail API
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/kube-system/daemonsets/calico-node" \
-H "Authorization: Bearer *** | jq '.data | {name: .metadata.name, desired: .status.desiredNumberScheduled, ready: .status.numberReady}'
# 期望: name="calico-node", desired=2, ready=2
# U4: Deployment YAML 仍正常(generic 路由未受影响)
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/namespace/devops/deployments/redis/yaml" \
-H "Authorization: Bearer *** | head -1
# 期望: apiVersion: apps/v1
# U5: SPA fallback — workload 路由 200
curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1/kubernetes/prod-cluster/namespace/kube-system/workload/view/DaemonSet/calico-node"
# 期望: 200
# U6: TypeScript + Vite 构建
cd frontend && npx tsc --noEmit && npm run build 2>&1 | tail -3
# 期望: 零错误 + built in Ns
```
### 通过标准
- [x] U2: DS YAML API 返回 200 + apiVersion + kind=DaemonSet(Gin radix tree 路由冲突已修复)
- [x] U3: DS Detail API 返回 name/desired/current/ready/containers
- [x] U4: Deployment YAML API 仍正常(generic `/:resource/:name/yaml` 路由未受影响)
- [x] U5: SPA 路由 view/yaml 两种模式均返回 200
- [x] U6: TypeScript 零编译错误 + Vite 构建成功
- [x] NamespaceResourcePage 点击 STS/DS 行可跳转详情页
- [x] WorkloadViewPage 支持 view/yaml 双模式切换
- [x] WorkloadViewPage kind 从 useLocation 正确提取(DaemonSet 不被误判为 StatefulSet)
- [x] 更新策略/选择器/PVC模板/InitContainers 全部展示
---
## M12: 事件聚合 + 告警联动
### 验证用例
```bash
# U1: 登录获取 Token
TOKEN=*** -s http://127.0.0.1:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' | jq -r '.data.token')
# U2: Events Summary API(聚合统计)
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/events/summary" \
-H "Authorization: Bearer $TOKEN" | jq '.data | {total, warning_count, normal_count, reasons: (.by_reason|length), namespaces: (.by_namespace|length), kinds: (.by_kind|length), recent: (.recent_warnings|length)}'
# 期望: total/warning_count/normal_count 为数字,by_reason/by_namespace/by_kind/recent_warnings 为数组
# U3: Events Summary 时间窗口过滤
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/events/summary?hours=24" \
-H "Authorization: Bearer $TOKEN" | jq '.data.total'
# 期望: 只返回近 24 小时事件计数
# U4: Events List 仍正常
curl -s "http://127.0.0.1:8080/api/v1/kubernetes/prod-cluster/events" \
-H "Authorization: Bearer $TOKEN" | jq '.data | length'
# 期望: 返回事件数组
# U5: SPA 路由
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/kubernetes/prod-cluster/events
# 期望: 200
# U6: TypeScript + Vite 构建
cd frontend && npx tsc --noEmit && npm run build 2>&1 | tail -3
# 期望: 零错误 + built in Ns
```
### 通过标准
- [x] U2: Events Summary API 返回完整聚合数据(total/warning_count/normal_count/by_reason/by_namespace/by_kind/recent_warnings)
- [x] U3: 时间窗口过滤正常(hours=24 只统计近 24h)
- [x] U4: Events List API 不受影响
- [x] U5: SPA 路由返回 200
- [x] U6: TypeScript 零编译错误 + Vite 构建成功
- [x] 前端三维度柱状图正确渲染(recharts)
- [x] 图表点击联动过滤事件列表
- [x] 最新告警面板展示 Warning 事件