mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
perf(instances): a VM page does not wait for the guest agent's addresses
A running VM's page read its addresses while it rendered: the guest agent, when its channel is connected but it does not answer, holds the page (and a gunicorn worker) for its whole 10 s timeout, on every load. The page now shows them once it has loaded: vm_addresses.js asks the new instances/<pk>/addresses/ for each NIC's addresses and fills the header's IPv4 and each network card's IPv4 and IPv6.
This commit is contained in:
parent
bf736942eb
commit
aab8dbf1df
18 changed files with 600 additions and 449 deletions
|
|
@ -795,15 +795,11 @@ class wvmInstance(wvmConnect):
|
|||
pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
|
||||
return range(1, max(int(pcpus), at_least) + 1)
|
||||
|
||||
def get_interface_addresses(self, iface_mac):
|
||||
"""The running VM's addresses of the NIC with iface_mac: (IPv4, IPv6
|
||||
with prefix), from the guest agent when it has some, else from the
|
||||
host's ARP table; (None, None) when neither has one. Read once in a
|
||||
cached_reads block: the agent may take its whole timeout."""
|
||||
return self._cached("addresses", self._read_addresses).get(iface_mac, (None, None))
|
||||
|
||||
def _read_addresses(self):
|
||||
"""{MAC: (IPv4 list, IPv6 list)}: each MAC's addresses from the first source that has some."""
|
||||
def get_addresses(self):
|
||||
"""The running VM's addresses, {MAC: (IPv4 list, IPv6 list with
|
||||
prefix)}, each MAC's from the first source that has some: the guest
|
||||
agent, else the host's ARP table. The agent may take its whole
|
||||
timeout: the VM page reads them after it loads (views.nic_addresses)."""
|
||||
if self.get_status() != 1:
|
||||
return {}
|
||||
sources = []
|
||||
|
|
@ -856,10 +852,6 @@ class wvmInstance(wvmConnect):
|
|||
out_burst = out_attr.get("burst")
|
||||
outbound = {"average": out_av, "peak": out_peak, "burst": out_burst}
|
||||
|
||||
try:
|
||||
ipv4, ipv6 = self.get_interface_addresses(mac_inst)
|
||||
except libvirtError:
|
||||
ipv4, ipv6 = None, None
|
||||
result.append(
|
||||
{
|
||||
"type": interface_type,
|
||||
|
|
@ -868,8 +860,6 @@ class wvmInstance(wvmConnect):
|
|||
"target": target_inst,
|
||||
"state": link_state,
|
||||
"model": model_type,
|
||||
"ipv4": ipv4,
|
||||
"ipv6": ipv6,
|
||||
"filterref": filterref_inst,
|
||||
"inbound": inbound,
|
||||
"outbound": outbound,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ XML = """<domain>
|
|||
|
||||
def proxy():
|
||||
p = wvmInstance.__new__(wvmInstance) # no connection: only these calls
|
||||
p._read_addresses = dict # no addresses
|
||||
p._XMLDesc = lambda flags: XML
|
||||
volumes = {"/iso/x.iso": ("x.iso", "iso")}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""A running VM's addresses come from the guest agent when it answers and
|
||||
from the host's ARP table, so a VM without an agent shows its IPv4 address.
|
||||
The agent is asked with a timeout: interfaceAddresses() would wait for a
|
||||
hung agent indefinitely, and the VM page with it."""
|
||||
hung agent indefinitely; the VM page asks for them after it loads."""
|
||||
|
||||
import json
|
||||
import unittest
|
||||
|
|
@ -38,32 +38,31 @@ class InterfaceAddressesTestCase(unittest.TestCase):
|
|||
|
||||
def test_a_vm_without_an_agent_shows_its_arp_address(self):
|
||||
inst = vm(agent=False)
|
||||
self.assertEqual(inst.get_interface_addresses(MAC), (["192.0.2.10"], []))
|
||||
self.assertEqual(inst.get_addresses(), {MAC: (["192.0.2.10"], [])})
|
||||
self.agent.assert_not_called()
|
||||
|
||||
def test_the_agents_address_comes_first_and_is_asked_with_a_timeout(self):
|
||||
inst = vm(agent=True)
|
||||
self.assertEqual(inst.get_interface_addresses(MAC), (["192.0.2.20"], ["2001:db8::20/64"]))
|
||||
self.assertEqual(inst.get_addresses(), {MAC: (["192.0.2.20"], ["2001:db8::20/64"])})
|
||||
self.agent.assert_called_once_with(inst.instance, '{"execute": "guest-network-get-interfaces"}', 10, 0)
|
||||
self.assertEqual([c.args for c in inst.instance.interfaceAddresses.call_args_list],
|
||||
[(VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP,)])
|
||||
|
||||
def test_the_addresses_are_read_once_in_a_page_and_again_after_it(self):
|
||||
def test_the_vm_s_definition_does_not_read_them(self):
|
||||
inst = vm(agent=True)
|
||||
with inst.cached_reads():
|
||||
inst.get_interface_addresses(MAC)
|
||||
inst.get_interface_addresses("52:54:00:00:00:02")
|
||||
self.assertEqual(self.agent.call_count, 1)
|
||||
# outside a page's block, a new read: a NIC's address can change
|
||||
inst.get_interface_addresses(MAC)
|
||||
self.assertEqual(self.agent.call_count, 2)
|
||||
inst._XMLDesc = lambda flags: f"<domain><devices><interface type='network'><mac address='{MAC}'/></interface></devices></domain>"
|
||||
self.assertEqual([nic["mac"] for nic in inst.get_net_devices()], [MAC])
|
||||
self.agent.assert_not_called()
|
||||
inst.instance.interfaceAddresses.assert_not_called()
|
||||
|
||||
def test_a_mac_without_addresses_has_none(self):
|
||||
self.assertEqual(vm(agent=False).get_interface_addresses("52:54:00:00:00:02"), (None, None))
|
||||
def test_a_vm_that_does_not_run_has_none(self):
|
||||
inst = vm(agent=True)
|
||||
inst.get_status.return_value = 5
|
||||
self.assertEqual(inst.get_addresses(), {})
|
||||
|
||||
def test_an_agent_that_does_not_answer_leaves_the_arp_address(self):
|
||||
self.agent.side_effect = libvirtError("guest agent didn't respond to command within '10' seconds")
|
||||
self.assertEqual(vm(agent=True).get_interface_addresses(MAC), (["192.0.2.10"], []))
|
||||
self.assertEqual(vm(agent=True).get_addresses(), {MAC: (["192.0.2.10"], [])})
|
||||
|
||||
|
||||
class OsInfoTestCase(unittest.TestCase):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue