From a8386bdab3e2b6f6cd984f4c6a69b000da2be4a4 Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Wed, 27 Aug 2025 18:08:47 +0900 Subject: [PATCH] Purge nested SEV RPs when SEV is disabled We can determine exact names of these RPs using the compute node name, independently from how nova is configured. So we can easily purge these PRs. Change-Id: I0a18e3a3750137061e04765f2feaf4889c6f5606 Signed-off-by: Takashi Kajinami --- .../libvirt/test_report_cpu_traits.py | 16 +++--- nova/tests/functional/libvirt/test_reshape.py | 35 ++++++++---- .../regressions/test_bug_1928063.py | 6 ++- nova/tests/unit/virt/libvirt/test_driver.py | 54 +++++++++++++++++-- nova/virt/libvirt/driver.py | 13 ++++- 5 files changed, 99 insertions(+), 25 deletions(-) diff --git a/nova/tests/functional/libvirt/test_report_cpu_traits.py b/nova/tests/functional/libvirt/test_report_cpu_traits.py index bc1c67dbce..0f023eec66 100644 --- a/nova/tests/functional/libvirt/test_report_cpu_traits.py +++ b/nova/tests/functional/libvirt/test_report_cpu_traits.py @@ -433,11 +433,9 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase): self.assertNotIn(ost.HW_CPU_X86_AMD_SEV, traits) self.assertNotIn(ost.HW_CPU_X86_AMD_SEV_ES, traits) - # NOTE(tkajinam): Currently the sev rp is not deleted after sev - # support is turned off. This follows the existing behavior for - # other resources such as vGPU. - # sev_rps = self._get_amd_sev_rps() - # self.assertEqual(0, len(sev_rps['sev-es'])) + sev_rps = self._get_amd_sev_rps() + self.assertEqual(1, len(sev_rps['sev'])) + self.assertEqual(0, len(sev_rps['sev-es'])) # Now simulate the host losing SEV functionality. Here we # simulate a kernel downgrade or reconfiguration which causes @@ -480,8 +478,6 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase): self.assertNotIn(ost.HW_CPU_X86_AMD_SEV, traits) self.assertNotIn(ost.HW_CPU_X86_AMD_SEV_ES, traits) - # NOTE(tkajinam): Currently the sev rp is not deleted after sev - # support is turned off. This follows the existing behavior for - # other resources such as vGPU. - # sev_rps = self._get_amd_sev_rps() - # self.assertEqual(0, len(sev_rps['sev'])) + sev_rps = self._get_amd_sev_rps() + self.assertEqual(0, len(sev_rps['sev'])) + self.assertEqual(0, len(sev_rps['sev-es'])) diff --git a/nova/tests/functional/libvirt/test_reshape.py b/nova/tests/functional/libvirt/test_reshape.py index 02bceb35cf..03876a6886 100644 --- a/nova/tests/functional/libvirt/test_reshape.py +++ b/nova/tests/functional/libvirt/test_reshape.py @@ -253,6 +253,11 @@ class SevResphapeTests(base.ServersTestBase): hw_mem_enc_image['properties']['hw_mem_encryption'] = True self.glance.create(admin_context, hw_mem_enc_image) + def _delete_server(self, server): + with mock.patch('nova.virt.libvirt.driver.LibvirtDriver.' + 'update_provider_tree'): + super()._delete_server(server) + @mock.patch('nova.virt.libvirt.driver.LibvirtDriver.' '_guest_configure_mem_encryption') def test_create_servers_with_amd_sev(self, mock_configure_me): @@ -294,7 +299,7 @@ class SevResphapeTests(base.ServersTestBase): 'update_provider_tree'): pre_server = self._create_server( image_uuid=uuidsentinel.mem_enc_image_id) - self.addCleanup(self._delete_server, pre_server) + self.addCleanup(self._delete_server, pre_server) # verify that the inventory, usages and allocation are correct before # the reshape @@ -328,8 +333,12 @@ class SevResphapeTests(base.ServersTestBase): self.assertIn(os_traits.HW_CPU_X86_AMD_SEV, sev_traits) # create a new server after reshape - post_server = self._create_server( - image_uuid=uuidsentinel.mem_enc_image_id) + with mock.patch('nova.virt.libvirt.host.Host.supports_amd_sev', + return_value=True), \ + mock.patch('nova.virt.libvirt.host.Host.supports_amd_sev_es', + return_value=False): + post_server = self._create_server( + image_uuid=uuidsentinel.mem_enc_image_id) self.addCleanup(self._delete_server, post_server) sev_usages = self._get_provider_usages(sev_rp_uuid) @@ -413,13 +422,21 @@ class SevResphapeTests(base.ServersTestBase): self.assertEqual(0, compute_usages['MEM_ENCRYPTION_CONTEXT']) # create new servers to both compute nodes - post_server1 = self._create_server( - host='compute1', networks='none', - image_uuid=uuidsentinel.mem_enc_image_id) + with mock.patch('nova.virt.libvirt.host.Host.supports_amd_sev', + return_value=True), \ + mock.patch('nova.virt.libvirt.host.Host.supports_amd_sev_es', + return_value=False): + post_server1 = self._create_server( + host='compute1', networks='none', + image_uuid=uuidsentinel.mem_enc_image_id) self.addCleanup(self._delete_server, post_server1) - post_server2 = self._create_server( - host='compute2', networks='none', - image_uuid=uuidsentinel.mem_enc_image_id) + # NOTE(tkajinam): compute2 has old SEV RP so we should avoid + # update_provider_tree here + with mock.patch('nova.virt.libvirt.driver.LibvirtDriver.' + 'update_provider_tree'): + post_server2 = self._create_server( + host='compute2', networks='none', + image_uuid=uuidsentinel.mem_enc_image_id) self.addCleanup(self._delete_server, post_server2) # server1 should allocate M_E_C from SEV RP diff --git a/nova/tests/functional/regressions/test_bug_1928063.py b/nova/tests/functional/regressions/test_bug_1928063.py index 3e9daec337..1c607d01b4 100644 --- a/nova/tests/functional/regressions/test_bug_1928063.py +++ b/nova/tests/functional/regressions/test_bug_1928063.py @@ -48,7 +48,11 @@ class TestSEVInstanceReboot(base.ServersTestBase): sev_image['properties']['hw_mem_encryption'] = 'True' self.glance.create(None, sev_image) - def test_hard_reboot(self): + @mock.patch('nova.virt.libvirt.host.Host.supports_amd_sev_es', + return_value=False) + @mock.patch('nova.virt.libvirt.host.Host.supports_amd_sev', + return_value=True) + def test_hard_reboot(self, mock_sev, mock_sev_es): # Launch a SEV based instance and then attempt to hard reboot server = self._create_server( image_uuid=uuids.sev_image_id, diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 851140c7ab..0d2423a4b1 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -31144,24 +31144,52 @@ class TestLibvirtSEV(test.NoDBTestCase): @mock.patch.object(os.path, 'exists', new=mock.Mock(return_value=False)) class TestLibvirtSEVUnsupported(TestLibvirtSEV): def test_get_memory_encryption_inventories_no_config(self): - self.assertEqual({}, self.driver._get_memory_encryption_inventories()) + self.assertEqual({ + 'amd_sev': { + 'total': 0 + }, + 'amd_sev_es': { + 'total': 0 + } + }, self.driver._get_memory_encryption_inventories()) def test_get_memory_encryption_inventories_config_zero(self): self.flags(num_memory_encrypted_guests=0, group='libvirt') - self.assertEqual({}, self.driver._get_memory_encryption_inventories()) + self.assertEqual({ + 'amd_sev': { + 'total': 0 + }, + 'amd_sev_es': { + 'total': 0 + } + }, self.driver._get_memory_encryption_inventories()) @mock.patch.object(libvirt_driver.LOG, 'warning') def test_get_memory_encryption_inventories_config_non_zero_unsupported( self, mock_log): self.flags(num_memory_encrypted_guests=16, group='libvirt') # Still zero without mocked SEV support - self.assertEqual({}, self.driver._get_memory_encryption_inventories()) + self.assertEqual({ + 'amd_sev': { + 'total': 0 + }, + 'amd_sev_es': { + 'total': 0 + } + }, self.driver._get_memory_encryption_inventories()) mock_log.assert_called_with( 'Host is configured with libvirt.num_memory_encrypted_guests ' 'set to %d, but is not SEV-capable.', 16) def test_get_memory_encryption_inventories_unsupported(self): - self.assertEqual({}, self.driver._get_memory_encryption_inventories()) + self.assertEqual({ + 'amd_sev': { + 'total': 0 + }, + 'amd_sev_es': { + 'total': 0 + } + }, self.driver._get_memory_encryption_inventories()) @mock.patch.object(vc, '_domain_capability_features', @@ -31189,6 +31217,9 @@ class TestLibvirtSEVSupportedNoMaxGuests(TestLibvirtSEV): 'reserved': 0, 'allocation_ratio': 1.0, 'traits': [ot.HW_CPU_X86_AMD_SEV] + }, + 'amd_sev_es': { + 'total': 0 } }, self.driver._get_memory_encryption_inventories()) @@ -31204,6 +31235,9 @@ class TestLibvirtSEVSupportedNoMaxGuests(TestLibvirtSEV): 'reserved': 0, 'allocation_ratio': 1.0, 'traits': [ot.HW_CPU_X86_AMD_SEV] + }, + 'amd_sev_es': { + 'total': 0 } }, self.driver._get_memory_encryption_inventories()) @@ -31220,6 +31254,9 @@ class TestLibvirtSEVSupportedNoMaxGuests(TestLibvirtSEV): 'allocation_ratio': 1.0, 'traits': [ot.HW_CPU_X86_AMD_SEV] }, + 'amd_sev_es': { + 'total': 0 + }, }, self.driver._get_memory_encryption_inventories()) @@ -31250,6 +31287,9 @@ class TestLibvirtSEVSupportedMaxGuests(TestLibvirtSEV): 'allocation_ratio': 1.0, 'traits': [ot.HW_CPU_X86_AMD_SEV] }, + 'amd_sev_es': { + 'total': 0 + }, }, self.driver._get_memory_encryption_inventories()) mock_log.assert_not_called() @@ -31266,6 +31306,9 @@ class TestLibvirtSEVSupportedMaxGuests(TestLibvirtSEV): 'reserved': 0, 'allocation_ratio': 1.0, 'traits': [ot.HW_CPU_X86_AMD_SEV] + }, + 'amd_sev_es': { + 'total': 0 } }, self.driver._get_memory_encryption_inventories()) mock_log.assert_called_with( @@ -31285,6 +31328,9 @@ class TestLibvirtSEVSupportedMaxGuests(TestLibvirtSEV): 'reserved': 0, 'allocation_ratio': 1.0, 'traits': [ot.HW_CPU_X86_AMD_SEV] + }, + 'amd_sev_es': { + 'total': 0 } }, self.driver._get_memory_encryption_inventories()) mock_log.assert_not_called() diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index eefbfca78a..bd5cd6ff07 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -9811,7 +9811,14 @@ class LibvirtDriver(driver.ComputeDriver): LOG.warning("Host is configured with " "libvirt.num_memory_encrypted_guests set to " "%d, but is not SEV-capable.", conf_slots) - return {} + return { + 'amd_sev': { + 'total': 0 + }, + 'amd_sev_es': { + 'total': 0 + } + } sev_slots = db_const.MAX_INT @@ -9850,6 +9857,10 @@ class LibvirtDriver(driver.ComputeDriver): 'reserved': 0, 'traits': [ot.HW_CPU_X86_AMD_SEV_ES] } + else: + inventories['amd_sev_es'] = { + 'total': 0, + } LOG.debug("Available memory encrypted slots: " "AMD SEV=%d SEV-ES=%d", sev_slots, sev_es_slots)