mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
A VM list row showed the VM's state, memory, vCPUs and title, read through the VM's own connection object: a lookup by UUID, virDomainGetInfo and the live XML, one after the other for every VM on the page. The lists (Instances, grouped or not, and a compute's VMs) now read each host once: the states in one getAllDomainStats call (the state group only, as the lists' poll; no other group, so a VM busy in the QEMU monitor holds nothing up) and the memory, vCPUs and title from each VM's live XML, which the title already read. Checked on QEMU against virDomainGetInfo for running, paused and shut-off VMs: the same values. A VM gone from its host, or a host that cannot be read or fails its listing, shows its VMs unknown as before. Only the grouped list, a superuser's, prefetches every host's VMs and owners.
83 lines
3.6 KiB
Python
83 lines
3.6 KiB
Python
"""Instance lists read their VMs once a host (get_domain_rows): the states in
|
|
one call and each VM's live XML once, no lookup or info call a VM; on
|
|
libvirt's test driver."""
|
|
|
|
from collections import Counter
|
|
from unittest.mock import PropertyMock, patch
|
|
|
|
import libvirt
|
|
from appsettings.models import AppSettings
|
|
from computes.models import Compute
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
from instances.models import Instance
|
|
|
|
DOMAIN = """<domain type='test'><name>{name}</name><uuid>{uuid}</uuid><title>{name} title</title>
|
|
<memory unit='MiB'>4096</memory><currentMemory unit='MiB'>2048</currentMemory><vcpu current='3'>4</vcpu>
|
|
<os><type arch='i686'>hvm</type></os></domain>"""
|
|
VMS = {"vm-a": "11111111-1111-1111-1111-111111111111", "vm-b": "22222222-2222-2222-2222-222222222222"}
|
|
|
|
|
|
class ListReadTests(TestCase):
|
|
def setUp(self):
|
|
self.client.force_login(
|
|
get_user_model().objects.create_superuser(username="rpc-admin", password="pwd", email="rpc@example.com")
|
|
)
|
|
self.conn = libvirt.open("test:///default")
|
|
self.addCleanup(self.conn.close)
|
|
self.compute = Compute.objects.create(name="rpc-compute", hostname="localhost", type=4, login="", password="")
|
|
for name, uuid in VMS.items():
|
|
domain = self.conn.defineXML(DOMAIN.format(name=name, uuid=uuid))
|
|
domain.create()
|
|
self.addCleanup(domain.undefine)
|
|
self.addCleanup(domain.destroy)
|
|
Instance.objects.create(compute=self.compute, name=name, uuid=uuid)
|
|
|
|
def get(self, url):
|
|
calls = Counter()
|
|
|
|
def counted(cls, name):
|
|
real = getattr(cls, name)
|
|
|
|
def call(*args, **kwargs):
|
|
calls[name] += 1
|
|
return real(*args, **kwargs)
|
|
|
|
return patch.object(cls, name, call)
|
|
|
|
patches = [patch("instances.views.utils.refr"), patch("computes.views.utils.refresh_instance_database"),
|
|
patch("vrtManager.connection.connection_manager.get_connection", return_value=self.conn),
|
|
counted(libvirt.virDomain, "info"), counted(libvirt.virDomain, "XMLDesc"),
|
|
counted(libvirt.virConnect, "lookupByUUIDString")]
|
|
# the grouped list's host line; the test driver has no memory stats
|
|
patches += [patch.object(Compute, k, new_callable=PropertyMock, return_value=v)
|
|
for k, v in {"cpu_count": 1, "ram_size": 1024, "ram_usage": 0}.items()]
|
|
for p in patches:
|
|
p.start()
|
|
try:
|
|
response = self.client.get(url)
|
|
finally:
|
|
for p in reversed(patches):
|
|
p.stop()
|
|
self.assertEqual(response.status_code, 200)
|
|
return response, calls
|
|
|
|
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())})
|
|
self.assertContains(response, "2048 MiB", count=len(VMS))
|
|
self.assertContains(response, "Active")
|
|
self.assertContains(response, "vm-a title")
|
|
|
|
def test_nongrouped_index(self):
|
|
AppSettings.objects.filter(key="VIEW_INSTANCES_LIST_STYLE").update(value="nongrouped")
|
|
self.assert_read_once_a_host(reverse("instances:index"))
|
|
|
|
def test_grouped_index(self):
|
|
AppSettings.objects.filter(key="VIEW_INSTANCES_LIST_STYLE").update(value="grouped")
|
|
self.assert_read_once_a_host(reverse("instances:index"))
|
|
|
|
def test_compute_instances(self):
|
|
self.assert_read_once_a_host(reverse("instances", args=[self.compute.id]))
|