feat(chv-guest): seed 附加项供客机用户与静态网络(wake 路径前置)
wake_vm 在 WSL 台架上跑通需要客机身份与网络:镜像本身不建 用户、tap 无 DHCP,缺 users 块的 VM 登不进去、缺 network-config 的 VM 拿不到静态 IP。最小补法(复用 write_seed 机制): - hostkeys.write_seed 新增 user_data_extra(原样追加进 user-data,供 users: 块)与 network_config(写 seed network-config 文件,0600);附加项含 runcmd: 即 ValueError - config _seed_fragment:CHV_SEED_USER_DATA_EXTRA_FILE / CHV_SEED_NETWORK_CONFIG_FILE(只存路径) - executor._seed_extras 在 wake 起 VMM 前读入,缺失即 ChvFailure seed_extra_missing;provision_host_key 透传 - README §7 残留更新:guest-env 集成已做 - 测试:test_chv_gitea_sync 新增 5 项(写盘/禁 runcmd/ 配置映射/wake 带附加项/缺失 fail-closed)
This commit is contained in:
1 parent
e7f699c62b
commit
d7cc482ed5
5 files changed
+184
-11
No files matched your search
+40
-6
@@ -400,7 +400,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
"single_tenant_project", "snapshot_max_count",
|
||||
"snapshot_max_total_gb", "snapshot_retention_days",
|
||||
"snapshot_dir", "allow_remote_snapshot",
|
||||
"gitea_sync_env"):
|
||||
"gitea_sync_env", "seed_user_data_extra_file",
|
||||
"seed_network_config_file"):
|
||||
setattr(self, _field, getattr(_cfg, _field))
|
||||
|
||||
# -- 名字 / 路径 ---------------------------------------------------
|
||||
@@ -830,7 +831,9 @@ class CloudHypervisorExecutor(Executor):
|
||||
host=ssh_host)])
|
||||
|
||||
def provision_host_key(self, task: dict, secret_env: dict | None = None,
|
||||
guest_env: dict | None = None) -> dict:
|
||||
guest_env: dict | None = None,
|
||||
user_data_extra: str | None = None,
|
||||
network_config: str | None = None) -> dict:
|
||||
"""按 VM 预置 host key(补缺口轨强方案,见 hostkeys.py):
|
||||
启动前为该 VM 生成一次性 ed25519 host key 对,公钥
|
||||
立即写进该 VM 的 known_hosts(钉死),私钥只写进
|
||||
@@ -868,7 +871,9 @@ class CloudHypervisorExecutor(Executor):
|
||||
seed_dir = write_seed(paths["seed_dir"], vm,
|
||||
private_text, public_text,
|
||||
secret_env=secret_env,
|
||||
guest_env=guest_env)
|
||||
guest_env=guest_env,
|
||||
user_data_extra=user_data_extra,
|
||||
network_config=network_config)
|
||||
self._emit("host_key_generated", task,
|
||||
"vm=%s secret_names=%s"
|
||||
% (vm, ",".join(sorted(secret_env or {}))))
|
||||
@@ -1311,6 +1316,30 @@ class CloudHypervisorExecutor(Executor):
|
||||
"VMM api-socket 组/其它可写(%o),拒绝启动:%s"
|
||||
% (mode, socket_path))
|
||||
|
||||
def _seed_extras(self) -> tuple:
|
||||
"""读 seed 附加项文件(CHV_SEED_* 配置的路径):
|
||||
返回 (user_data_extra, network_config),皆空即
|
||||
(None, None)。路径已配但文件缺失/读不出时
|
||||
ChvFailure(seed_extra_missing),wake 在起 VMM
|
||||
之前拒绝——缺 users 块的 VM 起了也登不进去,缺
|
||||
network-config 的 VM 在无 DHCP 的 tap 上拿不到 IP,
|
||||
不如不起。错误只含路径,不含文件内容。"""
|
||||
out = []
|
||||
for attr in ("seed_user_data_extra_file",
|
||||
"seed_network_config_file"):
|
||||
path = getattr(self, attr, None)
|
||||
if not path:
|
||||
out.append(None)
|
||||
continue
|
||||
try:
|
||||
with open(path) as fh:
|
||||
out.append(fh.read())
|
||||
except OSError as exc:
|
||||
raise ChvFailure(
|
||||
"seed_extra_missing",
|
||||
"seed 附加文件读不出:%s:%s" % (path, exc))
|
||||
return out[0], out[1]
|
||||
|
||||
def _effective_extra_env(self, task: dict,
|
||||
extra_env: dict | None) -> dict | None:
|
||||
"""wake 生效的 extra_env:把 Gitea 同步变量并进来。
|
||||
@@ -1381,7 +1410,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
return secrets, net_entries
|
||||
|
||||
def _provision_seed_disk(self, task: dict, name: str, secrets,
|
||||
guest_env: dict | None = None) -> str | None:
|
||||
guest_env: dict | None = None,
|
||||
seed_extras: tuple | None = None) -> str | None:
|
||||
"""provisioned 模式的 seed 盘供给:生成→制盘→挂盘,
|
||||
任一步失败即抛(调用方 stop_vm 清理),纯移动。"""
|
||||
seed_disk = None
|
||||
@@ -1403,9 +1433,11 @@ class CloudHypervisorExecutor(Executor):
|
||||
delete_host_private_key,
|
||||
seed_disk_path,
|
||||
)
|
||||
extra, netcfg = seed_extras or (None, None)
|
||||
provisioned = self.provision_host_key(
|
||||
task, secret_env=secrets or None,
|
||||
guest_env=guest_env or None)
|
||||
guest_env=guest_env or None,
|
||||
user_data_extra=extra, network_config=netcfg)
|
||||
seed_disk = seed_disk_path(self.state_dir, name)
|
||||
build_seed_disk(
|
||||
provisioned["seed_dir"], seed_disk,
|
||||
@@ -1487,6 +1519,7 @@ class CloudHypervisorExecutor(Executor):
|
||||
name = self.vm_name(task)
|
||||
try:
|
||||
extra_env = self._effective_extra_env(task, extra_env)
|
||||
seed_extras = self._seed_extras()
|
||||
except ChvFailure as exc:
|
||||
self._emit("vm_failed", task,
|
||||
"vm=%s wake 失败 kind=%s" % (name, exc.kind),
|
||||
@@ -1497,7 +1530,8 @@ class CloudHypervisorExecutor(Executor):
|
||||
task_disk, socket_path = self._wake_prepare(task, name)
|
||||
try:
|
||||
seed_disk = self._provision_seed_disk(
|
||||
task, name, secrets, guest_env=guest_env or None)
|
||||
task, name, secrets, guest_env=guest_env or None,
|
||||
seed_extras=seed_extras)
|
||||
self._boot_vm(task, name, task_disk, seed_disk, net_entries)
|
||||
except Exception:
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user