sub2api 网关接入:每用户独立账号 + 任务注入 + 网关可配置
- cloud/sub2api.py:管理 API 客户端(管理员登录/token 刷新/ 建用户/以用户发 key/删用户/查组/网关模型目录)+ 幂等开通 ensure_user_gateway_key(入库失败尽力清理孤儿 key 与账号) - worker:网关门(sub2api 时按 created_by 幂等开通,失败任务 直接 failed;协调员子任务跟父任务属主)+ 默认模型走网关 目录首个;三条执行路径(Local popen/同步、Docker 同步)注 入任务级 env 与 --model-provider;NO_PROXY 追加网关 host - host.py:--model-provider,sub2api 时以 -c 注入 provider 表 (不改租户 config.toml);未配 SUB2API_BASE_URL 时 loud fail - sandbox:Local/Docker 执行器传 --model-provider 与任务 env; docker 密钥只传名(-e SUB2API_API_KEY),值由 CLI 子进程 环境提供,绝不进 argv;runner 不支持 env 时 loud fail - server:OAuth 建号 best-effort 开通;/relay/models 走调用者 自己的网关模型目录;init_db 补 user_gateway_keys 表 - 测试:新单测 11 个;全量 cloud 679(4 跳过)、host 65、 deploy 19 全过 - 诚实边界:真模型调用实弹需上游账号挂组后才做;切流前 xcmapi 保持现网
This commit is contained in:
1 parent
437684902a
commit
ec47328d3c
7 files changed
+996
-54
No files matched your search
+44
-1
@@ -113,6 +113,12 @@ from cloud.oauth import (
|
||||
)
|
||||
from cloud.relay import RelayError as _RelayError
|
||||
from cloud.relay import get_relay_models as _get_relay_models
|
||||
from cloud.sub2api import ensure_gateway_keys_table as _ensure_gateway_keys
|
||||
from cloud.sub2api import ensure_user_gateway_key as _ensure_sub2api_key
|
||||
from cloud.sub2api import gateway_name as _gateway_name
|
||||
from cloud.sub2api import gateway_origin as _gateway_origin
|
||||
from cloud.sub2api import get_user_gateway_key as _get_sub2api_key
|
||||
from cloud.sub2api import list_gateway_models as _list_sub2api_models
|
||||
from cloud.repos import validate_repo_url
|
||||
from cloud.push import (
|
||||
create_subscription as _push_create,
|
||||
@@ -1052,6 +1058,7 @@ def init_db(db_path):
|
||||
_ensure_followups_table(conn)
|
||||
_ensure_environments_table(conn)
|
||||
_ensure_quotas_table(conn)
|
||||
_ensure_gateway_keys(conn)
|
||||
_ensure_uploads_tables(conn)
|
||||
conn.commit()
|
||||
return
|
||||
@@ -2340,6 +2347,33 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
# 现回,只把模型 id 交给调用者。key 绝不进响应、日志、
|
||||
# 缓存(见 cloud/relay.py)。单测可经 server.relay_fetcher
|
||||
# 注入假取数函数;中转挂了或未配 key 时 502,不编造列表。
|
||||
# 网关为 sub2api 时:模型目录因用户而异(key 绑定的组
|
||||
# 决定),取调用者自己的网关 key 现查;无 key 时返回空
|
||||
# 列表 + provisioning 标记(控制台据此提示开通中),不
|
||||
# 在页面加载时悄悄开通(开通在建号与任务时发生)。
|
||||
if _gateway_name() == "sub2api":
|
||||
conn = self._db()
|
||||
try:
|
||||
row = _get_sub2api_key(conn, user_id)
|
||||
try:
|
||||
conn.commit()
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
conn.close()
|
||||
if row is None or not row.get("api_key"):
|
||||
self._send_json(200, {"models": [], "gateway": "sub2api",
|
||||
"provisioning": "pending"})
|
||||
return
|
||||
try:
|
||||
models = _list_sub2api_models(_gateway_origin(),
|
||||
row["api_key"])
|
||||
except Exception as exc:
|
||||
self._send_json(502, {"error": str(exc)})
|
||||
return
|
||||
self._send_json(200, {"models": models, "gateway": "sub2api",
|
||||
"cached": False, "updated_at": None})
|
||||
return
|
||||
fetcher = getattr(self.server, "relay_fetcher", None)
|
||||
try:
|
||||
models, cached, updated_at = _get_relay_models(fetcher=fetcher)
|
||||
@@ -2347,7 +2381,8 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
self._send_json(502, {"error": str(exc)})
|
||||
return
|
||||
self._send_json(200, {
|
||||
"models": models, "cached": cached, "updated_at": updated_at})
|
||||
"models": models, "cached": cached, "updated_at": updated_at,
|
||||
"gateway": "xcmapi"})
|
||||
|
||||
def _models_overview(self, user_id):
|
||||
# 优先级列表来自环境变量 MODELS_PRIORITY(逗号分隔),未设时
|
||||
@@ -4505,6 +4540,14 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
auth.audit(local_id, "", "quota_default",
|
||||
"quota_usd_micros=%d"
|
||||
% _default_quota_usd_micros())
|
||||
if created and _gateway_origin() is not None:
|
||||
# sub2api 开通(best-effort):建号不因网关开通失败
|
||||
# 而失败,任务时 _ensure_gateway 会懒开通兜底。
|
||||
try:
|
||||
_ensure_sub2api_key(auth.conn, local_id)
|
||||
except Exception as exc:
|
||||
auth.audit(local_id, "", "sub2api_provision_failed",
|
||||
str(exc)[:200])
|
||||
if not created:
|
||||
auth.audit(local_id, "", "api_key_issued", provider)
|
||||
return local_id, created, api_key_plain, rotated, identity, False
|
||||
|
||||
Reference in new issue
Block a user