This commit is contained in:
Your Name
2026-04-22 14:13:21 +08:00
parent e0406b5d0e
commit 7cbde2aa78
145 changed files with 23086 additions and 2243 deletions

View File

@@ -39,6 +39,13 @@ CREATE TABLE IF NOT EXISTS ops_managed_nodes (
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS ops_managed_node_secrets (
node_code VARCHAR(64) PRIMARY KEY REFERENCES ops_managed_nodes(node_code) ON DELETE CASCADE,
ssh_password TEXT NOT NULL DEFAULT '',
ssh_private_key TEXT NOT NULL DEFAULT '',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS ops_jobs (
id BIGSERIAL PRIMARY KEY,
job_code VARCHAR(64) NOT NULL UNIQUE,
@@ -321,6 +328,107 @@ def _serialize_node_row(row: tuple) -> dict:
}
def _load_node_secret_flags(node_codes: list[str]) -> dict[str, dict]:
normalized_codes = [str(item or "").strip() for item in node_codes if str(item or "").strip()]
if not normalized_codes:
return {}
result: dict[str, dict] = {}
with get_db() as conn:
with conn.cursor() as cur:
cur.execute(
"""
SELECT node_code, ssh_password, ssh_private_key
FROM ops_managed_node_secrets
WHERE node_code = ANY(%s)
""",
(normalized_codes,),
)
rows = cur.fetchall()
for row in rows:
node_code = str(row[0] or "").strip()
result[node_code] = {
"ssh_password_configured": bool(str(row[1] or "").strip()),
"ssh_private_key_configured": bool(str(row[2] or "").strip()),
}
return result
def _parse_ssh_entry(raw_value: object) -> dict:
raw = str(raw_value or "").strip()
if not raw:
return {}
parts = raw.split(maxsplit=2)
if len(parts) < 2:
return {}
host_port = str(parts[0] or "").strip()
ssh_user = str(parts[1] or "").strip()
secret = str(parts[2] or "").strip() if len(parts) >= 3 else ""
ssh_host = host_port
ssh_port = 22
if ":" in host_port:
host_candidate, port_candidate = host_port.rsplit(":", 1)
if host_candidate and port_candidate.isdigit():
ssh_host = host_candidate
ssh_port = max(int(port_candidate), 1)
if secret.startswith("<") and secret.endswith(">") and len(secret) >= 2:
secret = secret[1:-1].strip()
payload = {
"ssh_host": ssh_host,
"ssh_port": ssh_port,
"ssh_user": ssh_user,
}
if secret:
payload["auth_mode"] = "password"
payload["ssh_password"] = secret
return payload
def _upsert_managed_node_secret(
*,
node_code: str,
ssh_password: str = "",
ssh_private_key: str = "",
clear_ssh_password: bool = False,
clear_ssh_private_key: bool = False,
) -> None:
normalized_node_code = str(node_code or "").strip()
if not normalized_node_code:
return
with get_db() as conn:
with conn.cursor() as cur:
cur.execute(
"""
INSERT INTO ops_managed_node_secrets (
node_code, ssh_password, ssh_private_key, updated_at
) VALUES (%s, %s, %s, CURRENT_TIMESTAMP)
ON CONFLICT (node_code) DO UPDATE SET
ssh_password = CASE
WHEN %s THEN ''
WHEN %s <> '' THEN %s
ELSE ops_managed_node_secrets.ssh_password
END,
ssh_private_key = CASE
WHEN %s THEN ''
WHEN %s <> '' THEN %s
ELSE ops_managed_node_secrets.ssh_private_key
END,
updated_at = CURRENT_TIMESTAMP
""",
(
normalized_node_code,
"" if clear_ssh_password else ssh_password,
"" if clear_ssh_private_key else ssh_private_key,
clear_ssh_password,
ssh_password,
ssh_password,
clear_ssh_private_key,
ssh_private_key,
ssh_private_key,
),
)
conn.commit()
def _pick_text_value(payload: dict, key: str, fallback: str = "", *, default: str = "") -> str:
if key in payload:
normalized = str(payload.get(key) or "").strip()
@@ -397,6 +505,15 @@ def upsert_managed_node(payload: dict) -> tuple[bool, str, dict]:
node_code = str(payload.get("node_code") or "").strip()
if not node_code:
return False, "node_code 不能为空", {}
parsed_ssh_entry = _parse_ssh_entry(payload.get("ssh_entry"))
merged_payload = {
**dict(payload or {}),
**{key: value for key, value in parsed_ssh_entry.items() if value not in ("", None)},
}
ssh_password = str(merged_payload.get("ssh_password") or "").strip()
ssh_private_key = str(merged_payload.get("ssh_private_key") or "")
clear_ssh_password = bool(merged_payload.get("clear_ssh_password", False))
clear_ssh_private_key = bool(merged_payload.get("clear_ssh_private_key", False))
with get_db() as conn:
with conn.cursor() as cur:
@@ -413,22 +530,22 @@ def upsert_managed_node(payload: dict) -> tuple[bool, str, dict]:
existing_row = cur.fetchone()
existing_node = _serialize_node_row(existing_row) if existing_row else {}
existing_metadata = dict(existing_node.get("metadata") or {})
incoming_metadata = dict(payload.get("metadata") or {})
incoming_metadata = dict(merged_payload.get("metadata") or {})
region = _pick_text_value(payload, "region", str(existing_node.get("region") or ""), default="unknown") or "unknown"
role = _pick_text_value(payload, "role", str(existing_node.get("role") or ""), default="worker") or "worker"
title = _pick_text_value(payload, "title", str(existing_node.get("title") or ""), default=node_code) or node_code
ssh_host = _pick_text_value(payload, "ssh_host", str(existing_node.get("ssh_host") or ""))
ssh_port = _pick_int_value(payload, "ssh_port", int(existing_node.get("ssh_port") or 22), default=22, minimum=1)
ssh_user = _pick_text_value(payload, "ssh_user", str(existing_node.get("ssh_user") or ""))
auth_mode = _pick_text_value(payload, "auth_mode", str(existing_node.get("auth_mode") or ""), default="key") or "key"
region = _pick_text_value(merged_payload, "region", str(existing_node.get("region") or ""), default="unknown") or "unknown"
role = _pick_text_value(merged_payload, "role", str(existing_node.get("role") or ""), default="worker") or "worker"
title = _pick_text_value(merged_payload, "title", str(existing_node.get("title") or ""), default=node_code) or node_code
ssh_host = _pick_text_value(merged_payload, "ssh_host", str(existing_node.get("ssh_host") or ""))
ssh_port = _pick_int_value(merged_payload, "ssh_port", int(existing_node.get("ssh_port") or 22), default=22, minimum=1)
ssh_user = _pick_text_value(merged_payload, "ssh_user", str(existing_node.get("ssh_user") or ""))
auth_mode = _pick_text_value(merged_payload, "auth_mode", str(existing_node.get("auth_mode") or ""), default="key") or "key"
deploy_channel = _pick_text_value(
payload,
merged_payload,
"deploy_channel",
str(existing_node.get("deploy_channel") or ""),
default="stable",
) or "stable"
is_enabled = bool(payload["is_enabled"]) if "is_enabled" in payload else bool(existing_node.get("is_enabled", True))
is_enabled = bool(merged_payload["is_enabled"]) if "is_enabled" in merged_payload else bool(existing_node.get("is_enabled", True))
metadata = {
**existing_metadata,
**incoming_metadata,
@@ -469,7 +586,16 @@ def upsert_managed_node(payload: dict) -> tuple[bool, str, dict]:
)
row = cur.fetchone()
conn.commit()
return True, "托管节点已保存", {"node": _serialize_node_row(row)}
_upsert_managed_node_secret(
node_code=node_code,
ssh_password=ssh_password,
ssh_private_key=ssh_private_key,
clear_ssh_password=clear_ssh_password,
clear_ssh_private_key=clear_ssh_private_key,
)
node = _serialize_node_row(row)
node.update(_load_node_secret_flags([node_code]).get(node_code, {}))
return True, "托管节点已保存", {"node": node}
def list_managed_nodes() -> list[dict]:
@@ -485,7 +611,11 @@ def list_managed_nodes() -> list[dict]:
"""
)
rows = cur.fetchall()
return [_serialize_node_row(row) for row in rows]
items = [_serialize_node_row(row) for row in rows]
secret_flags = _load_node_secret_flags([str(item.get("node_code") or "") for item in items])
for item in items:
item.update(secret_flags.get(str(item.get("node_code") or "").strip(), {}))
return items
def sync_managed_nodes_from_cluster(*, dry_run: bool = False) -> dict: