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
@@ -10,7 +10,10 @@
|
||||
不重应用 = host_key_mismatch);
|
||||
- F2:跨实例 stop 按 socket 进程扫描清未登记 VMM;
|
||||
- V-4:remote_command source 失败 fail-fast(exit 126),
|
||||
guest-env 归 SSH 用户所有;
|
||||
guest-env 归 SSH 用户所有;V-9:owner 恒 root:root(write_files
|
||||
先于建用户)+ 客内 runcmd chown,wake 在密钥投递后等
|
||||
guest-env 对 SSH 用户可读再报 ready(runcmd chown 比 SSH
|
||||
就绪晚约 30 秒),超时关 VM 再抛 guest_env_not_ready;
|
||||
- V-1 附带:build.sh 预建 /app/work(1777 粘滞位 + 断言);
|
||||
- V-1 附带:host.py default_codex_bin() 走 PATH 查找。
|
||||
- V-7 复修(feat-chv-v3-repair):D1 snapshot 先建目录(旧
|
||||
@@ -434,12 +437,14 @@ class GuestEnvV4Test(V3Case):
|
||||
tokens = remote_command(["true"])
|
||||
self.assertEqual(tokens, ["true"])
|
||||
|
||||
def test_write_seed_owner_follows_ssh_user(self):
|
||||
def test_write_seed_guest_env_owner_always_root(self):
|
||||
# V-9 真机根因:write_files 在 users-groups 之前跑,
|
||||
# owner 写 chv:chv 时 getpwnam 失败、整个模块失败,
|
||||
# 文件根本不产生;故 owner 恒为 root:root,改归 SSH
|
||||
# 用户由客内 final 阶段 99-chv-sync.cfg runcmd chown。
|
||||
import yaml
|
||||
for ssh_user, want_owner in (
|
||||
(None, "root:root"), ("root", "root:root"),
|
||||
("chv", "chv:chv")):
|
||||
seed_dir = os.path.join(self.dir, "seed-%s" % want_owner)
|
||||
for ssh_user in (None, "root", "chv"):
|
||||
seed_dir = os.path.join(self.dir, "seed-%s" % ssh_user)
|
||||
write_seed(seed_dir, "vm1", "PRIV",
|
||||
"ssh-ed25519 AAAAx",
|
||||
secret_env={"SUB2API_API_KEY": "s3cr3t"},
|
||||
@@ -449,7 +454,7 @@ class GuestEnvV4Test(V3Case):
|
||||
guest = [e for e in parsed["write_files"]
|
||||
if e["path"] == "/etc/chv/guest-env"]
|
||||
self.assertEqual(len(guest), 1)
|
||||
self.assertEqual(guest[0]["owner"], want_owner)
|
||||
self.assertEqual(guest[0]["owner"], "root:root")
|
||||
self.assertEqual(guest[0]["permissions"], "0600")
|
||||
|
||||
def test_provisioned_wake_writes_guest_env_for_chv_user(self):
|
||||
@@ -467,7 +472,54 @@ class GuestEnvV4Test(V3Case):
|
||||
guest = [e for e in parsed["write_files"]
|
||||
if e["path"] == "/etc/chv/guest-env"]
|
||||
self.assertEqual(len(guest), 1)
|
||||
self.assertEqual(guest[0]["owner"], "chv:chv")
|
||||
# V-9:owner 恒为 root:root(write_files 先于建用户),
|
||||
# 改归 chv 由客内 99-chv-sync.cfg runcmd chown。
|
||||
self.assertEqual(guest[0]["owner"], "root:root")
|
||||
|
||||
def _readable_runner(self, answers):
|
||||
"""Fake runner:`test -r /etc/chv/guest-env` 按 answers
|
||||
依次回可读与否(用完后重复最后一个),其余命令走默认
|
||||
runner。answers 是 bool 列表。"""
|
||||
state = {"n": 0}
|
||||
|
||||
def run(cmd, timeout=None):
|
||||
if ("test" in cmd
|
||||
and cmd[-1] == "/etc/chv/guest-env"):
|
||||
idx = min(state["n"], len(answers) - 1)
|
||||
state["n"] += 1
|
||||
return FakeResult(0 if answers[idx] else 1, "", "")
|
||||
return self._default_runner(cmd, timeout)
|
||||
run.readable_calls = lambda: state["n"]
|
||||
return run
|
||||
|
||||
def test_wake_waits_for_guest_env_readable(self):
|
||||
# V-9:runcmd chown 比 SSH 就绪晚约 30 秒,wake 须等
|
||||
# guest-env 对 SSH 用户可读再报 ready,否则首个派发
|
||||
# source 它即 Permission denied。
|
||||
runner = self._readable_runner([False, False, True])
|
||||
ex = self.make_exec(
|
||||
runner=runner,
|
||||
env_extra={"CHV_HOST_KEY_MODE": "provisioned"},
|
||||
ssh_user="chv")
|
||||
out = ex.wake_vm(self._task(),
|
||||
extra_env={"SUB2API_API_KEY": "s3cr3t"})
|
||||
self.assertEqual(out["state"], "running")
|
||||
self.assertEqual(runner.readable_calls(), 3)
|
||||
|
||||
def test_wake_fails_when_guest_env_never_readable(self):
|
||||
# V-9:guest-env 一直对 SSH 用户不可读时 wake 超时即
|
||||
# 关 VM 再抛 guest_env_not_ready,绝不带着读不到的密钥
|
||||
# 跑任务。
|
||||
runner = self._readable_runner([False])
|
||||
ex = self.make_exec(
|
||||
runner=runner,
|
||||
env_extra={"CHV_HOST_KEY_MODE": "provisioned"},
|
||||
ssh_user="chv")
|
||||
with self.assertRaises(ChvFailure) as ctx:
|
||||
ex.wake_vm(self._task(),
|
||||
extra_env={"SUB2API_API_KEY": "s3cr3t"})
|
||||
self.assertEqual(ctx.exception.kind, "guest_env_not_ready")
|
||||
self.assertGreater(runner.readable_calls(), 1)
|
||||
|
||||
|
||||
# -- V-1 附带:build.sh /app/work + host.py default_codex_bin --------------
|
||||
@@ -478,6 +530,21 @@ class GuestBuildAndHostBinV3Test(unittest.TestCase):
|
||||
self.assertIn("chmod 1777 /app/work", text)
|
||||
self.assertIn('stat -c %a /app/work', text)
|
||||
|
||||
def test_build_sh_runcmd_chowns_guest_env_before_sync_boot(self):
|
||||
# V-9:guest-env 由 write_files 以 root:root 写(建用户
|
||||
# 之前),须在 final 阶段 chv-sync boot 之前改归 chv,
|
||||
# 否则 SSH 派发 source 它会 Permission denied;无文件
|
||||
# 时 test -f 护栏使该行空操作,runcmd 失败不影响启动。
|
||||
text = (ROOT / "chv-guest" / "build.sh").read_text()
|
||||
chown = ("test -f /etc/chv/guest-env && "
|
||||
"chown chv:chv /etc/chv/guest-env || true")
|
||||
self.assertIn(chown, text)
|
||||
# "chv-sync boot" 在文件前部注释里先出现过一次,故从
|
||||
# chown 位置往后找同一 runcmd 行里的 boot。
|
||||
chown_at = text.index(chown)
|
||||
boot_at = text.index("/usr/local/bin/chv-sync boot", chown_at)
|
||||
self.assertLess(chown_at, boot_at)
|
||||
|
||||
def test_build_sh_dry_run_prints_app_work_step(self):
|
||||
tmp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(tmp.cleanup)
|
||||
|
||||
Reference in new issue
Block a user