refactor: full-stack restructure with multi-tenancy, workspace management, and K8s diagnostics

- Add Workspace domain (entity, repository, service, handler, DTO)
- Add multi-tenant K8s client with tenant binding and quota management
- Add K8s diagnostics client (instance diagnostics)
- Add authorization middleware (authz package)
- Restructure frontend to feature-based architecture (features/)
- Add User Management page in configuration
- Add AccessDenied page and route guards
- Refactor shared components (form inputs, layout, UI)
- Update Tailwind config for new design system
- Add comprehensive documentation (docs/, tasks/, plans)
- Improve cluster service with better kubeconfig handling
- Add tests for crypto, config, helm client, tenant binding
This commit is contained in:
Ivan087
2026-05-12 16:15:14 +08:00
parent c5e51ed069
commit 7f238a3168
172 changed files with 15703 additions and 3162 deletions

141
docs/test2-report.md Normal file
View File

@ -0,0 +1,141 @@
# OCDP 第二次测试报告
**测试日期:** 2026-05-11
**测试环境:** http://10.6.80.114:18080
---
## 测试1: 资源配额限额
### 测试方法
使用 test-user-bquota: cpu=2, mem=4Gi, gpu=0, gpumem=0在 k3s 集群部署 nginx chart
### 测试结果
| 测试 | 操作 | 预期 | 实际 | 结论 |
|------|------|------|------|------|
| Test A | 部署 nginx默认值在配额内 | 成功 | 部署完成,状态 deployed | ✅ |
| Test B | 部署 nginxrequests.cpu=2, mem=4Gi, replica=5超配额 | 被配额阻止 | Helm release 创建成功,所有 Pod 被 ResourceQuota 阻塞,状态永远 stuck 在 pending-install | ⚠️ 部分通过 |
| Test C | 部署 vllm-servegpuLimit=1gpu配额=0 | 被配额阻止 | Helm release 创建成功Pod 被 ResourceQuota 阻塞,状态 pending-install | ⚠️ 部分通过 |
### 关键发现
**1. 没有 API 层的预检查配额验证**
- 后端 API 无条件接受所有部署请求,不检查是否超配额
- 所有超配额请求返回 HTTP 200 + status: pending-install
- 后端日志中**没有任何配额相关的条目**
**2. K8s ResourceQuota 在 Pod 级别执行**
- `tenant-quota` ResourceQuota 对象确实存在并执行限制
- 当 Pod 超配额时K8s 明确拒绝创建并给出错误消息
- 但 Helm release、Service、Deployment、ReplicaSet **仍然被创建**
**3. 实例永远 stuck 在 "pending-install"**
- 超配额的实例永远不会转换到 deployed/failed/error
- OCDP 平台不检测 ResourceQuota 拒绝事件
- 唯一知道失败的方式是直接查 K8s events
**4. GPU 配额绕过**
- gpu=0 的用户可以提交需要 GPU 的 chart 部署
- K8s ResourceQuota 最终会阻止,但 Helm release 等资源已被创建
**5. 有效的 ResourceQuota 配置**
```yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-quota
namespace: ocdp-u-test-b
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
requests.nvidia.com/gpu: "0"
requests.nvidia.com/gpumem: "0"
```
### 建议
1. **添加 API 层预检查配额验证** — 在接受部署前检查请求资源是否超过用户配额
2. **处理 pending-install 超时** — 监控 Helm release 创建后 Pod 是否 stuck更新状态为 failed
3. **GPU 配额预检查** — 如果 chart 需要 GPU 而用户 gpu=0在 API 层拒绝
4. **UI 配额指示器** — 在部署表单上显示剩余配额
---
## 测试2: values.yaml 覆盖优先级
### 测试方法
使用 test-user-cquota: cpu=4, mem=8Gi, gpu=1, gpumem=5000部署 vllm-serve:0.6.0 chart
### 测试结果
| 方法 | 提交方式 | 是否部署成功 | 存储的值 | 结论 |
|------|----------|-------------|---------|------|
| 方法1 | `values` JSON 字段 | ✅ | cpuRequest=2, gpuMem=10000 | JSON 值被准确接受和存储 |
| 方法2 | `valuesYaml` 字符串 | ✅ | cpuRequest=4, gpuMem=10000 | YAML 被正确解析为结构化 values |
| 方法3 | 同时提供 `values` + `valuesYaml`(冲突) | ✅ 无任何错误/警告 | **values JSON 全胜** | `values` JSON 静默覆盖 `valuesYaml` |
| 方法4 | 不提供任何 values使用 chart 默认) | ✅ | 仅 namespace | chart 默认值不存储在 API 响应中 |
### 优先级最终结论
| 优先级 | 来源 | 说明 |
|--------|------|------|
| **最高** | `values` JSON 字段 | 请求体中的结构化 JSON |
| **中** | `valuesYaml` 字符串 | 请求体中的 YAML 字符串 |
| **最低** | Chart 内置 values.yaml | Helm chart 打包的默认值 |
### 冲突测试详细结果
当同时提供 `values``valuesYaml` 且值冲突时:
- `values` JSON 字段**完全覆盖** `valuesYaml`
- **没有任何错误或警告**返回给用户
- 两者被合并到统一的 DB `values` 字段
### gpuMem=10000 行为
- 整数值 `10000``values` JSON 和 `valuesYaml` 中都被**正确接受**
- 无单位转换(作为整数 MB 标量存储)
- 符合项目规范
### 建议
1. **记录优先级顺序** — 用户需知道同时提供两者时 values JSON 优先
2. **添加冲突警告** — 当两个字段存在冲突值时应返回警告
3. **考虑废弃一个字段** — values 和 valuesYaml 语义重复易混淆
---
## 测试3: 前端 UI 溢出/滚动/刷新
### 测试方法
Playwright + 源码分析,测试 1920/768/375 三个视口
### 测试结果
**总体结论: PASS** — 没有导致功能问题的关键溢出问题
| 测试项 | 结果 | 详情 |
|--------|------|------|
| 水平溢出 | ✅ 无问题 | 所有视口均无水平溢出 |
| 文本截断 | ⚠️ 1 个低风险 | InstanceCard h3 标题 truncate 无 title tooltip |
| 响应式设计 | ✅ 正确 | sm/md/lg/xl 断点覆盖完整 |
| 滚动行为 | ✅ 流畅 | Sidebar 和内容区独立滚动overscroll-contain 防滚动穿透 |
| 模态框布局 | ✅ 正确 | body scroll lock + 内容独立滚动 |
| 页面刷新 | ✅ 正常 | 受保护路由正确重定向到登录页 |
| 颜色对比度 | ⚠️ 1 个中风险 | 登录页错误文本 red-400 在白色背景上仅 2.5:1 (WCAG AA 要求 4.5:1) |
### 通过的细分项
- Chart Browser 全高 + overflow-y-auto 布局 ✅
- InstanceCard 操作按钮网格 grid-cols-2/3/5 响应正确 ✅
- Tabs 支持 overflow-x-auto 水平滚动 ✅
- 用户管理表格 overflow-x-auto ✅
- iOS 触摸滚动 (`-webkit-overflow-scrolling: touch`) 已配置 ✅
### 建议
1. 将登录页错误文本从 text-red-400 改为 text-red-600/700
2. InstanceCard h3 标题添加 title 属性
---
## 综合建议
1. 添加 API 层配额预检查
2. 处理 pending-install 超时 + 状态更新
3. 记录 values 覆盖优先级并添加冲突警告
4. 统一 values JSON/YAML 的 API 设计