mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 12:16:49 +00:00
The VM page's getters read the domain XML on their own: one load made 86 libvirt calls for a real VM, 29 of them for the same three XML documents (live, live with secrets, persistent) and 6 for the host capabilities. Each call is a round trip to the host. wvmInstance.cached_reads() is a block in which _XMLDesc (per flags value) and get_cap_xml are read from libvirt once; it ends with the block, even on an error, does not nest, and _defineXML drops it. Outside a block every read goes to libvirt as before. Only the VM page view, which does not change the VM, uses it, around its rendering. Views that change the VM keep reading fresh XML: most changes (devices, QoS, memory) do not go through _defineXML, and several views read, change and define more than once in one request. Measured on the test host: 86 -> 55 calls (XMLDesc 29 -> 3, getCapabilities 6 -> 1) for one VM, 82 -> 54 for another; the page took 0.23-0.25 s before, 0.14-0.15 s after. The HTML of both pages is identical before and after (CSRF tokens aside). A test renders the page on libvirt's test driver through the real getters: 25 XML reads before, one per kind now.
66 lines
3.1 KiB
Python
66 lines
3.1 KiB
Python
"""The VM page reads each kind of domain XML and the host capabilities once,
|
|
through the real getters, on libvirt's test driver."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
import libvirt
|
|
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
|
|
|
|
# a VM with a VNC console, on libvirt's test driver
|
|
DOMAIN = """<domain type='test'><name>read-cache-vm</name><memory unit='MiB'>128</memory><vcpu>1</vcpu>
|
|
<os><type arch='i686'>hvm</type></os>
|
|
<devices><graphics type='vnc' port='-1' listen='127.0.0.1'><listen type='address' address='127.0.0.1'/></graphics></devices>
|
|
</domain>"""
|
|
|
|
|
|
class DetailReadsTests(TestCase):
|
|
def setUp(self):
|
|
self.conn = libvirt.open("test:///default") # each open is a fresh, private test host
|
|
self.addCleanup(self.conn.close)
|
|
domain = self.conn.defineXML(DOMAIN)
|
|
self.compute = Compute.objects.create(name="testdrv", hostname="localhost", login="", password="", type=4)
|
|
self.vm = Instance.objects.create(compute=self.compute, name=domain.name(), uuid=domain.UUIDString())
|
|
# what the test driver lacks: machine types, network filters
|
|
for target, value in (("get_machine_types", ["pc"]), ("get_nwfilters", [])):
|
|
patcher = patch(f"vrtManager.connection.wvmConnect.{target}", return_value=value)
|
|
patcher.start()
|
|
self.addCleanup(patcher.stop)
|
|
self.admin = get_user_model().objects.create_superuser("dr-admin", "dr@example.com", "pw")
|
|
|
|
def render(self):
|
|
xml_reads, cap_reads = [], []
|
|
real_xml, real_caps = libvirt.virDomain.XMLDesc, libvirt.virConnect.getCapabilities
|
|
|
|
def xml(dom, flags=0):
|
|
xml_reads.append(flags)
|
|
return real_xml(dom, flags)
|
|
|
|
def caps(conn):
|
|
cap_reads.append(1)
|
|
return real_caps(conn)
|
|
|
|
self.client.force_login(self.admin)
|
|
with patch("vrtManager.connection.connection_manager.get_connection", return_value=self.conn), patch.object(
|
|
libvirt.virDomain, "XMLDesc", xml
|
|
), patch.object(libvirt.virConnect, "getCapabilities", caps):
|
|
response = self.client.get(reverse("instances:instance", args=[self.vm.id]))
|
|
self.assertEqual(response.status_code, 200)
|
|
return response, xml_reads, cap_reads
|
|
|
|
def test_each_xml_and_the_capabilities_are_read_once(self):
|
|
_, xml_reads, cap_reads = self.render()
|
|
self.assertEqual(sorted(xml_reads), sorted(set(xml_reads)), "an XML read twice")
|
|
self.assertEqual(len(cap_reads), 1)
|
|
|
|
def test_a_change_after_the_page_reads_fresh_xml(self):
|
|
# outside the page the getters read libvirt each time, as changes need
|
|
with patch("vrtManager.connection.connection_manager.get_connection", return_value=self.conn):
|
|
proxy = self.vm.proxy
|
|
proxy.set_console_passwd("pass1")
|
|
proxy.set_console_keymap("de")
|
|
self.assertEqual(proxy.get_console_passwd(), "pass1")
|
|
self.assertEqual(proxy.get_console_keymap(), "de")
|