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:
1 parent
1836c5af32
commit
c904ae9358
6 files changed
+157
-29
No files matched your search
+47
-3
@@ -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 再起新
|
||||
|
||||
+23
-16
@@ -231,19 +231,24 @@ def _apply_seed_extras(seed_dir: str, user_data: str,
|
||||
return user_data
|
||||
|
||||
|
||||
def _insert_guest_env_entry(user_data: str, merged_env: dict,
|
||||
ssh_user: str | None) -> str:
|
||||
def _insert_guest_env_entry(user_data: str, merged_env: dict) -> str:
|
||||
"""把 guest-env 条目并进 user-data 已有的 write_files
|
||||
列表(绝不再写一个 write_files: 键,见 _guest_env_entry)。
|
||||
owner:SSH 用户非 root 时写 "<用户>:<用户>"(0600 不变),
|
||||
否则 root:root。条目插在 runcmd 段之前、仍属同一
|
||||
write_files 列表(seed 自 2026-11-07 起不再带 runcmd,
|
||||
见 build_seed_user_data 的根因禁令;marker 分支只作
|
||||
防御,将来模板若恢复 runcmd 仍插在其前)。"""
|
||||
owner = "root:root"
|
||||
if ssh_user and ssh_user != "root":
|
||||
owner = "%s:%s" % (ssh_user, ssh_user)
|
||||
lines = _guest_env_entry(merged_env, owner=owner)
|
||||
owner 恒为 root:root——V-9 真机根因(2026-11-07):
|
||||
cloud-init 的 config 阶段里 write_files 在 users-groups
|
||||
之前跑,owner 写 chv:chv 时 getpwnam('chv') 尚不存在,
|
||||
整个 write_files 模块失败(cloud-init.log:
|
||||
OSError('Unknown user or group: "getpwnam(): name not
|
||||
found: \'chv\'"')),guest-env 文件根本不产生(host
|
||||
key 两条 root:root 的条目在前、已写入,所以 PUBKEY-MATCH
|
||||
仍 True——只看钉死匹配会漏判此缺陷)。文件改归实际读
|
||||
它的 SSH 用户,由客内 final 阶段的 99-chv-sync.cfg
|
||||
runcmd 在 chv-sync boot 之前 chown(用户那时已建好),
|
||||
见 chv-guest/build.sh。条目插在 runcmd 段之前、仍属
|
||||
同一 write_files 列表(seed 自 2026-11-07 起不再带
|
||||
runcmd,见 build_seed_user_data 的根因禁令;marker
|
||||
分支只作防御,将来模板若恢复 runcmd 仍插在其前)。"""
|
||||
lines = _guest_env_entry(merged_env, owner="root:root")
|
||||
marker = "runcmd:\n"
|
||||
if marker in user_data:
|
||||
head, tail = user_data.split(marker, 1)
|
||||
@@ -268,9 +273,12 @@ def write_seed(seed_dir: str, vm_name: str, private_key_text: str,
|
||||
装 boot 时要用的非密钥同步变量(GITEA_URL 等,见
|
||||
gitea_sync):只走 SSH 前缀到不了 cloud-init 时运行
|
||||
的 chv-sync boot。两者皆空时不写该条目。
|
||||
ssh_user:远程 shell 的用户;非 root 时 guest-env 条目
|
||||
owner 写 "<用户>:<用户>"(0600 不变),否则该用户读
|
||||
不到文件(V-4);root/未给时仍 root:root。
|
||||
ssh_user:远程 shell 的用户。guest-env 条目 owner 恒为
|
||||
root:root(V-9 根因:write_files 在 users-groups 之前跑,
|
||||
owner 写非 root 用户时该用户尚不存在、整个模块失败),
|
||||
文件改归 SSH 用户由客内 final 阶段 99-chv-sync.cfg
|
||||
runcmd 在 chv-sync boot 之前 chown,见
|
||||
_insert_guest_env_entry 与 chv-guest/build.sh。
|
||||
user_data_extra / network_config 见 _apply_seed_extras
|
||||
(客机用户与静态网络的供给,皆空即不写)。"""
|
||||
os.makedirs(seed_dir, exist_ok=True)
|
||||
@@ -288,8 +296,7 @@ def write_seed(seed_dir: str, vm_name: str, private_key_text: str,
|
||||
merged_env = dict(guest_env or {})
|
||||
merged_env.update(secret_env or {})
|
||||
if merged_env:
|
||||
user_data = _insert_guest_env_entry(
|
||||
user_data, merged_env, ssh_user)
|
||||
user_data = _insert_guest_env_entry(user_data, merged_env)
|
||||
user_data = _apply_seed_extras(seed_dir, user_data,
|
||||
user_data_extra, network_config)
|
||||
atomic_write_text(user_path, user_data)
|
||||
|
||||
Reference in new issue
Block a user