Merge "Follow-up of AMD SEV-ES support"
This commit is contained in:
@@ -330,10 +330,12 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase):
|
||||
|
||||
def setUp(self):
|
||||
super(LibvirtReportSevTraitsTests, self).setUp()
|
||||
|
||||
def _init_compute(self, sev, sev_es):
|
||||
sev_features = (fakelibvirt.virConnect.
|
||||
_domain_capability_features_with_SEV_max_guests)
|
||||
with test.nested(
|
||||
self._patch_sev_exists(True, True),
|
||||
self._patch_sev_exists(sev, sev_es),
|
||||
self._patch_sev_open(),
|
||||
mock.patch.object(fakelibvirt.virConnect,
|
||||
'_domain_capability_features',
|
||||
@@ -346,20 +348,106 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase):
|
||||
self.start_compute()
|
||||
|
||||
def test_sev_trait_on_off(self):
|
||||
"""Test that the compute service reports the SEV/SEV-ES trait in
|
||||
"""Test that the compute service reports the SEV trait in
|
||||
the list of global traits, and immediately registers it on the compute
|
||||
host resource provider in the placement API, due to the SEV/SEV-ES
|
||||
host resource provider in the placement API, due to the SEV
|
||||
capability being (mocked as) present.
|
||||
|
||||
Then test that if the SEV/SEV-ES capability disappears (again via
|
||||
Then test that if the SEV capability disappears (again via mocking),
|
||||
after a restart of the compute service, the trait gets removed from
|
||||
the compute host.
|
||||
|
||||
Also test that on both occasions, the inventory of the
|
||||
MEM_ENCRYPTION_CONTEXT resource class on the compute host
|
||||
corresponds to the absence or presence of the SEV capability.
|
||||
"""
|
||||
self._init_compute(True, False)
|
||||
|
||||
# Make sure that SEV is enabled but SEV-ES is not enabled
|
||||
self.assertTrue(self.compute.driver._host.supports_amd_sev)
|
||||
self.assertFalse(self.compute.driver._host.supports_amd_sev_es)
|
||||
|
||||
global_traits = self._get_all_traits()
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV, global_traits)
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV_ES, global_traits)
|
||||
|
||||
# sev capabilities are managed by sub rp and are not present in root rp
|
||||
traits = self._get_provider_traits(self.host_uuid)
|
||||
self.assertNotIn(ost.HW_CPU_X86_AMD_SEV, traits)
|
||||
self.assertMemEncryptionSlotsEqual(self.host_uuid, 0)
|
||||
|
||||
sev_rps = self._get_amd_sev_rps()
|
||||
|
||||
self.assertEqual(1, len(sev_rps['sev']))
|
||||
sev_rp_uuid = sev_rps['sev'][0]['uuid']
|
||||
sev_rp_traits = self._get_provider_traits(sev_rp_uuid)
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV, sev_rp_traits)
|
||||
self.assertMemEncryptionSlotsEqual(sev_rp_uuid, 100)
|
||||
|
||||
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
|
||||
# the kvm-amd kernel module's "sev-" parameter to become
|
||||
# unavailable.
|
||||
sev_features = (fakelibvirt.virConnect.
|
||||
_domain_capability_features_with_SEV)
|
||||
with test.nested(
|
||||
self._patch_sev_exists(False, False),
|
||||
self._patch_sev_open(),
|
||||
mock.patch.object(fakelibvirt.virConnect,
|
||||
'_domain_capability_features',
|
||||
new=sev_features)
|
||||
) as (mock_exists, mock_open, mock_features):
|
||||
# Retrigger the detection code. In the real world this
|
||||
# would be a restart of the compute service.
|
||||
self.compute.driver._host._domain_caps = None
|
||||
self.compute.driver._host._supports_amd_sev = None
|
||||
self.compute.driver._host._supports_amd_sev_es = None
|
||||
self.assertFalse(self.compute.driver._host.supports_amd_sev)
|
||||
self.assertFalse(self.compute.driver._host.supports_amd_sev_es)
|
||||
|
||||
mock_exists.assert_has_calls([
|
||||
mock.call(libvirt_host.SEV_KERNEL_PARAM_FILE % 'sev'),
|
||||
])
|
||||
|
||||
# However it won't disappear in the provider tree and get synced
|
||||
# back to placement until we force a reinventory:
|
||||
self.compute.manager.reset()
|
||||
# reset cached traits so they are recalculated.
|
||||
self.compute.driver._static_traits = None
|
||||
self._run_periodics()
|
||||
|
||||
# Sanity check that we've still got the trait globally.
|
||||
global_traits = self._get_all_traits()
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV, global_traits)
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV_ES, global_traits)
|
||||
|
||||
traits = self._get_provider_traits(self.host_uuid)
|
||||
self.assertNotIn(ost.HW_CPU_X86_AMD_SEV, traits)
|
||||
self.assertNotIn(ost.HW_CPU_X86_AMD_SEV_ES, traits)
|
||||
|
||||
sev_rps = self._get_amd_sev_rps()
|
||||
self.assertEqual(0, len(sev_rps['sev']))
|
||||
self.assertEqual(0, len(sev_rps['sev-es']))
|
||||
|
||||
def test_sev_es_trait_on_off(self):
|
||||
"""Test that the compute service reports the SEV-ES trait in
|
||||
the list of global traits, and immediately registers it on the compute
|
||||
host resource provider in the placement API, due to the SEV-ES
|
||||
capability being (mocked as) present.
|
||||
|
||||
Then test that if the SEV-ES capability disappears (again via
|
||||
mocking), after a restart of the compute service, the trait
|
||||
gets removed from the compute host.
|
||||
|
||||
Also test that on both occasions, the inventory of the
|
||||
MEM_ENCRYPTION_CONTEXT resource class on the compute host
|
||||
corresponds to the absence or presence of the SEV/SEV-ES capability.
|
||||
corresponds to the absence or presence of the SEV-ES capability.
|
||||
"""
|
||||
self._init_compute(True, True)
|
||||
|
||||
# Make sure that both SEV and SEV-ES are enabled
|
||||
self.assertTrue(self.compute.driver._host.supports_amd_sev)
|
||||
self.assertTrue(self.compute.driver._host.supports_amd_sev_es)
|
||||
|
||||
@@ -437,10 +525,54 @@ class LibvirtReportSevTraitsTests(LibvirtReportTraitsTestBase):
|
||||
self.assertEqual(1, len(sev_rps['sev']))
|
||||
self.assertEqual(0, len(sev_rps['sev-es']))
|
||||
|
||||
# Now simulate the host losing SEV functionality. Here we
|
||||
def test_sev_all_trait_on_off(self):
|
||||
"""Test that the compute service reports the SEV/SEV-ES trait in
|
||||
the list of global traits, and immediately registers it on the compute
|
||||
host resource provider in the placement API, due to the SEV/SEV-ES
|
||||
capability being (mocked as) present.
|
||||
|
||||
Then test that if the SEV/SEV-ES capability disappears (again via
|
||||
mocking), after a restart of the compute service, the trait
|
||||
gets removed from the compute host.
|
||||
|
||||
Also test that on both occasions, the inventory of the
|
||||
MEM_ENCRYPTION_CONTEXT resource class on the compute host
|
||||
corresponds to the absence or presence of the SEV/SEV-ES capability.
|
||||
"""
|
||||
self._init_compute(True, True)
|
||||
|
||||
# Make sure that both SEV and SEV-ES are enabled
|
||||
self.assertTrue(self.compute.driver._host.supports_amd_sev)
|
||||
self.assertTrue(self.compute.driver._host.supports_amd_sev_es)
|
||||
global_traits = self._get_all_traits()
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV, global_traits)
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV_ES, global_traits)
|
||||
|
||||
# sev capabilities are managed by sub rp and are not present in root rp
|
||||
traits = self._get_provider_traits(self.host_uuid)
|
||||
self.assertNotIn(ost.HW_CPU_X86_AMD_SEV, traits)
|
||||
self.assertMemEncryptionSlotsEqual(self.host_uuid, 0)
|
||||
|
||||
sev_rps = self._get_amd_sev_rps()
|
||||
|
||||
self.assertEqual(1, len(sev_rps['sev']))
|
||||
sev_rp_uuid = sev_rps['sev'][0]['uuid']
|
||||
sev_rp_traits = self._get_provider_traits(sev_rp_uuid)
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV, sev_rp_traits)
|
||||
self.assertMemEncryptionSlotsEqual(sev_rp_uuid, 100)
|
||||
|
||||
self.assertEqual(1, len(sev_rps['sev-es']))
|
||||
sev_es_rp_uuid = sev_rps['sev-es'][0]['uuid']
|
||||
sev_es_rp_traits = self._get_provider_traits(sev_es_rp_uuid)
|
||||
self.assertIn(ost.HW_CPU_X86_AMD_SEV_ES, sev_es_rp_traits)
|
||||
self.assertMemEncryptionSlotsEqual(sev_es_rp_uuid, 15)
|
||||
self.assertEqual(1, len(sev_rps['sev']))
|
||||
|
||||
# Now simulate the host losing SEV/SEV-ES functionality. Here we
|
||||
# simulate a kernel downgrade or reconfiguration which causes
|
||||
# the kvm-amd kernel module's "sev-" parameter to become
|
||||
# unavailable.
|
||||
# the kvm-amd kernel module's "sev" parameter and "sev-es" parameter
|
||||
# to become unavailable, however it could also happen via a libvirt
|
||||
# downgrade, for instance.
|
||||
sev_features = (fakelibvirt.virConnect.
|
||||
_domain_capability_features_with_SEV)
|
||||
with test.nested(
|
||||
|
||||
@@ -280,6 +280,7 @@ class SevResphapeTests(base.ServersTestBase):
|
||||
compute_rp_uuid = self._get_provider_uuid_by_name('compute1')
|
||||
inventories = self.placement.get(
|
||||
'/resource_providers/%s/inventories' % compute_rp_uuid).body
|
||||
# MEM_ENCRYPTION_CONTEXT inventory was added to compute RP
|
||||
inventories['inventories']['MEM_ENCRYPTION_CONTEXT'] = {
|
||||
'allocation_ratio': 1.0,
|
||||
'max_unit': 1,
|
||||
@@ -290,6 +291,7 @@ class SevResphapeTests(base.ServersTestBase):
|
||||
self.placement.put(
|
||||
'/resource_providers/%s/inventories' % compute_rp_uuid,
|
||||
inventories)
|
||||
# SEV trait was also added to compute RP
|
||||
traits = self._get_provider_traits(compute_rp_uuid)
|
||||
traits.append(os_traits.HW_CPU_X86_AMD_SEV)
|
||||
self._set_provider_traits(compute_rp_uuid, traits)
|
||||
@@ -322,13 +324,14 @@ class SevResphapeTests(base.ServersTestBase):
|
||||
self.assertNotIn('MEM_ENCRYPTION_CONTEXT', compute_inventories)
|
||||
compute_usages = self._get_provider_usages(compute_rp_uuid)
|
||||
self.assertNotIn('MEM_ENCRYPTION_CONTEXT', compute_usages)
|
||||
|
||||
# MEM_ENCRYPTION_CONTEXT inventory/usage should be moreved to child RP
|
||||
sev_rp_uuid = self._get_provider_uuid_by_name('compute1_amd_sev')
|
||||
sev_inventories = self._get_provider_inventory(sev_rp_uuid)
|
||||
self.assertEqual(
|
||||
16, sev_inventories['MEM_ENCRYPTION_CONTEXT']['total'])
|
||||
sev_usages = self._get_provider_usages(sev_rp_uuid)
|
||||
self.assertEqual(1, sev_usages['MEM_ENCRYPTION_CONTEXT'])
|
||||
# SEV trait should be also moved to child RP
|
||||
sev_traits = self._get_provider_traits(sev_rp_uuid)
|
||||
self.assertIn(os_traits.HW_CPU_X86_AMD_SEV, sev_traits)
|
||||
|
||||
@@ -370,6 +373,7 @@ class SevResphapeTests(base.ServersTestBase):
|
||||
compute_rp_uuid = self._get_provider_uuid_by_name(name)
|
||||
inventories = self.placement.get(
|
||||
'/resource_providers/%s/inventories' % compute_rp_uuid).body
|
||||
# MEM_ENCRYPTION_CONTEXT inventory was added to compute RP
|
||||
inventories['inventories']['MEM_ENCRYPTION_CONTEXT'] = {
|
||||
'allocation_ratio': 1.0,
|
||||
'max_unit': 1,
|
||||
@@ -380,6 +384,7 @@ class SevResphapeTests(base.ServersTestBase):
|
||||
self.placement.put(
|
||||
'/resource_providers/%s/inventories' % compute_rp_uuid,
|
||||
inventories)
|
||||
# SEV trait was also added to compute root RP
|
||||
traits = self._get_provider_traits(compute_rp_uuid)
|
||||
traits.append(os_traits.HW_CPU_X86_AMD_SEV)
|
||||
self._set_provider_traits(compute_rp_uuid, traits)
|
||||
@@ -444,7 +449,7 @@ class SevResphapeTests(base.ServersTestBase):
|
||||
sev_usages = self._get_provider_usages(sev_rp_uuid)
|
||||
self.assertEqual(1, sev_usages['MEM_ENCRYPTION_CONTEXT'])
|
||||
|
||||
# server2 should allocate M_E_C from compute RP
|
||||
# server2 should allocate M_E_C from compute root RP
|
||||
compute_rp_uuid = self._get_provider_uuid_by_name('compute2')
|
||||
compute_usages = self._get_provider_usages(compute_rp_uuid)
|
||||
self.assertEqual(1, compute_usages['MEM_ENCRYPTION_CONTEXT'])
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import itertools
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
@@ -2301,6 +2302,7 @@ class TestUtils(TestUtilsBase):
|
||||
mock_map.assert_called_once_with(allocation, {uuids.rp_uuid: traits})
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestEncryptedMemoryTranslation(TestUtilsBase):
|
||||
flavor_name = 'm1.test'
|
||||
image_name = 'cirros'
|
||||
@@ -2333,13 +2335,13 @@ class TestEncryptedMemoryTranslation(TestUtilsBase):
|
||||
'MEMORY_MB': 1024,
|
||||
'DISK_GB': 15,
|
||||
}
|
||||
required_traits = []
|
||||
required_traits = set()
|
||||
if mem_encryption_model == 'amd-sev':
|
||||
expected_resources[orc.MEM_ENCRYPTION_CONTEXT] = 1
|
||||
required_traits = ['HW_CPU_X86_AMD_SEV']
|
||||
required_traits |= {'HW_CPU_X86_AMD_SEV'}
|
||||
elif mem_encryption_model == 'amd-sev-es':
|
||||
expected_resources[orc.MEM_ENCRYPTION_CONTEXT] = 1
|
||||
required_traits = ['HW_CPU_X86_AMD_SEV_ES']
|
||||
required_traits |= {'HW_CPU_X86_AMD_SEV_ES'}
|
||||
elif mem_encryption_model is not None:
|
||||
self.fail('invalid mem_encryption_model: %s'
|
||||
% mem_encryption_model)
|
||||
@@ -2348,7 +2350,7 @@ class TestEncryptedMemoryTranslation(TestUtilsBase):
|
||||
expected._rg_by_id[None] = objects.RequestGroup(
|
||||
use_same_provider=False,
|
||||
resources=expected_resources,
|
||||
required_traits=set(required_traits)
|
||||
required_traits=required_traits
|
||||
)
|
||||
return expected
|
||||
|
||||
@@ -2362,34 +2364,35 @@ class TestEncryptedMemoryTranslation(TestUtilsBase):
|
||||
def test_encrypted_memory_support_empty_extra_specs(self):
|
||||
self._test_encrypted_memory_support_not_required(extra_specs={})
|
||||
|
||||
def test_encrypted_memory_support_false_extra_spec(self):
|
||||
for extra_spec in ('0', 'false', 'False'):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={'hw:mem_encryption': extra_spec})
|
||||
@ddt.data('0', 'false', 'False')
|
||||
def test_encrypted_memory_support_false_extra_spec(self, extra_spec):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={'hw:mem_encryption': extra_spec})
|
||||
|
||||
def test_encrypted_memory_support_empty_image_props(self):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={},
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps()))
|
||||
|
||||
def test_encrypted_memory_support_false_image_prop(self):
|
||||
for image_prop in ('0', 'false', 'False'):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={},
|
||||
image=objects.ImageMeta(
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
@ddt.data('0', 'false', 'False')
|
||||
def test_encrypted_memory_support_false_image_prop(self, image_prop):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={},
|
||||
image=objects.ImageMeta(
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
|
||||
def test_encrypted_memory_support_both_false(self):
|
||||
for extra_spec in ('0', 'false', 'False'):
|
||||
for image_prop in ('0', 'false', 'False'):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={'hw:mem_encryption': extra_spec},
|
||||
image=objects.ImageMeta(
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
@ddt.unpack
|
||||
@ddt.data(*itertools.product(
|
||||
('0', 'false', 'False'), ('0', 'false', 'False')))
|
||||
def test_encrypted_memory_support_both_false(self, image_prop, extra_spec):
|
||||
self._test_encrypted_memory_support_not_required(
|
||||
extra_specs={'hw:mem_encryption': extra_spec},
|
||||
image=objects.ImageMeta(
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
|
||||
def _test_encrypted_memory_support_conflict(self, extra_spec,
|
||||
image_prop_in,
|
||||
@@ -2432,19 +2435,25 @@ class TestEncryptedMemoryTranslation(TestUtilsBase):
|
||||
}
|
||||
self.assertEqual(error % error_data, str(exc))
|
||||
|
||||
def test_encrypted_memory_support_conflict1(self):
|
||||
for extra_spec in ('0', 'false', 'False'):
|
||||
for image_prop_in in ('1', 'true', 'True'):
|
||||
self._test_encrypted_memory_support_conflict(
|
||||
extra_spec, image_prop_in, True
|
||||
)
|
||||
@ddt.unpack
|
||||
@ddt.data(*itertools.product(
|
||||
('1', 'true', 'True'),
|
||||
('0', 'false', 'False')))
|
||||
def test_encrypted_memory_support_conflict1(
|
||||
self, image_prop_in, extra_spec):
|
||||
self._test_encrypted_memory_support_conflict(
|
||||
extra_spec, image_prop_in, True
|
||||
)
|
||||
|
||||
def test_encrypted_memory_support_conflict2(self):
|
||||
for extra_spec in ('1', 'true', 'True'):
|
||||
for image_prop_in in ('0', 'false', 'False'):
|
||||
self._test_encrypted_memory_support_conflict(
|
||||
extra_spec, image_prop_in, False
|
||||
)
|
||||
@ddt.unpack
|
||||
@ddt.data(*itertools.product(
|
||||
('0', 'false', 'False'),
|
||||
('1', 'true', 'True')))
|
||||
def test_encrypted_memory_support_conflict2(
|
||||
self, image_prop_in, extra_spec):
|
||||
self._test_encrypted_memory_support_conflict(
|
||||
extra_spec, image_prop_in, False
|
||||
)
|
||||
|
||||
@mock.patch.object(utils, 'LOG')
|
||||
def _test_encrypted_memory_support_required(self, requesters, extra_specs,
|
||||
@@ -2467,120 +2476,122 @@ class TestEncryptedMemoryTranslation(TestUtilsBase):
|
||||
model, me_trait)
|
||||
])
|
||||
|
||||
def test_encrypted_memory_support_extra_spec(self):
|
||||
for extra_spec in ('1', 'true', 'True'):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec',
|
||||
{'hw:mem_encryption': extra_spec},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi'))
|
||||
)
|
||||
@ddt.data('1', 'true', 'True')
|
||||
def test_encrypted_memory_support_extra_spec(self, extra_spec):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec',
|
||||
{'hw:mem_encryption': extra_spec},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi'))
|
||||
)
|
||||
|
||||
def test_encrypted_memory_support_image_prop(self):
|
||||
for image_prop in ('1', 'true', 'True'):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw_mem_encryption image property',
|
||||
{},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
@ddt.data('1', 'true', 'True')
|
||||
def test_encrypted_memory_support_image_prop(self, image_prop):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw_mem_encryption image property',
|
||||
{},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
|
||||
def test_encrypted_memory_support_both_required(self):
|
||||
for extra_spec in ('1', 'true', 'True'):
|
||||
for image_prop in ('1', 'true', 'True'):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec and '
|
||||
'hw_mem_encryption image property',
|
||||
{'hw:mem_encryption': extra_spec},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
@ddt.unpack
|
||||
@ddt.data(*itertools.product(
|
||||
('1', 'true', 'True'), ('1', 'true', 'True')))
|
||||
def test_encrypted_memory_support_both_required(
|
||||
self, image_prop, extra_spec):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec and '
|
||||
'hw_mem_encryption image property',
|
||||
{'hw:mem_encryption': extra_spec},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption=image_prop))
|
||||
)
|
||||
|
||||
def test_encrypted_memory_model_extra_spec(self):
|
||||
for model in ('amd-sev', 'amd-sev-es'):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec',
|
||||
{'hw:mem_encryption': 'true',
|
||||
'hw:mem_encryption_model': model},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi')),
|
||||
model=model
|
||||
)
|
||||
@ddt.data('amd-sev', 'amd-sev-es')
|
||||
def test_encrypted_memory_model_extra_spec(self, model):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec',
|
||||
{'hw:mem_encryption': 'true',
|
||||
'hw:mem_encryption_model': model},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi')),
|
||||
model=model
|
||||
)
|
||||
|
||||
def test_encrypted_memory_model_image_prop(self):
|
||||
for model in ('amd-sev', 'amd-sev-es'):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw_mem_encryption image property',
|
||||
{},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption='true',
|
||||
hw_mem_encryption_model=model)),
|
||||
model=model
|
||||
)
|
||||
|
||||
def test_encrypted_memory_model_both_required(self):
|
||||
for model in ('amd-sev', 'amd-sev-es'):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec and '
|
||||
'hw_mem_encryption image property',
|
||||
{'hw:mem_encryption': 'true',
|
||||
'hw:mem_encryption_model': model},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption='true',
|
||||
hw_mem_encryption_model=model)),
|
||||
model=model
|
||||
)
|
||||
|
||||
def test_encrypted_memory_model_conflict_1(self):
|
||||
for f_model, i_model in (
|
||||
('amd-sev', 'amd-sev-es'),
|
||||
('amd-sev-es', 'amd-sev')
|
||||
):
|
||||
image = objects.ImageMeta(
|
||||
@ddt.data('amd-sev', 'amd-sev-es')
|
||||
def test_encrypted_memory_model_image_prop(self, model):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw_mem_encryption image property',
|
||||
{},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption='true',
|
||||
hw_mem_encryption_model=i_model
|
||||
)
|
||||
)
|
||||
reqspec = self._get_request_spec(
|
||||
extra_specs={
|
||||
'hw:mem_encryption': 'true',
|
||||
'hw:mem_encryption_model': f_model,
|
||||
},
|
||||
image=image)
|
||||
self.assertRaises(
|
||||
exception.FlavorImageConflict,
|
||||
utils.ResourceRequest.from_request_spec, reqspec
|
||||
hw_mem_encryption_model=model)),
|
||||
model=model
|
||||
)
|
||||
|
||||
@ddt.data('amd-sev', 'amd-sev-es')
|
||||
def test_encrypted_memory_model_both_required(self, model):
|
||||
self._test_encrypted_memory_support_required(
|
||||
'hw:mem_encryption extra spec and '
|
||||
'hw_mem_encryption image property',
|
||||
{'hw:mem_encryption': 'true',
|
||||
'hw:mem_encryption_model': model},
|
||||
image=objects.ImageMeta(
|
||||
id='005249be-3c2f-4351-9df7-29bb13c21b14',
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption='true',
|
||||
hw_mem_encryption_model=model)),
|
||||
model=model
|
||||
)
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
('amd-sev', 'amd-sev-es'),
|
||||
('amd-sev-es', 'amd-sev'))
|
||||
def test_encrypted_memory_model_conflict_1(self, f_model, i_model):
|
||||
image = objects.ImageMeta(
|
||||
name=self.image_name,
|
||||
properties=objects.ImageMetaProps(
|
||||
hw_machine_type='q35',
|
||||
hw_firmware_type='uefi',
|
||||
hw_mem_encryption='true',
|
||||
hw_mem_encryption_model=i_model
|
||||
)
|
||||
)
|
||||
reqspec = self._get_request_spec(
|
||||
extra_specs={
|
||||
'hw:mem_encryption': 'true',
|
||||
'hw:mem_encryption_model': f_model,
|
||||
},
|
||||
image=image)
|
||||
self.assertRaises(
|
||||
exception.FlavorImageConflict,
|
||||
utils.ResourceRequest.from_request_spec, reqspec
|
||||
)
|
||||
|
||||
|
||||
class TestResourcesFromRequestGroupDefaultPolicy(test.NoDBTestCase):
|
||||
|
||||
@@ -2716,11 +2716,11 @@ class LibvirtConfigGuestTest(LibvirtConfigBaseTest):
|
||||
|
||||
self.assertXmlEqual(launch_security_expected, xml)
|
||||
|
||||
obj.policy = 0x0035
|
||||
obj.policy = obj.DEFAULT_SEV_ES_POLICY
|
||||
xml = obj.to_xml()
|
||||
launch_security_expected = """
|
||||
<launchSecurity type="sev">
|
||||
<policy>0x0035</policy>
|
||||
<policy>0x0037</policy>
|
||||
<cbitpos>47</cbitpos>
|
||||
<reducedPhysBits>1</reducedPhysBits>
|
||||
</launchSecurity>"""
|
||||
|
||||
@@ -3974,7 +3974,7 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
@ddt.data(
|
||||
{'sev_model': None, 'sev_policy': 0x0033},
|
||||
{'sev_model': 'amd-sev', 'sev_policy': 0x0033},
|
||||
{'sev_model': 'amd-sev-es', 'sev_policy': 0x0035}
|
||||
{'sev_model': 'amd-sev-es', 'sev_policy': 0x0037}
|
||||
)
|
||||
@mock.patch.object(host.Host, 'get_domain_capabilities')
|
||||
@mock.patch.object(designer, 'set_driver_iommu_for_all_devices')
|
||||
|
||||
@@ -3018,13 +3018,27 @@ class LibvirtConfigGuestFeatureHyperV(LibvirtConfigGuestFeature):
|
||||
|
||||
|
||||
class LibvirtConfigGuestSEVLaunchSecurity(LibvirtConfigObject):
|
||||
# NOTE(tkajinam): See also
|
||||
# https://gitlab.com/qemu-project/qemu/-/blob/v10.1.0/target/i386/sev.h
|
||||
SEV_POLICY_NODEBG = 0x1
|
||||
SEV_POLICY_NOKS = 0x2
|
||||
SEV_POLICY_ES = 0x4
|
||||
SEV_POLICY_NOSEND = 0x8
|
||||
SEV_POLICY_DOMAIN = 0x10
|
||||
SEV_POLICY_SEV = 0x20
|
||||
|
||||
DEFAULT_SEV_POLICY = (
|
||||
SEV_POLICY_NODEBG | SEV_POLICY_NOKS |
|
||||
SEV_POLICY_DOMAIN | SEV_POLICY_SEV)
|
||||
DEFAULT_SEV_ES_POLICY = (
|
||||
DEFAULT_SEV_POLICY | SEV_POLICY_ES)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(LibvirtConfigGuestSEVLaunchSecurity, self).__init__(
|
||||
root_name='launchSecurity', **kwargs)
|
||||
|
||||
# hardcoded default for SEV according to the spec
|
||||
self.policy = 0x0033
|
||||
# Use SEV policy as default, because SEV is the default encryption
|
||||
# model
|
||||
self.policy = self.DEFAULT_SEV_POLICY
|
||||
self.cbitpos = None
|
||||
self.reduced_phys_bits = None
|
||||
|
||||
|
||||
+13
-12
@@ -7702,8 +7702,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
launch_security = vconfig.LibvirtConfigGuestSEVLaunchSecurity()
|
||||
launch_security.cbitpos = sev.cbitpos
|
||||
launch_security.reduced_phys_bits = sev.reduced_phys_bits
|
||||
# NOTE(tkajinam): Default policy is for SEV
|
||||
if model == fields.MemEncryptionModel.AMD_SEV_ES:
|
||||
launch_security.policy = 0x0035
|
||||
launch_security.policy = launch_security.DEFAULT_SEV_ES_POLICY
|
||||
guest.launch_security = launch_security
|
||||
|
||||
def _find_sev_feature(self, arch, mach_type):
|
||||
@@ -9560,8 +9561,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
metadata=vpmem)
|
||||
resources[rc].add(resource_obj)
|
||||
|
||||
def _update_provider_tree_for_memory_encryption(self, provider_tree,
|
||||
nodename, allocations):
|
||||
def _update_provider_tree_for_memory_encryption(
|
||||
self, provider_tree, nodename, allocations):
|
||||
"""Updates the provider tree for MEM_ENCRYPTION_CONTEXT inventory.
|
||||
|
||||
Before 2025.2, MEM_ENCRYPTION_CONTEXT inventory and allocations were on
|
||||
@@ -9626,8 +9627,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
root_node = provider_tree.data(nodename)
|
||||
return orc.MEM_ENCRYPTION_CONTEXT in root_node.inventory
|
||||
|
||||
def _ensure_memory_encryption_providers(self, inventories_dict,
|
||||
provider_tree, nodename):
|
||||
def _ensure_memory_encryption_providers(
|
||||
self, inventories_dict, provider_tree, nodename):
|
||||
"""Ensures MEM_ENCRYPTION_CONTEXT inventory providers exist in the tree
|
||||
for $nodename.
|
||||
|
||||
@@ -9660,7 +9661,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
if not inventory['total']:
|
||||
if provider_tree.exists(me_rp_name):
|
||||
provider_tree.remove(me_rp_name)
|
||||
break
|
||||
continue
|
||||
if not provider_tree.exists(me_rp_name):
|
||||
provider_tree.new_child(me_rp_name, nodename)
|
||||
me_rp = provider_tree.data(me_rp_name)
|
||||
@@ -9847,8 +9848,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
root_node = provider_tree.data(nodename)
|
||||
return orc.VGPU in root_node.inventory
|
||||
|
||||
def _ensure_pgpu_providers(self, inventories_dict, provider_tree,
|
||||
nodename):
|
||||
def _ensure_pgpu_providers(
|
||||
self, inventories_dict, provider_tree, nodename):
|
||||
"""Ensures GPU inventory providers exist in the tree for $nodename.
|
||||
|
||||
GPU providers are named $nodename_$gpu-device-id, e.g.
|
||||
@@ -10116,8 +10117,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
rp_uuid, root_node, consumer_uuid, alloc_data,
|
||||
resources, pgpu_rps)
|
||||
|
||||
def _update_provider_tree_for_vgpu(self, provider_tree, nodename,
|
||||
allocations=None):
|
||||
def _update_provider_tree_for_vgpu(
|
||||
self, provider_tree, nodename, allocations=None):
|
||||
"""Updates the provider tree for VGPU inventory.
|
||||
|
||||
Before Stein, VGPU inventory and allocations were on the root compute
|
||||
@@ -10173,8 +10174,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
del root_node.inventory[orc.VGPU]
|
||||
provider_tree.update_inventory(nodename, root_node.inventory)
|
||||
|
||||
def _update_provider_tree_for_pcpu(self, provider_tree, nodename,
|
||||
allocations=None):
|
||||
def _update_provider_tree_for_pcpu(
|
||||
self, provider_tree, nodename, allocations=None):
|
||||
"""Updates the provider tree for PCPU inventory.
|
||||
|
||||
Before Train, pinned instances consumed VCPU inventory just like
|
||||
|
||||
Reference in New Issue
Block a user