feat: 平台治理与权限体系完善,存储进度/GPU预留/审批中心与日志整合

- 平台治理: 租户用户权限层次、资源ACL、审批中心与审批模板、访问申请
- 存储: MinIO 存储进度迁移、对象存储安全加固与测试
- 计算: GPU 资源预留、compute 轮询与同步增强
- 权限: permission v2 迁移、权限安全验收测试
- 日志: 后端运行日志中文说明、操作日志整合
- 数据处理/评测: 数据转换与模型评测优化

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
wuyongtao
2026-08-21 09:49:48 +08:00
parent 080ef6ab00
commit 6f0e82f351
94 changed files with 9547 additions and 1045 deletions

View File

@@ -1,25 +1,18 @@
"""GPU 算力分配管理路由。"""
from __future__ import annotations
import json
from typing import Any
from fastapi import APIRouter, Body, Depends, Request
from app.api.v1.endpoints.platform import ok, fail
from app.core.auth import get_current_user, is_admin
from app.core.auth import get_current_user, is_admin, user_tenant_ids
from app.db.platform_store import get_platform_store
router = APIRouter(prefix="/compute", tags=["gpu-assignment"])
def _actor_id(request: Request) -> str | None:
auth = request.headers.get("Authorization", "")
token = auth.replace("Bearer ", "").strip()
if token.startswith("platform-token-"):
return token[len("platform-token-"):]
return None
@router.get("/gpu-assignments")
def list_assignments(current_user: dict = Depends(get_current_user)) -> dict[str, Any]:
"""查看全部分配关系(仅 admin"""
@@ -40,8 +33,11 @@ def assign_gpus(
assignments = payload.get("assignments") or []
if not assignments:
raise fail(400, "assignments 不能为空")
actor = _actor_id(request) if request else None
result = get_platform_store().assign_gpus(assignments, assigned_by=actor)
actor = current_user.get("id")
try:
result = get_platform_store().assign_gpus(assignments, assigned_by=actor)
except ValueError as exc:
raise fail(409, str(exc))
get_platform_store().record_audit(
action="gpu.assign",
actor_id=actor,
@@ -51,6 +47,41 @@ def assign_gpus(
return ok(result)
@router.post("/gpu-assignments/request")
def request_gpu_assignment(
payload: dict[str, Any] = Body(...),
current_user: dict = Depends(get_current_user),
) -> dict[str, Any]:
assignments = payload.get("assignments") or []
if not assignments:
raise fail(400, "assignments 不能为空")
if is_admin(current_user):
try:
return ok(get_platform_store().assign_gpus(assignments, assigned_by=current_user.get("id")))
except ValueError as exc:
raise fail(409, str(exc))
user_id = str(current_user.get("id") or "")
normalized = []
for item in assignments:
if not isinstance(item, dict) or not item.get("node_id") or item.get("gpu_index") is None:
raise fail(400, "每项必须包含 node_id 和 gpu_index")
normalized.append({**item, "user_id": user_id})
instance = get_platform_store().create_approval_instance({
"resource_type": "gpu",
"resource_id": f"batch:{user_id}",
"applicant_id": user_id,
"action": "gpu.assign",
"tenant_id": current_user.get("tenant_id") or "default",
"reason": json.dumps({"assignments": normalized}, ensure_ascii=False),
})
get_platform_store().record_audit(
action="gpu.assign.request", actor_id=user_id, target_type="gpu",
target_id=instance["id"], tenant_id=current_user.get("tenant_id") or "default",
detail=f"count={len(normalized)}",
)
return ok({"approval_required": True, "approval_id": instance["id"], "approval": instance})
@router.delete("/gpu-assignments/{assignment_id}")
def unassign_gpu(
assignment_id: str,
@@ -61,7 +92,7 @@ def unassign_gpu(
if not is_admin(current_user):
raise fail(403, "admin permission required")
get_platform_store().unassign_gpu(assignment_id)
actor = _actor_id(request) if request else None
actor = current_user.get("id")
get_platform_store().record_audit(
action="gpu.unassign",
actor_id=actor,