mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
perf(instances): a VM list reads only the VMs it shows
#394 read each host's states in one call and every domain's XML once, for the title, memory and vCPUs. A user's list shows only their own VMs, but it read the XML of every VM on those hosts: a user with two VMs on a host of 300 made about 301 libvirt calls a list load, where the old per-VM reads made 6. get_domain_rows takes the UUIDs the list shows and reads only their XML; the states still come in one call. The capacity reads every domain, as before.
This commit is contained in:
parent
02d4d02757
commit
337063bf7b
5 changed files with 28 additions and 11 deletions
|
|
@ -65,8 +65,8 @@ class ListReadTests(TestCase):
|
|||
|
||||
def assert_read_once_a_host(self, url):
|
||||
response, calls = self.get(url)
|
||||
# every domain of the host once (the test driver's own, and other tests', too)
|
||||
self.assertEqual(calls, {"XMLDesc": len(self.conn.listAllDomains())})
|
||||
# each VM the list shows once; the host's other domains (the test driver's own) not at all
|
||||
self.assertEqual(calls, {"XMLDesc": len(VMS)})
|
||||
self.assertContains(response, "2048 MiB", count=len(VMS))
|
||||
self.assertContains(response, "Active")
|
||||
self.assertContains(response, "vm-a title")
|
||||
|
|
@ -81,3 +81,15 @@ class ListReadTests(TestCase):
|
|||
|
||||
def test_compute_instances(self):
|
||||
self.assert_read_once_a_host(reverse("instances", args=[self.compute.id]))
|
||||
|
||||
def test_a_user_s_list_reads_only_their_vms(self):
|
||||
from accounts.models import UserInstance
|
||||
|
||||
user = get_user_model().objects.create_user("rpc-user", password="pwd")
|
||||
UserInstance.objects.create(user=user, instance=Instance.objects.get(name="vm-a"))
|
||||
self.client.force_login(user)
|
||||
response, calls = self.get(reverse("instances:index"))
|
||||
# the other VMs of the host, the test driver's own and other tests' included, are not read
|
||||
self.assertEqual(calls, {"XMLDesc": 1})
|
||||
self.assertContains(response, "vm-a title")
|
||||
self.assertNotContains(response, "vm-b")
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class UnreachableListTests(TestCase):
|
|||
or up with the error its listing raises."""
|
||||
up = rows is not None
|
||||
|
||||
def domain_rows():
|
||||
def domain_rows(uuids=None):
|
||||
if isinstance(rows, Exception):
|
||||
raise rows
|
||||
return rows
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class StateTests(TestCase):
|
|||
|
||||
self.client.force_login(user)
|
||||
props = {"status": True, "connection_error": None, "cpu_count": 1, "ram_size": 1, "ram_usage": 0,
|
||||
"proxy": SimpleNamespace(get_domain_rows=lambda: rows)}
|
||||
"proxy": SimpleNamespace(get_domain_rows=lambda uuids=None: rows)}
|
||||
patches = [patch.object(Compute, k, new_callable=PropertyMock, return_value=v) for k, v in props.items()]
|
||||
patches += [patch("instances.views.utils.refr"), patch("computes.views.utils.refresh_instance_database")]
|
||||
for p in patches:
|
||||
|
|
|
|||
|
|
@ -356,10 +356,12 @@ def read_list_rows(instances):
|
|||
"""Each VM's info and title for a VM list, read once a host
|
||||
(get_domain_rows), not three calls a VM; a VM whose host or whose
|
||||
domain cannot be read has no info: the list shows it unknown."""
|
||||
rows = {}
|
||||
rows, shown = {}, {}
|
||||
for inst in instances:
|
||||
shown.setdefault(inst.compute_id, set()).add(inst.uuid)
|
||||
for compute in {inst.compute_id: inst.compute for inst in instances}.values():
|
||||
try:
|
||||
rows[compute.pk] = compute.proxy.get_domain_rows() if compute.status is True else {}
|
||||
rows[compute.pk] = compute.proxy.get_domain_rows(shown[compute.pk]) if compute.status is True else {}
|
||||
except libvirtError:
|
||||
rows[compute.pk] = {}
|
||||
for inst in instances:
|
||||
|
|
|
|||
|
|
@ -1098,13 +1098,16 @@ class wvmConnect(object):
|
|||
return {dom.UUIDString(): [dom.name(), stats["state.state"]]
|
||||
for dom, stats in self.wvm.getAllDomainStats(libvirt.VIR_DOMAIN_STATS_STATE)}
|
||||
|
||||
def get_domain_rows(self):
|
||||
"""{uuid: (info, title)} of every domain, as the VM lists show them:
|
||||
info in virDomainGetInfo's shape (state, max memory KiB, memory KiB,
|
||||
vCPUs), the states in one call and the rest from each domain's live
|
||||
XML, which the title needs anyway. A domain gone meanwhile is left out."""
|
||||
def get_domain_rows(self, uuids=None):
|
||||
"""{uuid: (info, title)} of every domain, or of those in uuids, as the
|
||||
VM lists show them: info in virDomainGetInfo's shape (state, max
|
||||
memory KiB, memory KiB, vCPUs), the states in one call and the rest
|
||||
from each domain's live XML, which the title needs anyway. A domain
|
||||
gone meanwhile is left out."""
|
||||
rows = {}
|
||||
for dom, stats in self.wvm.getAllDomainStats(libvirt.VIR_DOMAIN_STATS_STATE):
|
||||
if uuids is not None and dom.UUIDString() not in uuids:
|
||||
continue # a VM the list does not show: its XML is not read
|
||||
try:
|
||||
doc = etree.fromstring(dom.XMLDesc(0))
|
||||
except libvirtError:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue