From 0c939329c50ded6d2b9e1e7fdeb58a788f2c1bf8 Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Wed, 3 Dec 2025 00:14:47 +0900 Subject: [PATCH] libvirt: Extend functional test coverage of UEFI boot guests Adds non-secure boot scenario and stateless firmware scenario to demonstrate how guest xml contents look like when firmware files are selected by libvirt. Partially-Implements: blueprint libvirt-firmware-auto-selection Change-Id: I88f0b81c8455630145efca8c6349fc00a0c29835 Signed-off-by: Takashi Kajinami --- nova/tests/functional/libvirt/test_uefi.py | 218 ++++++++++++++++++++- 1 file changed, 210 insertions(+), 8 deletions(-) diff --git a/nova/tests/functional/libvirt/test_uefi.py b/nova/tests/functional/libvirt/test_uefi.py index 628acb6df8b0..87ca8ed7a4c0 100644 --- a/nova/tests/functional/libvirt/test_uefi.py +++ b/nova/tests/functional/libvirt/test_uefi.py @@ -31,7 +31,9 @@ LOG = logging.getLogger(__name__) class UEFIServersTest(base.ServersTestBase): - def assertInstanceHasUEFI(self, server): + def assertInstanceHasUEFI( + self, server, secure_boot=False, stateless=False + ): ctx = nova_context.get_admin_context() instance = objects.Instance.get_by_uuid(ctx, server['id']) self.assertIn('image_hw_machine_type', instance.system_metadata) @@ -40,9 +42,22 @@ class UEFIServersTest(base.ServersTestBase): self.assertIn('image_hw_firmware_type', instance.system_metadata) self.assertEqual( 'uefi', instance.system_metadata['image_hw_firmware_type']) - self.assertIn('image_os_secure_boot', instance.system_metadata) - self.assertEqual( - 'required', instance.system_metadata['image_os_secure_boot']) + + if secure_boot: + self.assertIn('image_os_secure_boot', instance.system_metadata) + self.assertEqual( + 'required', instance.system_metadata['image_os_secure_boot']) + else: + self.assertNotIn('image_os_secure_boot', instance.system_metadata) + + if stateless: + self.assertIn('image_hw_firmware_stateless', + instance.system_metadata) + self.assertTrue( + instance.system_metadata['image_hw_firmware_stateless']) + else: + self.assertNotIn('image_hw_firmware_stateless', + instance.system_metadata) def test_create_server(self): orig_create = nova.virt.libvirt.guest.Guest.create @@ -55,9 +70,8 @@ class UEFIServersTest(base.ServersTestBase): """ hvm - /usr/share/OVMF/OVMF_CODE.secboot.fd - + /usr/share/OVMF/OVMF_CODE.fd + @@ -98,7 +112,6 @@ class UEFIServersTest(base.ServersTestBase): 'properties': { 'hw_machine_type': 'q35', 'hw_firmware_type': 'uefi', - 'os_secure_boot': 'required', } } self.glance.create(None, uefi_image) @@ -107,3 +120,192 @@ class UEFIServersTest(base.ServersTestBase): # ensure our instance's system_metadata field is correct self.assertInstanceHasUEFI(server) + + def test_create_server_secure_boot(self): + orig_create = nova.virt.libvirt.guest.Guest.create + + def fake_create(cls, xml, host): + xml = re.sub('type arch.*machine', + 'type machine', xml) + tree = etree.fromstring(xml) + self.assertXmlEqual( + """ + + hvm + /usr/share/OVMF/OVMF_CODE.secboot.fd + + + + + """, # noqa: E501 + etree.tostring(tree.find('./os'), encoding='unicode')) + + return orig_create(xml, host) + + self.stub_out('nova.virt.libvirt.guest.Guest.create', fake_create) + + compute = self.start_compute() + + # ensure we are reporting the correct trait + traits = self._get_provider_traits(self.compute_rp_uuids[compute]) + self.assertIn('COMPUTE_SECURITY_UEFI_SECURE_BOOT', traits) + + # create a server with UEFI and secure boot + timestamp = datetime.datetime( + 2021, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc + ) + sb_image = { + 'id': uuids.sb_image, + 'name': 'sb_image', + 'created_at': timestamp, + 'updated_at': timestamp, + 'deleted_at': None, + 'deleted': False, + 'status': 'active', + 'is_public': False, + 'container_format': 'ova', + 'disk_format': 'vhd', + 'size': 74185822, + 'min_ram': 0, + 'min_disk': 0, + 'protected': False, + 'visibility': 'public', + 'tags': [], + 'properties': { + 'hw_machine_type': 'q35', + 'hw_firmware_type': 'uefi', + 'os_secure_boot': 'required', + } + } + self.glance.create(None, sb_image) + + server = self._create_server(image_uuid=uuids.sb_image) + + # ensure our instance's system_metadata field is correct + self.assertInstanceHasUEFI(server, secure_boot=True) + + def test_create_server_stateless(self): + orig_create = nova.virt.libvirt.guest.Guest.create + + def fake_create(cls, xml, host): + xml = re.sub('type arch.*machine', + 'type machine', xml) + tree = etree.fromstring(xml) + self.assertXmlEqual( + """ + + hvm + /usr/share/OVMF/OVMF_CODE.fd + + + + """, # noqa: E501 + etree.tostring(tree.find('./os'), encoding='unicode')) + + return orig_create(xml, host) + + self.stub_out('nova.virt.libvirt.guest.Guest.create', fake_create) + + compute = self.start_compute(libvirt_version=8006000) + + # ensure we are reporting the correct trait + traits = self._get_provider_traits(self.compute_rp_uuids[compute]) + self.assertIn('COMPUTE_SECURITY_STATELESS_FIRMWARE', traits) + + # create a server with UEFI and secure boot + timestamp = datetime.datetime( + 2021, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc + ) + stateless_image = { + 'id': uuids.stateless_image, + 'name': 'stateless_image', + 'created_at': timestamp, + 'updated_at': timestamp, + 'deleted_at': None, + 'deleted': False, + 'status': 'active', + 'is_public': False, + 'container_format': 'ova', + 'disk_format': 'vhd', + 'size': 74185822, + 'min_ram': 0, + 'min_disk': 0, + 'protected': False, + 'visibility': 'public', + 'tags': [], + 'properties': { + 'hw_machine_type': 'q35', + 'hw_firmware_type': 'uefi', + 'hw_firmware_stateless': True, + } + } + self.glance.create(None, stateless_image) + + server = self._create_server(image_uuid=uuids.stateless_image) + + # ensure our instance's system_metadata field is correct + self.assertInstanceHasUEFI(server, stateless=True) + + def test_create_server_secure_boot_stateless(self): + orig_create = nova.virt.libvirt.guest.Guest.create + + def fake_create(cls, xml, host): + xml = re.sub('type arch.*machine', + 'type machine', xml) + tree = etree.fromstring(xml) + self.assertXmlEqual( + """ + + hvm + /usr/share/OVMF/OVMF_CODE.secboot.fd + + + + """, # noqa: E501 + etree.tostring(tree.find('./os'), encoding='unicode')) + + return orig_create(xml, host) + + self.stub_out('nova.virt.libvirt.guest.Guest.create', fake_create) + + compute = self.start_compute(libvirt_version=8006000) + + # ensure we are reporting the correct trait + traits = self._get_provider_traits(self.compute_rp_uuids[compute]) + self.assertIn('COMPUTE_SECURITY_UEFI_SECURE_BOOT', traits) + self.assertIn('COMPUTE_SECURITY_STATELESS_FIRMWARE', traits) + + # create a server with UEFI and secure boot + timestamp = datetime.datetime( + 2021, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc + ) + sb_image = { + 'id': uuids.sb_image, + 'name': 'sb_image', + 'created_at': timestamp, + 'updated_at': timestamp, + 'deleted_at': None, + 'deleted': False, + 'status': 'active', + 'is_public': False, + 'container_format': 'ova', + 'disk_format': 'vhd', + 'size': 74185822, + 'min_ram': 0, + 'min_disk': 0, + 'protected': False, + 'visibility': 'public', + 'tags': [], + 'properties': { + 'hw_machine_type': 'q35', + 'hw_firmware_type': 'uefi', + 'os_secure_boot': 'required', + 'hw_firmware_stateless': True, + } + } + self.glance.create(None, sb_image) + + server = self._create_server(image_uuid=uuids.sb_image) + + # ensure our instance's system_metadata field is correct + self.assertInstanceHasUEFI(server, secure_boot=True, stateless=True)