feat: harden data access and simplify user management
This commit is contained in:
1 parent
3dd5731751
commit
adb780bc82
51 files changed
+3239
-2121
No files matched your search
@@ -33,12 +33,12 @@ def _connection_options(*, include_database: bool) -> dict[str, object]:
|
||||
parsed = urlparse(settings.data_mysql_url)
|
||||
if parsed.scheme not in {"mysql", "mysql+aiomysql"}:
|
||||
raise ValueError("DATA_MYSQL_URL 必须使用 mysql:// 协议")
|
||||
database = unquote(parsed.path.lstrip("/")) or "platform_control"
|
||||
if not _DATABASE_PATTERN.fullmatch(database):
|
||||
control_database = unquote(parsed.path.lstrip("/")) or "platform_control"
|
||||
if not _DATABASE_PATTERN.fullmatch(control_database):
|
||||
raise ValueError("DATA_MYSQL_URL 中的控制数据库名称不合法")
|
||||
|
||||
global _control_database
|
||||
_control_database = database
|
||||
_control_database = control_database
|
||||
options: dict[str, object] = {
|
||||
"host": parsed.hostname or "localhost",
|
||||
"port": parsed.port or 3306,
|
||||
@@ -49,7 +49,7 @@ def _connection_options(*, include_database: bool) -> dict[str, object]:
|
||||
"cursorclass": aiomysql.DictCursor,
|
||||
}
|
||||
if include_database:
|
||||
options["db"] = database
|
||||
options["db"] = control_database
|
||||
return options
|
||||
|
||||
|
||||
@@ -153,3 +153,44 @@ async def get_data_conn(database: str | None = None) -> AsyncIterator[aiomysql.C
|
||||
await conn.select_db(_control_database)
|
||||
except Exception:
|
||||
logger.warning("Failed to reset a Data Center MySQL connection", exc_info=True)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def get_provisioner_conn() -> AsyncIterator[aiomysql.Connection]:
|
||||
"""Open the isolated account-provisioning connection.
|
||||
|
||||
The normal Data Center account must not hold ``CREATE USER`` or ``GRANT
|
||||
OPTION``. This short-lived connection is used only by the admin-only
|
||||
DBeaver issuance and revocation endpoints.
|
||||
"""
|
||||
|
||||
username = settings.data_mysql_provisioner_user.strip()
|
||||
password = settings.data_mysql_provisioner_password
|
||||
if not username or not password:
|
||||
raise DataCenterUnavailable("DBeaver账号签发服务尚未配置")
|
||||
if not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]{0,31}", username):
|
||||
raise ValueError("MySQL账号签发用户名称不合法")
|
||||
|
||||
parsed = urlparse(settings.data_mysql_url)
|
||||
database = unquote(parsed.path.lstrip("/")) or "platform_control"
|
||||
if not _DATABASE_PATTERN.fullmatch(database):
|
||||
raise ValueError("DATA_MYSQL_URL 中的控制数据库名称不合法")
|
||||
conn = await aiomysql.connect(
|
||||
host=parsed.hostname or "localhost",
|
||||
port=parsed.port or 3306,
|
||||
user=username,
|
||||
password=password,
|
||||
charset="utf8mb4",
|
||||
autocommit=False,
|
||||
cursorclass=aiomysql.DictCursor,
|
||||
)
|
||||
try:
|
||||
yield conn
|
||||
except Exception:
|
||||
await conn.rollback()
|
||||
raise
|
||||
finally:
|
||||
try:
|
||||
await conn.rollback()
|
||||
finally:
|
||||
conn.close()
|
||||
Reference in new issue
Block a user