From dc5cc8933f91d5f8fab4a2ec67ce92be96e9b8a8 Mon Sep 17 00:00:00 2001 From: sjat Date: Fri, 19 Jun 2026 22:29:35 +0200 Subject: [PATCH] fix(harness): fall back to --source arp for VM IP discovery (no leaseshelper) wait_for_ip now tries --source lease first then --source arp; both produce identical output handled by parse_lease_ip. Removes the suid leaseshelper dependency introduced and backed out in Task 3. New unit test confirms parse_lease_ip works on --source arp output format. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/integration-vm.py | 15 ++++++++++----- tests/test_integration_vm.py | 8 ++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/scripts/integration-vm.py b/scripts/integration-vm.py index c51f9f7..7e5b412 100644 --- a/scripts/integration-vm.py +++ b/scripts/integration-vm.py @@ -243,13 +243,18 @@ def up(host, name=None, mem_mib=DEFAULT_MEM_MIB, vcpus=DEFAULT_VCPUS): def wait_for_ip(name, timeout=120): + # Try --source lease first (fastest when leaseshelper works), then fall back to + # --source arp (reads the host neighbour/ARP table — no privileged helper needed, + # populated once the VM sends traffic). Both sources produce identical output that + # parse_lease_ip handles, so this removes the leaseshelper/suid dependency. end = time.time() + timeout while time.time() < end: - out = sh(["virsh", "domifaddr", name, "--source", "lease"], - check=False, capture=True).stdout - ip = parse_lease_ip(out) - if ip: - return ip + for source in ("lease", "arp"): + out = sh(["virsh", "domifaddr", name, "--source", source], + check=False, capture=True).stdout + ip = parse_lease_ip(out) + if ip: + return ip time.sleep(4) raise SystemExit(f"timed out waiting for {name} to get a DHCP lease — " "VM left defined; run `integration-vm prune` to remove it") diff --git a/tests/test_integration_vm.py b/tests/test_integration_vm.py index 1d0a750..7061c0c 100644 --- a/tests/test_integration_vm.py +++ b/tests/test_integration_vm.py @@ -32,6 +32,14 @@ def test_parse_lease_ip_extracts_ipv4(): def test_parse_lease_ip_none_when_absent(): assert ivm.parse_lease_ip("no leases\n") is None +def test_parse_lease_ip_arp_source(): + # virsh domifaddr --source arp output format is identical to --source lease; + # this test proves parse_lease_ip handles it so the arp fallback in wait_for_ip works. + out = (" Name MAC address Protocol Address\n" + "-------------------------------------------------------------------\n" + " vnet0 52:54:00:de:ad:be ipv4 192.168.150.73/24\n") + assert ivm.parse_lease_ip(out) == "192.168.150.73" + def test_meta_data_has_instance_and_hostname(): md = ivm.render_meta_data("iid-askari-x", "boma-it-askari-x")