carry-over: 在途 V-9 根因修复 + Muse P2 对齐原样带入(未改一行业务逻辑)

来源:feat-chv-muse-p2 @ c918d69 的 6 个未提交文件(+157/-29):
build.sh(GT 哈希轮换 + 99-chv-sync.cfg runcmd chown)、
check_lockfile.py / generate_lockfile.py(DECLARED_SOURCES 加
chv-cell/chv-broker/chv-browser)、executor.py(_wait_guest_env_usable)、
hostkeys.py(guest-env owner 恒 root:root)、test_chv_v3_fixes.py。
单测:python3 -m unittest cloud.tests.test_chv_v3_fixes 38/38 通过。
本提交只搬运,不含阶段 1 改动;阶段 1 另起提交。
This commit is contained in:
host committed 2026-11-08 09:45:00 +00:00
1 parent 1836c5af32
commit c904ae9358
6 files changed
+157 -29

No files matched your search

+47 -3
View File
@@ -1461,6 +1461,43 @@ class CloudHypervisorExecutor(Executor):
"guest SSH 就绪超时:%d 次轮询内 sshd 未通,已关 VM"
% attempts)
def _wait_guest_env_usable(self, task: dict) -> None:
"""密钥已投递时,等客内 guest-env 对 SSH 用户可读再返回:
write_files 以 root:root 写文件(见 hostkeys.py——
write_files 在 users-groups 之前跑,owner 只能写 root),
客内 final 阶段的 99-chv-sync.cfg runcmd 才 chown 给
SSH 用户;SSH 就绪(vm_ready)比 final 阶段早约 30 秒
(V-9 真机:runcmd 脚本在 vm_ready 后约 31 秒才执行),
派发若在这窗口内 source 文件会 Permission denied。
判定用 `test -r`(SSH 用户本人可读与否,正是派发
source 的前置条件),不比对 owner 名。无密钥投递时
不等待、不轮询。超时先关 VM 再抛 guest_env_not_ready,
绝不带着读不到的密钥去跑任务。"""
if not self._delivered_secrets(self.vm_name(task)):
return
from cloud.chv.hostkeys import GUEST_ENV_PATH
attempts = max(1, int(self.ready_timeout / self.ready_interval))
for attempt in range(attempts):
try:
result = self._call_runner(self.build_ssh_command(
task, ["test", "-r", GUEST_ENV_PATH]))
except Exception:
result = None
if (result is not None
and getattr(result, "returncode", 1) == 0):
return
if attempt + 1 < attempts:
self.sleeper(self.ready_interval)
try:
self.stop_vm(task)
except Exception:
pass
raise ChvFailure(
"guest_env_not_ready",
"guest-env 在 %d 次轮询内仍对 SSH 用户不可读,已关 VM:"
"runcmd chown 未生效或 cloud-init 未完成"
% attempts)
def _guest_host_command(self, *args, model=None, effort=None,
approval=None, sandbox=None,
model_provider=None):
@@ -1722,7 +1759,9 @@ class CloudHypervisorExecutor(Executor):
def _boot_vm(self, task, name, task_disk, seed_disk,
net_entries) -> None:
"""VMM 启动→vm.create→vm.boot→SSH 就绪,纯移动。"""
"""VMM 启动→vm.create→vm.boot→SSH 就绪→密钥已投递时
等 guest-env 对 SSH 用户可读(V-9,见
_wait_guest_env_usable),纯移动。"""
socket_path = self.api_socket(task)
self._launch_api_only(task)
self.wait_api_ready(task)
@@ -1751,6 +1790,9 @@ class CloudHypervisorExecutor(Executor):
"vm.boot 失败:status=%s" % status)
self._emit("vm_boot", task, "vm=%s" % name)
self.wait_guest_ready(task)
# V-9:密钥已投递时等 guest-env 对 SSH 用户可读再报
# 就绪(runcmd chown 比 SSH 就绪晚约 30 秒)。
self._wait_guest_env_usable(task)
def _wake_prepare(self, task: dict, name: str) -> tuple:
"""wake 准备:reuse 审计、旧 VM 清理、任务盘供给、
@@ -1796,8 +1838,10 @@ class CloudHypervisorExecutor(Executor):
preflight → 容量门 → 磁盘配额门 → 每任务磁盘供给 →
launcher 只起 VMM(--api-socket)→ 等 vmm.ping 通 →
PUT vm.create(VmConfig)→ PUT vm.boot → 等 guest
SSH 就绪。任一步失败都关 VM(stop_vm)再抛
ChvFailure,绝不带着半醒的 VM 去跑任务。
SSH 就绪 → 密钥已投递时再等 guest-env 对 SSH 用户可读
(见 _wait_guest_env_usable,V-9)。任一步失败都
关 VM(stop_vm)再抛 ChvFailure,绝不带着半醒的 VM
去跑任务。
成功返回 {vm, api_socket, state: "running", ready: True,
mode: "cold"},并审计 vm_create/vm_boot/vm_ready。
单任务单 VM:同一任务重复 wake 时先关旧 VM 再起新