Files
vps-manager/app/core/seed.py
T
gouki 103f48e38b feat(adapters): 接入 CloudCone/Zeabur/Dynadot/新网/Agnes 五个平台
线上平台列表里 cloudcone、zeabur、xinwang、dynadot、agnes 的 sdk_type 仍为空,
平台卡片只能显示「未对接」,用户无法同步。按各自真实 API 能力补齐:

- CloudCone:实例清单 + 开机/关机/重启;无公开账单接口,不声明余额与续费
- Zeabur:服务器清单 + 重启;毫核/MB 归一化为核/GB,未采集时不伪造规格
- Dynadot:域名清单(含到期日)+ 账户余额;set_dns2 位置参数无法安全 CRUD
- 新网:代理 API 按域名逐个查到期日;无列表接口,需在账号里填 domains 清单
- Agnes:/models 校验 Key;无余额接口,如实标记不支持

配套改动:
- _align_preset_providers 为库中为空的 sdk_type 回填种子值(启动即生效),
  避免新适配器上线后线上仍停留在「未对接」
- 适配器可声明 plain_config,代理号/域名等非密钥字段前端按明文输入
- PRESET_PROVIDERS 五条记录填上对应 sdk_type

测试:445 passed(新增 tests/test_platform_adapters.py),vitest 62 passed。
2026-10-26 09:16:45 +00:00

97 lines
6.0 KiB
Python

"""平台预设种子数据
首次部署或调用 POST /api/providers/seed 时初始化常见平台。
每个平台有唯一 slug,供未来按 sdk_type 对接自动同步扩展。
"""
from sqlmodel import Session, select
from app.models.provider import Provider
PRESET_PROVIDERS = [
# ---- VPS / 云服务商 ----
# 综合平台:services 列出可提供的服务,卡片上会显示多标签
{"slug": "aliyun", "name": "阿里云", "name_en": "Aliyun", "category": "vps",
"services": "vps,domain,ssl_cert,cdn,dns",
"website": "https://aliyun.com", "console_url": "https://ecs.console.aliyun.com", "sdk_type": "aliyun-sdk"},
{"slug": "tencent", "name": "腾讯云", "name_en": "Tencent Cloud", "category": "vps",
"services": "vps,domain,ssl_cert,cdn,dns",
"website": "https://cloud.tencent.com", "console_url": "https://console.cloud.tencent.com/cvm", "sdk_type": "tencent-sdk"},
{"slug": "aliyun-intl", "name": "阿里国际", "name_en": "Alibaba Cloud", "category": "vps",
"services": "vps,domain,ssl_cert,cdn,dns",
"website": "https://alibabacloud.com", "console_url": "https://ecs.console.alibabacloud.com", "sdk_type": "alibabacloud-sdk"},
{"slug": "tencent-intl", "name": "腾讯国际", "name_en": "Tencent Cloud Intl", "category": "vps",
"services": "vps,domain,ssl_cert,cdn,dns",
"website": "https://intl.cloud.tencent.com", "console_url": "https://console.intl.cloud.tencent.com", "sdk_type": "tencent-intl-sdk"},
{"slug": "aws", "name": "AWS", "name_en": "Amazon Web Services", "category": "vps",
"services": "vps,domain,dns,cdn,ssl_cert",
"website": "https://aws.amazon.com", "console_url": "https://console.aws.amazon.com/ec2/", "sdk_type": "aws-api"},
{"slug": "vultr", "name": "Vultr", "name_en": "Vultr", "category": "vps",
"services": "vps,domain,dns",
"website": "https://vultr.com", "console_url": "https://my.vultr.com", "sdk_type": "vultr-api"},
{"slug": "digitalocean", "name": "DigitalOcean", "name_en": "DigitalOcean", "category": "vps",
"services": "vps,domain,dns",
"website": "https://digitalocean.com", "console_url": "https://cloud.digitalocean.com", "sdk_type": "do-api"},
{"slug": "linode", "name": "Linode", "name_en": "Akamai Linode", "category": "vps",
"services": "vps,domain,dns",
"website": "https://linode.com", "console_url": "https://cloud.linode.com", "sdk_type": "linode-api"},
# WHMCS 面板类平台没有开放 API,通过账号关联的登录凭据进入客户区只读核对。
{"slug": "tothost", "name": "TotHost", "name_en": "TotHost", "category": "vps",
"services": "vps",
"website": "https://www.tothost.vn", "console_url": "https://billing.tothost.vn/clientarea.php", "sdk_type": "whmcs-panel"},
{"slug": "cloudcone", "name": "CloudCone", "name_en": "CloudCone", "category": "vps",
"services": "vps",
"website": "https://cloudcone.com", "console_url": "https://app.cloudcone.com", "sdk_type": "cloudcone-api"},
{"slug": "zeabur", "name": "Zeabur", "name_en": "Zeabur", "category": "vps",
"services": "vps,domain",
"website": "https://zeabur.com", "console_url": "https://dash.zeabur.com", "sdk_type": "zeabur-api"},
# ---- 域名注册商 ----
{"slug": "namesilo", "name": "Namesilo", "name_en": "Namesilo", "category": "domain",
"services": "domain,dns",
"website": "https://namesilo.com", "console_url": "https://www.namesilo.com/account_domains.php", "sdk_type": "namesilo-api"},
# 新网只有代理账号能调 API,且没有「列出全部域名」的接口:需在账号里
# 填写 domains 清单;零售客户区有验证码,无法用面板抓取替代。
{"slug": "xinwang", "name": "新网", "name_en": "Xinnet", "category": "domain",
"services": "domain,dns",
"website": "https://xinnet.com", "console_url": "https://www.xinnet.com", "sdk_type": "xinnet-api"},
{"slug": "dynadot", "name": "Dynadot", "name_en": "Dynadot", "category": "domain",
"services": "domain,dns",
"website": "https://dynadot.com", "console_url": "https://www.dynadot.com/account/domains", "sdk_type": "dynadot-api"},
# ---- AI 服务商 ----
{"slug": "openai", "name": "OpenAI", "name_en": "OpenAI", "category": "ai_agent",
"services": "ai_agent",
"website": "https://openai.com", "console_url": "https://platform.openai.com", "sdk_type": "openai-api"},
{"slug": "minimax", "name": "Minimax", "name_en": "Minimax", "category": "ai_agent",
"services": "ai_agent",
"website": "https://minimax.io", "console_url": "https://platform.minimaxi.com", "sdk_type": "minimax-api"},
{"slug": "kimi", "name": "Kimi", "name_en": "Moonshot", "category": "ai_agent",
"services": "ai_agent",
"website": "https://moonshot.cn", "console_url": "https://platform.moonshot.cn", "sdk_type": "moonshot-api"},
{"slug": "agnes", "name": "Agnes", "name_en": "Agnes", "category": "ai_agent",
"services": "ai_agent",
"website": None, "console_url": None, "sdk_type": "agnes-api"},
{"slug": "deepseek", "name": "DeepSeek", "name_en": "DeepSeek", "category": "ai_agent",
"services": "ai_agent",
"website": "https://deepseek.com", "console_url": "https://platform.deepseek.com", "sdk_type": "deepseek-api"},
# ---- Cloudflare ----
{"slug": "cloudflare", "name": "Cloudflare", "name_en": "Cloudflare", "category": "cloudflare",
"services": "cloudflare,dns,ssl_cert,cdn",
"website": "https://cloudflare.com", "console_url": "https://dash.cloudflare.com", "sdk_type": "cloudflare-api"},
]
def seed_providers(session: Session) -> int:
"""初始化预设平台(已存在的 slug 跳过),返回新增数量
单次查询获取全部已存在 slug,避免逐条 SELECT 的 N 次往返。
"""
existing_slugs = set(session.exec(select(Provider.slug)).all())
added = 0
for data in PRESET_PROVIDERS:
if data["slug"] not in existing_slugs:
session.add(Provider(**data))
added += 1
if added:
session.commit()
return added