1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00

fix(instances): the create page offers the UEFI loader of the chosen machine

create_instance passed the loader list where find_uefi_path_for_arch
expects the machine type. The domain capabilities were then read for
the default machine (pc) instead of the chosen one: on a RHEL host a q35
VM was offered /usr/share/OVMF/OVMF_CODE.secboot.fd, which q35 does not
list, instead of /usr/share/edk2/ovmf/OVMF_CODE.fd. The machine type is
passed now.

The page also read dom_caps["loader_enums"] into an unused variable;
on a host without loader support the key is missing and the page failed
with a KeyError. The line is removed.

A unit test covers the call and the host without loader support (it
fails on the previous code). A live test creates a q35 VM with the
offered UEFI firmware, checks that libvirt lists that loader for q35 and
starts the VM; it fails on the previous code.
This commit is contained in:
catborise 2026-10-04 17:22:54 +03:00
parent 16e1a334d0
commit cdbff38223
3 changed files with 45 additions and 2 deletions

View file

@ -62,3 +62,30 @@ class CreateInstanceViewTests(TestCase):
fetch_redirect_response=False,
)
conn.create_instance.assert_called_once()
@patch("instances.views.wvmCreate")
def test_firmware_list_uses_the_chosen_machine_type(self, connection_class):
user = get_user_model().objects.create_superuser(
username="create-fw-admin", password="password", email="fw@example.com"
)
self.client.force_login(user)
compute = Compute.objects.create(
name="create-fw-compute", hostname="localhost", type=4, login="", password="",
)
conn = connection_class.return_value
conn.get_instances.return_value = []
conn.get_storages.return_value = []
conn.get_networks.return_value = []
conn.get_nwfilters.return_value = []
conn.get_cache_modes.return_value = {}
# A host without loader support has no "loaders"/"loader_enums" keys
conn.get_dom_capabilities.return_value = {"loader_support": "no"}
conn.get_capabilities.return_value = {}
conn.label_for_firmware_path.return_value = None
conn.find_uefi_path_for_arch.return_value = None
response = self.client.get(reverse("instances:create_instance", args=[compute.id, "x86_64", "q35"]))
self.assertEqual(response.status_code, 200)
conn.find_uefi_path_for_arch.assert_called_once_with("x86_64", "q35")

View file

@ -11,6 +11,7 @@ from computes.models import Compute
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from lxml import etree
from vrtManager.connection import connection_manager
from . import livetest
@ -111,6 +112,22 @@ class LiveCreateTestCase(TestCase):
self.assertTrue(self.domain_exists(P + "cr-ok"))
self.assertEqual(len(self.volumes()), 1)
def test_offered_uefi_firmware_boots_on_q35(self):
page = self.client.get(reverse("instances:create_instance", args=[self.compute.id, "x86_64", "q35"]))
uefi = [f for f in page.context["firmwares"] if f.startswith("UEFI")]
self.assertTrue(uefi, "no UEFI firmware offered for q35")
self.create("cr-uefi-ok", firmware=uefi[0])
dom = self.conn.lookupByName(P + "cr-uefi-ok")
loader = etree.fromstring(dom.XMLDesc(0)).findtext("os/loader")
self.assertEqual(loader, uefi[0].split(":", 1)[1].strip())
# Listed by libvirt for q35, so the domain starts with it
caps = etree.fromstring(self.conn.getDomainCapabilities(None, "x86_64", "q35", "kvm"))
self.assertIn(loader, caps.xpath("os/loader/value/text()"))
dom.create()
self.assertTrue(dom.isActive())
def test_api_rejected_definition_removes_the_new_disk(self):
response = self.client.post(
f"/api/v1/computes/{self.compute.id}/instances/create/x86_64/q35/",

View file

@ -2085,13 +2085,12 @@ def create_instance(request, compute_id, arch, machine):
caps = conn.get_capabilities(arch)
virtio_support = conn.is_supports_virtio(arch, machine)
hv_supports_uefi = conn.supports_uefi_xml(dom_caps["loader_enums"])
# Add BIOS
label = conn.label_for_firmware_path(arch, None)
if label:
firmwares.append(label)
# Add UEFI
loader_path = conn.find_uefi_path_for_arch(arch, dom_caps["loaders"])
loader_path = conn.find_uefi_path_for_arch(arch, machine)
label = conn.label_for_firmware_path(arch, loader_path)
if label:
firmwares.append(label)