diff --git a/instances/addresses.py b/instances/addresses.py index 4b1c4dde..4c669a06 100644 --- a/instances/addresses.py +++ b/instances/addresses.py @@ -152,14 +152,14 @@ def _read_host(target, network, everything, mac): """The cheap first phase on one compute: leases and ARP of each running VM in scope (with everything, the shut-off ones are listed too). Returns the VMs' records, the observations, the (domain, vm, MACs) whose agent is - to be asked, the number of running VMs read and of those without a - connected agent; None when the compute cannot be reached (connecting may + to be asked, the number of running VMs read, of those without a + connected agent, and of paused ones whose agent cannot answer; None when the compute cannot be reached (connecting may take the connect timeout, so this too runs on the compute's thread). A VM that stops or leaves meanwhile is skipped. With a mac, only the VMs with a NIC of that MAC, and only that NIC's addresses.""" if target.compute.status is not True: return None - records, found, agents, checked, no_agent = [], [], [], 0, 0 + records, found, agents, checked, no_agent, paused = [], [], [], 0, 0, 0 listing = 0 if everything else VIR_CONNECT_LIST_DOMAINS_ACTIVE for dom in target.compute.connection.listAllDomains(listing): try: @@ -187,9 +187,11 @@ def _read_host(target, network, everything, mac): found += _matching(dom, vm, source, macs, network) or [] if not agent_connected(xml): no_agent += 1 - elif state == VIR_DOMAIN_RUNNING: # a paused guest cannot answer + elif state == VIR_DOMAIN_RUNNING: agents.append((dom, vm, macs)) - return records, found, agents, checked, no_agent + else: + paused += 1 + return records, found, agents, checked, no_agent, paused def _rows(observations): """One row per VM, MAC and address with its sources; sorted by address. A VM is its compute and UUID: one UUID may be defined on two hosts.""" @@ -236,11 +238,12 @@ def _survey(targets, network, deadline, everything, with_os=False, mac=None): if read_host is None: hosts_down.append(hosts[done].name) continue - host_records, found, agents, host_checked, host_no_agent = read_host + host_records, found, agents, host_checked, host_no_agent, host_paused = read_host records += host_records observations += found checked += host_checked no_agent += host_no_agent + unread += host_paused # a paused guest cannot answer its agent # the OS on its own thread: a hung OS read keeps the addresses read for dom, vm, macs in agents: agent_reads.append(pool.submit(_counted, _matching, dom, vm, diff --git a/instances/templates/allinstances.html b/instances/templates/allinstances.html index 48770a1e..2852f9e9 100644 --- a/instances/templates/allinstances.html +++ b/instances/templates/allinstances.html @@ -54,7 +54,7 @@ data-unregistered="{% trans "(not registered in the panel)" %}" data-conflict="{% trans "possible conflict" %}" data-checked="{% trans "Running VMs checked: %(n)s." %}" data-no-agent="{% trans "%(n)s had no connected guest agent; a static address on them cannot be seen." %}" - data-unread="{% trans "Guest agents not read (no answer in time, or an error): %(n)s." %}" + data-unread="{% trans "Guest agents not read (a paused VM, no answer in time, or an error): %(n)s." %}" data-hosts-down="{% trans "Not reached: %(hosts)s." %}" data-hosts-unfinished="{% trans "Not finished in time: %(hosts)s." %}" data-read-at="{% trans "Read at %(time)s." %}" diff --git a/instances/tests/test_addresses.py b/instances/tests/test_addresses.py index fc5b061c..53cad012 100644 --- a/instances/tests/test_addresses.py +++ b/instances/tests/test_addresses.py @@ -171,6 +171,13 @@ class FindTests(unittest.TestCase): result = self.find(addresses.Target(c, None)) self.assertEqual((result["checked"], result["no_agent"]), (2, 1)) + def test_a_paused_vm_with_an_agent_is_an_agent_not_read(self): + # a paused guest cannot answer its agent: not "checked and empty" + paused = FakeDomain({ARP: {"e": iface(MAC1, (0, "192.0.2.10", 24))}}, state=3) + result = self.find(addresses.Target(compute("c1", paused), None)) + self.assertEqual((result["checked"], result["no_agent"], result["unread"]), (1, 0, 1)) + self.assertEqual([m["sources"] for m in result["matches"]], [["ARP"]]) + def test_a_hung_agent_does_not_hold_the_answer(self): hung = threading.Event() try: diff --git a/instances/views.py b/instances/views.py index 65f0ec16..0e988f54 100755 --- a/instances/views.py +++ b/instances/views.py @@ -195,7 +195,7 @@ def vm_report(request): f"VMs listed: {len(rows)}", f"Running VMs read: {result['checked']}", f"Without a connected guest agent (a static address on them cannot be seen): {result['no_agent']}", - f"Guest agents not read (no answer in time, or an error): {result['unread']}"] + f"Guest agents not read (a paused VM, no answer in time, or an error): {result['unread']}"] if result["hosts_down"]: notes.append("Hosts not reached: " + ", ".join(result["hosts_down"])) if result["hosts_unfinished"]: