fix(integration-vm): place VM disk/seed/console in CACHE_DIR for system-qemu

Under qemu:///system the hypervisor runs as libvirt-qemu, which cannot traverse
/home/claude — so the overlay/seed/console must live in /var/lib/boma-integration
(group libvirt, world-traversable, created by the integration_test role), not the
repo/home RUN_DIR. The inventory (hosts.yml + group_vars symlink, read by ansible
as claude) stays in RUN_DIR. Verified: virt-install now creates the domain.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
sjat 2026-06-18 14:56:35 +02:00
parent 147eb874ea
commit e5256696d6

View file

@ -182,14 +182,16 @@ def up(host, name=None, mem_mib=DEFAULT_MEM_MIB, vcpus=DEFAULT_VCPUS):
img = ensure_image()
net_ensure()
RUN_DIR.mkdir(parents=True, exist_ok=True)
overlay = RUN_DIR / f"{name}.qcow2"
# VM disk/seed/console must live where the SYSTEM hypervisor (libvirt-qemu) can reach
# them — NOT under the repo/home (qemu cannot traverse /home/claude). CACHE_DIR is
# group-libvirt + world-traversable (created by the integration_test role).
overlay = CACHE_DIR / f"{name}.qcow2"
sh(["qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", str(img), str(overlay)])
(RUN_DIR / "user-data").write_text(render_user_data(_ssh_pubkey(), "ansible"))
(RUN_DIR / "meta-data").write_text(render_meta_data(f"iid-{name}", name))
seed = RUN_DIR / f"{name}-seed.img"
seed = CACHE_DIR / f"{name}-seed.img"
sh(["cloud-localds", str(seed), str(RUN_DIR / "user-data"), str(RUN_DIR / "meta-data")])
DIAG_ROOT.mkdir(parents=True, exist_ok=True)
console = DIAG_ROOT / f"{name}-console.log"
console = CACHE_DIR / f"{name}-console.log"
sh(["virt-install", "--name", name, "--memory", str(mem_mib), "--vcpus", str(vcpus),
"--import",
"--disk", f"path={overlay},format=qcow2",
@ -327,7 +329,7 @@ def dump_diagnostics(name, ip):
"-o", "UserKnownHostsFile=/dev/null",
f"ansible@{ip}", "sudo " + cmd], check=False, capture=True)
(d / f"{label}.txt").write_text((r.stdout or "") + (r.stderr or ""))
console = DIAG_ROOT / f"{name}-console.log"
console = CACHE_DIR / f"{name}-console.log"
if console.exists():
shutil.copy(console, d / "console.log")
print(f"diagnostics written to {d}", file=sys.stderr)
@ -336,8 +338,9 @@ def dump_diagnostics(name, ip):
def _destroy(name):
sh(["virsh", "destroy", name], check=False)
sh(["virsh", "undefine", name, "--nvram"], check=False)
for f in RUN_DIR.glob(f"{name}*"):
f.unlink(missing_ok=True)
for base in (RUN_DIR, CACHE_DIR):
for f in base.glob(f"{name}*"):
f.unlink(missing_ok=True)
def down(host=None, keep=False):
@ -363,7 +366,7 @@ def prune():
def console():
name = (RUN_DIR / "current").read_text().splitlines()[0]
log = DIAG_ROOT / f"{name}-console.log"
log = CACHE_DIR / f"{name}-console.log"
print(log.read_text() if log.exists() else f"no console log at {log}")