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")