fix(chv): CHV 54 VmConfig 形态——payload.kernel/cmdline 纯字符串 + 磁盘显式 image_type Raw
真机 CHV 54.0.0 实测:旧顶层 kernel:{path}/cmdline:{args}
create 时 204 照放、vm.boot 400 'No bootitem provided';
补 payload 后又报 'Image type required for disk'(raw 盘
无魔数、探测失败),磁盘须显式 image_type,枚举原名
Raw(JSON 写小写 raw 报 unknown variant)。
This commit is contained in:
1 parent
5b6514d019
commit
4f3a176771
4 files changed
+38
-12
No files matched your search
+26
-7
@@ -965,7 +965,14 @@ class CloudHypervisorExecutor(Executor):
|
||||
"""VmConfig 磁盘列表(to10 提取,含 L2 白名单校验)。
|
||||
任务盘 + 可选 seed 只读盘(CIDATA ISO,cloud-init
|
||||
NoCloud 数据源);显式给的盘若不是基础镜像本身,
|
||||
须在 state_dir 内,否则 VmConfig 不能挂进宿主任意文件。"""
|
||||
须在 state_dir 内,否则 VmConfig 不能挂进宿主任意文件。
|
||||
image_type 必须显式给 Raw:CHV 54 的磁盘类型靠文件
|
||||
魔数探测,raw 盘无魔数、探测失败即 vm.boot 400
|
||||
"Image type required for disk"(2026-11-07 WSL 真机
|
||||
CHV 54.0.0 实测);值须是枚举原名 Raw(CLI 的小写
|
||||
raw 是另一层映射,JSON 里写 raw 会报 unknown variant);
|
||||
CLI 各轮一直传 image_type=raw(seed ISO 亦然,客内
|
||||
仍以 /dev/vdb 读到 CIDATA)。"""
|
||||
# 旧文案逐字保留:任务盘“任务磁盘须在…”,seed 盘
|
||||
# “seed 磁盘须在…”(label 本身含“磁盘”与空格)。
|
||||
for path, label in ((task_disk, "任务磁盘"),
|
||||
@@ -976,28 +983,40 @@ class CloudHypervisorExecutor(Executor):
|
||||
raise ChvFailure(
|
||||
"disk_path_not_allowed",
|
||||
"%s须在 state_dir 内:%s" % (label, path))
|
||||
disks: list = [{"path": task_disk or self.rootfs}]
|
||||
disks: list = [{"path": task_disk or self.rootfs,
|
||||
"image_type": "Raw"}]
|
||||
if seed_disk:
|
||||
disks.append({"path": seed_disk, "readonly": True})
|
||||
disks.append({"path": seed_disk, "readonly": True,
|
||||
"image_type": "Raw"})
|
||||
return disks
|
||||
|
||||
def build_vm_config(self, task_disk: str | None = None, seed_disk: str | None = None) -> dict:
|
||||
"""API 模式的 VmConfig(vm.create 请求体,纯函数):
|
||||
cpus{boot_vcpus,max_vcpus}、memory{size: 字节}、
|
||||
kernel{path}、cmdline{args}、disks[{path: 每任务磁盘}]、
|
||||
payload{kernel, cmdline}、disks[{path: 每任务磁盘}]、
|
||||
rng{/dev/urandom},以及 CHV_NET_JSON 给出的 net 列表
|
||||
(不给则不带 net——客机无网卡时 SSH 就绪会超时失败,
|
||||
这是 fail-fast 前置条件,见类 docstring)。
|
||||
task_disk 不给时用基础镜像路径(仅 lab/reuse 模式)。"""
|
||||
task_disk 不给时用基础镜像路径(仅 lab/reuse 模式)。
|
||||
payload 形态(CHV 54 API):内核与命令行须放在
|
||||
payload 对象里(kernel/cmdline 均为直接字符串),
|
||||
旧版顶层 kernel{path}/cmdline{args} 会被服务端忽略,
|
||||
vm.create 照常 204、vm.boot 报 400 "No bootitem
|
||||
provided: neither firmware nor kernel"(2026-11-07
|
||||
WSL 真机 CHV 54.0.0 实测)。"""
|
||||
try:
|
||||
cpus = int(self.cpus)
|
||||
except ValueError:
|
||||
raise ValueError("CHV_CPU 必须是整数:%r" % (self.cpus,))
|
||||
payload: dict = {}
|
||||
if self.kernel:
|
||||
payload["kernel"] = self.kernel
|
||||
if self.cmdline:
|
||||
payload["cmdline"] = self.cmdline
|
||||
config = {
|
||||
"cpus": {"boot_vcpus": cpus, "max_vcpus": cpus},
|
||||
"memory": {"size": _parse_memory_bytes(self.memory)},
|
||||
"kernel": {"path": self.kernel},
|
||||
"cmdline": {"args": self.cmdline},
|
||||
"payload": payload,
|
||||
"disks": self._vm_config_disks(task_disk, seed_disk),
|
||||
"rng": {"src": "/dev/urandom"},
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class Arch95Case(unittest.TestCase):
|
||||
"第一盘必须是任务盘")
|
||||
self.assertTrue(disks[1].endswith("seed.iso"),
|
||||
"第二盘必须是 seed 盘,缺 seed 即假保证")
|
||||
self.assertTrue(payload.get("kernel", {}).get("path"))
|
||||
self.assertTrue(payload.get("payload", {}).get("kernel"))
|
||||
nets = payload.get("net", [])
|
||||
taps = [n.get("tap") for n in nets]
|
||||
self.assertEqual(len(taps), len(set(taps)), "net tap 重复")
|
||||
|
||||
@@ -158,6 +158,9 @@ class SeedDiskTest(ChvFixCase):
|
||||
self.assertEqual(len(cfg["disks"]), 2)
|
||||
self.assertEqual(cfg["disks"][1]["path"], seed)
|
||||
self.assertTrue(cfg["disks"][1]["readonly"])
|
||||
# CHV 54 要求磁盘显式 image_type(缺了 vm.boot 400)。
|
||||
self.assertEqual(cfg["disks"][0]["image_type"], "Raw")
|
||||
self.assertEqual(cfg["disks"][1]["image_type"], "Raw")
|
||||
cfg2 = ex.build_vm_config(disk)
|
||||
self.assertEqual(len(cfg2["disks"]), 1)
|
||||
|
||||
|
||||
@@ -243,9 +243,10 @@ class ConfigCommandTest(ChvCase):
|
||||
self.assertEqual(cfg["cpus"], {"boot_vcpus": 2,
|
||||
"max_vcpus": 2})
|
||||
self.assertEqual(cfg["memory"]["size"], 2 * 1024 ** 3)
|
||||
self.assertEqual(cfg["kernel"]["path"], self.kernel)
|
||||
self.assertEqual(cfg["disks"], [{"path": disk}])
|
||||
self.assertEqual(cfg["cmdline"]["args"],
|
||||
self.assertEqual(cfg["payload"]["kernel"], self.kernel)
|
||||
self.assertEqual(cfg["disks"],
|
||||
[{"path": disk, "image_type": "Raw"}])
|
||||
self.assertEqual(cfg["payload"]["cmdline"],
|
||||
"console=hvc0 root=/dev/vda1 rw")
|
||||
|
||||
def test_memory_parsing(self):
|
||||
@@ -346,7 +347,10 @@ class WakeApiTest(ChvCase):
|
||||
self.assertEqual(kinds[1], ("PUT", "/vm.create"))
|
||||
self.assertEqual(kinds[2], ("PUT", "/vm.boot"))
|
||||
create_payload = self.api_calls[1][2]
|
||||
self.assertEqual(create_payload["kernel"]["path"], self.kernel)
|
||||
# CHV 54:内核走 payload.kernel 纯字符串(旧顶层
|
||||
# kernel:{path} 会被忽略、vm.boot 400)。
|
||||
self.assertEqual(create_payload["payload"]["kernel"], self.kernel)
|
||||
self.assertEqual(create_payload["disks"][0]["image_type"], "Raw")
|
||||
self.assertTrue(create_payload["disks"][0]["path"].endswith(
|
||||
"disk.raw"))
|
||||
events = [e for e, _, _, _ in self.audit]
|
||||
|
||||
Reference in new issue
Block a user