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:
host committed 2026-11-06 16:58:27 +00:00
1 parent e7f699c62b
commit d7cc482ed5
5 files changed
+184 -11

No files matched your search

+37 -2
View File
@@ -185,10 +185,41 @@ def _guest_env_entry(merged_env: dict) -> list:
return lines
def _apply_seed_extras(seed_dir: str, user_data: str,
user_data_extra: str | None,
network_config: str | None) -> str:
"""seed 可选附加项(执行器 wake 路径的客机身份/网络供给):
user_data_extra 原样追加进 user-data(调用方用它供
`users:` 块——chv 用户 + authorized_keys,镜像本身不
建用户);network_config 写成 seed 目录的 network-config
文件(NoCloud 静态 IP,tap 无 DHCP 时客机才有地址)。
两者皆空即原样返回。user_data_extra 里含 runcmd: 行即
ValueError——seed 禁 runcmd 是 2026-11-06 根因禁令,
附加项也不得绕过(镜像的 99-chv-sync.cfg 靠它活着)。"""
if user_data_extra:
for line in user_data_extra.splitlines():
if line.strip().startswith("runcmd:"):
raise ValueError(
"seed 附加 user-data 里不得带 runcmd:")
if not user_data.endswith("\n"):
user_data += "\n"
user_data += user_data_extra
if not user_data.endswith("\n"):
user_data += "\n"
if network_config:
net_path = os.path.join(seed_dir, "network-config")
with open(net_path, "w") as fh:
fh.write(network_config)
os.chmod(net_path, 0o600)
return user_data
def write_seed(seed_dir: str, vm_name: str, private_key_text: str,
public_key_text: str,
secret_env: dict | None = None,
guest_env: dict | None = None) -> str:
guest_env: dict | None = None,
user_data_extra: str | None = None,
network_config: str | None = None) -> str:
"""写 seed 目录:meta-data + user-data(均为 0600),
返回 seed 目录路径。调用方负责随 VM 销毁删掉它。
@@ -198,7 +229,9 @@ def write_seed(seed_dir: str, vm_name: str, private_key_text: str,
个条目(secret 优先于同名键,防两行同名);guest_env
装 boot 时要用的非密钥同步变量(GITEA_URL 等,见
gitea_sync):只走 SSH 前缀到不了 cloud-init 时运行
的 chv-sync boot。两者皆空时不写该条目。"""
的 chv-sync boot。两者皆空时不写该条目。
user_data_extra / network_config 见 _apply_seed_extras
(客机用户与静态网络的供给,皆空即不写)。"""
os.makedirs(seed_dir, exist_ok=True)
meta_path = os.path.join(seed_dir, "meta-data")
user_path = os.path.join(seed_dir, "user-data")
@@ -221,6 +254,8 @@ def write_seed(seed_dir: str, vm_name: str, private_key_text: str,
user_data = head + "\n".join(lines) + "\n" + marker + tail
else:
user_data = user_data + "\n".join(lines) + "\n"
user_data = _apply_seed_extras(seed_dir, user_data,
user_data_extra, network_config)
with open(user_path, "w") as fh:
fh.write(user_data)
os.chmod(user_path, 0o600)