feat(deploy): prompt RDS config as separate fields

This commit is contained in:
姚章浩
2026-09-11 18:04:38 +08:00
parent d77fbd675b
commit 49e0789fa5
3 changed files with 38 additions and 3 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ sudo bash ./install-docker.sh
sudo dobotai-dingtalk-configure
```
配置器要求填写阿里云RDS连接串、WeKnora和钉钉凭证;密钥不回显,环境文件原子写入且权限0600。
配置器分字段录入阿里云RDS(主机、端口、数据库名、账号、密码),自动组装连接串;WeKnora和钉钉凭证密钥不回显,环境文件原子写入且权限0600。
`DOBOTAI_TENANT_KEY`不是WeKnora Agent租户键。它是DobotAI内部数据隔离键,首次安装时自动生成并固定保存;配置器不会要求填写或改动它。WeKnora侧只需要填写实际的两个Agent ID。
+33 -1
View File
@@ -4,11 +4,11 @@ import getpass
import json
import os
from pathlib import Path
from urllib.parse import quote, unquote, urlsplit
import subprocess
import sys
FIELDS = (
("DATABASE_URL", "阿里云RDS PostgreSQL连接串", "已有DobotAI专用阿里云RDS数据库;脚本只检查表,空库才初始化。", "postgres://USER:***@rds-endpoint:5432/dobotai?sslmode=require", True),
("WEKNORA_BASE_URL", "WeKnora 地址", "应用容器通过宿主机网络访问既有WeKnora。", "http://127.0.0.1:8080", False),
("WEKNORA_API_KEY", "WeKnora API Key", "DobotAI专用WeKnora API Key。", "<你的WeKnora API Key>", True),
("DOBOTAI_QUICK_AGENT_ID", "快速问答Agent ID", "默认问答实际调用的WeKnora Agent。", "<快速问答Agent ID>", False),
@@ -17,6 +17,37 @@ FIELDS = (
("DINGTALK_CLIENT_SECRET", "钉钉 Client Secret", "钉钉应用Client Secret/AppSecret。", "<你的钉钉 AppSecret>", True),
)
def prompt_rds(values):
"""分字段录入阿里云RDS并组装DATABASE_URL;已有值作为默认。"""
existing = values.get("DATABASE_URL", "").strip()
host = port = database = user = password = ""
if existing:
u = urlsplit(existing)
host = u.hostname or ""
port = str(u.port or "") if u.port else ""
database = u.path.lstrip("/")
user = unquote(u.username or "")
password = unquote(u.password or "")
def ask(key, label, default, secret=False):
suffix = "(已配置,直接回车保留)" if default else "(必填)"
reader = getpass.getpass if secret else input
entered = reader(f"{label}{suffix}: ").strip()
return entered or default
print("\n阿里云RDS PostgreSQL(分字段填写)\n用途:DobotAI专用数据库;空库自动初始化,已有表只校验不改结构。")
host = ask("host", "RDS主机地址", host)
port = ask("port", "RDS端口", port or "5432")
database = ask("database", "数据库名", database)
user = ask("user", "数据库账号", user)
password = ask("password", "数据库密码", password, secret=True)
if not all((host, port, database, user, password)):
raise SystemExit("RDS字段不完整,未保存。")
if not database.startswith(("dobotai", "dobotai_")):
print("警告:数据库名不是DobotAI专用库,继续前请确认。")
values["DATABASE_URL"] = f"postgres://{quote(user, safe='')}:{quote(password, safe='')}@{host}:{port}/{database}"
def parse_env(path):
lines = path.read_text(encoding="utf-8").splitlines(); values = {}
for line in lines:
@@ -40,6 +71,7 @@ def main():
args=parser.parse_args(); path=Path(args.env_file)
if not path.is_file(): raise SystemExit("DobotAI环境文件不存在,请先执行根目录install-docker.sh。")
lines,values=parse_env(path)
prompt_rds(values)
for key,label,description,example,secret in FIELDS:
suffix="(已配置,直接回车保留)" if values.get(key,"").strip() else "(必填)"
print(f"\n{label}\n用途:{description}\n格式示例:{example}")
+4 -1
View File
@@ -80,11 +80,14 @@ func TestRDSCredentialConfiguratorPromptsForExternalDatabase(t *testing.T) {
t.Fatal(err)
}
source := string(data)
for _, required := range []string{"DATABASE_URL", "阿里云RDS", "快速问答Agent ID", "智能推理Agent ID", "getpass.getpass", "os.replace", "0o600"} {
for _, required := range []string{"DATABASE_URL", "阿里云RDS", "RDS主机地址", "RDS端口", "数据库名", "数据库账号", "数据库密码", "快速问答Agent ID", "智能推理Agent ID", "getpass.getpass", "os.replace", "0o600"} {
if !strings.Contains(source, required) {
t.Errorf("RDS configurator missing %q", required)
}
}
if strings.Contains(source, "RDS PostgreSQL连接串") {
t.Fatal("operator must not be asked to type a whole DATABASE_URL string")
}
if strings.Contains(source, "DobotAI租户键") || strings.Contains(source, "Agent Bindings JSON") || strings.Contains(source, "DobotAI Ingress Token") {
t.Fatal("operator must only be prompted for real RDS, WeKnora and DingTalk configuration")
}