feat(chv-guest): Gitea 同步变量经 seed 进 guest-env(执行器集成)
- 新增 cloud/chv/gitea_sync.py:6 键白名单,三源合并 (宿主 CHV_GITEA_* < 任务 gitea_sync < extra_env), 必填 4 键缺失即 fail-closed,空即不同步 - ssh_transport:GITEA_TOKEN 进密钥集(argv 拒绝),其余 5 键进 guest-env 集(split_guest_env) - hostkeys.write_seed:guest_env 与 secret_env 合并写同一 条目,仍无 runcmd、0600 - config:_gitea_fragment 产 gitea_sync_env(函数内 import, 叶子模块顶层只许标准库) - executor.wake_vm:起 VMM 前合并+校验(gitea_sync_incomplete), guest-env 随 seed 投递;provision_host_key 透传 guest_env - worker:_run_attempt 仅对 CHV 执行器把同步变量并进 gateway_env - 测试:cloud/tests/test_chv_gitea_sync.py 20 项 - 边界:tasks 表无 JSON 列,DB 往返丢任务 gitea_sync; 生产主来源是宿主 CHV_GITEA_* 环境变量
This commit is contained in:
1 parent
67ca0b86cd
commit
e7f699c62b
7 files changed
+785
-37
No files matched your search
+55
-7
@@ -59,6 +59,7 @@ from cloud.chv.ssh_transport import build_ssh_command as _build_ssh_cmd
|
||||
from cloud.chv.ssh_transport import known_hosts_path as _known_hosts_path
|
||||
from cloud.chv.ssh_transport import (
|
||||
parse_keyscan_output,
|
||||
split_guest_env,
|
||||
split_secret_env,
|
||||
write_known_hosts,
|
||||
)
|
||||
@@ -398,7 +399,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
"ssh_forward", "reuse_experiment",
|
||||
"single_tenant_project", "snapshot_max_count",
|
||||
"snapshot_max_total_gb", "snapshot_retention_days",
|
||||
"snapshot_dir", "allow_remote_snapshot"):
|
||||
"snapshot_dir", "allow_remote_snapshot",
|
||||
"gitea_sync_env"):
|
||||
setattr(self, _field, getattr(_cfg, _field))
|
||||
|
||||
# -- 名字 / 路径 ---------------------------------------------------
|
||||
@@ -827,7 +829,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
[known_hosts_line(self.ssh_port, public_text,
|
||||
host=ssh_host)])
|
||||
|
||||
def provision_host_key(self, task: dict, secret_env: dict | None = None) -> dict:
|
||||
def provision_host_key(self, task: dict, secret_env: dict | None = None,
|
||||
guest_env: dict | None = None) -> dict:
|
||||
"""按 VM 预置 host key(补缺口轨强方案,见 hostkeys.py):
|
||||
启动前为该 VM 生成一次性 ed25519 host key 对,公钥
|
||||
立即写进该 VM 的 known_hosts(钉死),私钥只写进
|
||||
@@ -837,7 +840,9 @@ class CloudHypervisorExecutor(Executor):
|
||||
不同 VM 的 key 对不同(state_dir/<vm> 隔离),同一
|
||||
VM 重启复用已有对(否则钉死立即失效)。
|
||||
feat-chv-secfix(H2/M2):secret_env 给定时写进
|
||||
seed 的客内密钥文件(0600);上次清理失败留下的
|
||||
seed 的客内密钥文件(0600);guest_env 给定时与
|
||||
secret_env 合并写同一客内文件(boot 时要用的非密钥
|
||||
同步变量,见 gitea_sync);上次清理失败留下的
|
||||
脏标记存在时直接拒绝(清理失败即拒起,不再复用
|
||||
旧 key 对)。成功后审计 host_key_generated(只含
|
||||
VM 名与密钥名,不含任何 key 值)。"""
|
||||
@@ -862,7 +867,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
self._write_provisioned_known_hosts(paths, public_text)
|
||||
seed_dir = write_seed(paths["seed_dir"], vm,
|
||||
private_text, public_text,
|
||||
secret_env=secret_env)
|
||||
secret_env=secret_env,
|
||||
guest_env=guest_env)
|
||||
self._emit("host_key_generated", task,
|
||||
"vm=%s secret_names=%s"
|
||||
% (vm, ",".join(sorted(secret_env or {}))))
|
||||
@@ -1305,6 +1311,37 @@ class CloudHypervisorExecutor(Executor):
|
||||
"VMM api-socket 组/其它可写(%o),拒绝启动:%s"
|
||||
% (mode, socket_path))
|
||||
|
||||
def _effective_extra_env(self, task: dict,
|
||||
extra_env: dict | None) -> dict | None:
|
||||
"""wake 生效的 extra_env:把 Gitea 同步变量并进来。
|
||||
|
||||
优先级(低→高):执行器宿主配置 CHV_GITEA_*(构造时
|
||||
已映射成 gitea_sync_env)< 任务 dict 的 gitea_sync <
|
||||
显式 extra_env 同名键(见 gitea_sync.extract_...)。
|
||||
同步已请求(任一同步键出现)但必填键不全时,在起
|
||||
VMM 之前就 ChvFailure(gitea_sync_incomplete,
|
||||
fail-closed;错误只含缺失键名,不含值)——半份同步
|
||||
配置绝不能让 VM 带着“以为同步了”的状态启动。无同步
|
||||
变量时原样返回(本次启动不同步)。
|
||||
必须在 _wake_prechecks 之前调:任务/配置来源的
|
||||
GITEA_TOKEN 也要受 keyscan 模式 fail-closed 检查。"""
|
||||
from cloud.chv.gitea_sync import (
|
||||
extract_gitea_sync_env,
|
||||
validate_gitea_sync_env,
|
||||
)
|
||||
sync = extract_gitea_sync_env(
|
||||
task=task, extra_env=extra_env,
|
||||
config_sync=getattr(self, "gitea_sync_env", None))
|
||||
try:
|
||||
validate_gitea_sync_env(sync)
|
||||
except ValueError as exc:
|
||||
raise ChvFailure("gitea_sync_incomplete", str(exc))
|
||||
if not sync:
|
||||
return extra_env
|
||||
merged = dict(extra_env or {})
|
||||
merged.update(sync)
|
||||
return merged
|
||||
|
||||
def _wake_prechecks(self, task: dict, name: str, extra_env) -> tuple:
|
||||
"""wake 前置:preflight/容量/配额/net/密钥模式,纯移动。
|
||||
失败时发 vm_failed 审计并原样抛 ChvFailure。"""
|
||||
@@ -1343,7 +1380,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
raise
|
||||
return secrets, net_entries
|
||||
|
||||
def _provision_seed_disk(self, task: dict, name: str, secrets) -> str | None:
|
||||
def _provision_seed_disk(self, task: dict, name: str, secrets,
|
||||
guest_env: dict | None = None) -> str | None:
|
||||
"""provisioned 模式的 seed 盘供给:生成→制盘→挂盘,
|
||||
任一步失败即抛(调用方 stop_vm 清理),纯移动。"""
|
||||
seed_disk = None
|
||||
@@ -1366,7 +1404,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
seed_disk_path,
|
||||
)
|
||||
provisioned = self.provision_host_key(
|
||||
task, secret_env=secrets or None)
|
||||
task, secret_env=secrets or None,
|
||||
guest_env=guest_env or None)
|
||||
seed_disk = seed_disk_path(self.state_dir, name)
|
||||
build_seed_disk(
|
||||
provisioned["seed_dir"], seed_disk,
|
||||
@@ -1446,10 +1485,19 @@ class CloudHypervisorExecutor(Executor):
|
||||
if not isinstance(task, dict) or task.get("id") is None:
|
||||
raise ValueError("任务缺少 id")
|
||||
name = self.vm_name(task)
|
||||
try:
|
||||
extra_env = self._effective_extra_env(task, extra_env)
|
||||
except ChvFailure as exc:
|
||||
self._emit("vm_failed", task,
|
||||
"vm=%s wake 失败 kind=%s" % (name, exc.kind),
|
||||
exc.kind)
|
||||
raise
|
||||
secrets, net_entries = self._wake_prechecks(task, name, extra_env)
|
||||
guest_env, _plain = split_guest_env(extra_env)
|
||||
task_disk, socket_path = self._wake_prepare(task, name)
|
||||
try:
|
||||
seed_disk = self._provision_seed_disk(task, name, secrets)
|
||||
seed_disk = self._provision_seed_disk(
|
||||
task, name, secrets, guest_env=guest_env or None)
|
||||
self._boot_vm(task, name, task_disk, seed_disk, net_entries)
|
||||
except Exception:
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user