feat(compute): 算力引擎对接改造 + 用户生命周期自动同步
- config: 置顶 load_dotenv(.env),修复 .env 未生效;COMPUTE_ADMIN_TOKEN 改读 PINEAGENTS_INTERNAL_TOKEN(回退旧名),新增独立 COMPUTE_RELAY_TOKEN - compute_client: 空令牌不下发 Bearer(避免 httpx 非法头);proxy 空令牌返 503 中文诊断;新增 sync_user_enabled/sync_delete_user - relay: /v1 转发改走 COMPUTE_RELAY_TOKEN(真实消费令牌),空令牌不下发 - rbac_admin: 平台用户创建→自动建引擎账号+签PAT;启用/禁用→同步引擎状态;删除→同步删引擎账号(最佳努力,失败静默)
This commit is contained in:
@@ -10,10 +10,19 @@ from ..schemas.admin import SetUserRoleRequest, SetUserStatusRequest
|
||||
from ..schemas.admin import UserCreateRequest, RolePermissionRequest, UpdateUserRequest
|
||||
from ...rbac import require_permission, require_roles, write_audit
|
||||
from ...infrastructure.repositories import Database
|
||||
from ...services import compute_client
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
|
||||
|
||||
async def _sync_compute(coro) -> None:
|
||||
"""算力引擎用户同步为附加能力:失败不阻断平台用户操作(引擎未配置/不可达时静默)。"""
|
||||
try:
|
||||
await coro
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
|
||||
|
||||
@router.post("/users", summary="新增账号(按类型/角色)")
|
||||
async def create_user(
|
||||
req: UserCreateRequest,
|
||||
@@ -24,6 +33,9 @@ async def create_user(
|
||||
from ...services.user_admin_service import UserAdminService
|
||||
|
||||
user = await UserAdminService(db).create_user(req, actor)
|
||||
# 平台用户创建 → 引擎同步建号 + 签发 PAT(算力引擎用户与平台一致)
|
||||
await _sync_compute(compute_client.create_user(user["username"]))
|
||||
await _sync_compute(compute_client.issue_pat(user["username"]))
|
||||
await write_audit(db, action="user.create", resource="user", resource_id=user["id"],
|
||||
detail=f"role={req.role}", user=actor, request=request)
|
||||
return await db.users.to_profile(user)
|
||||
@@ -78,9 +90,14 @@ async def set_user_status(
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_permission("action:user.disable")),
|
||||
):
|
||||
if await db.users.get_by_id(user_id) is None:
|
||||
user = await db.users.get_by_id(user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
updated = await db.users.set_status(user_id, req.status)
|
||||
# 平台用户启用/禁用 → 引擎镜像同步
|
||||
await _sync_compute(compute_client.sync_user_enabled(
|
||||
user.get("username"), req.status == "active",
|
||||
))
|
||||
await write_audit(
|
||||
db, action="user.disable", resource="user", resource_id=user_id,
|
||||
detail=f"{actor['username']} -> status={req.status}",
|
||||
@@ -118,9 +135,13 @@ async def delete_user(
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_permission("action:user.manage")),
|
||||
):
|
||||
user = await db.users.get_by_id(user_id)
|
||||
ok = await db.users.delete(user_id)
|
||||
if not ok:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
# 平台用户删除 → 引擎镜像同步删除
|
||||
if user:
|
||||
await _sync_compute(compute_client.sync_delete_user(user.get("username")))
|
||||
await write_audit(db, action="user.delete", resource="user", resource_id=user_id,
|
||||
detail="deleted", user=actor, request=request)
|
||||
return {"ok": True, "user_id": user_id}
|
||||
|
||||
@@ -30,7 +30,12 @@ _ENGINE_MODEL_IDS = [
|
||||
|
||||
|
||||
def _auth_headers() -> dict[str, str]:
|
||||
return {"Authorization": f"Bearer {config.COMPUTE_ADMIN_TOKEN}"}
|
||||
# /v1 转发用引擎能识别的真实消费令牌(PINEAGENTS_COMPUTE_RELAY_TOKEN),
|
||||
# 与管理的 COMPUTE_ADMIN_TOKEN(内部合成 root) 区分;空令牌不下发,避免 `Bearer ` 非法被 httpx 拒绝。
|
||||
token = config.COMPUTE_RELAY_TOKEN or config.COMPUTE_ADMIN_TOKEN
|
||||
if not token:
|
||||
return {}
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
||||
|
||||
@router.post("/chat/completions")
|
||||
|
||||
Reference in New Issue
Block a user