From dc6641baad3f6902f238ace14ace6defb029a828 Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Mon, 2 Sep 2024 14:59:31 +0900 Subject: [PATCH] Add hw_mem_encryption_model image property This is prep work to support launching instances with AMD SEV-ES memory encryption and adds the object field to select the CPU feature to encrypt and protect memory data of instances. Partially-Implements: blueprint amd-sev-es-libvirt-support Change-Id: I71fde5438d4e22c9e2566f8a684c5a965a7f3dd3 Signed-off-by: Takashi Kajinami --- .../common_payloads/ImageMetaPropsPayload.json | 4 ++-- nova/notifications/objects/image.py | 3 ++- nova/objects/fields.py | 11 +++++++++++ nova/objects/image_meta.py | 11 +++++++++-- .../notification_sample_tests/test_instance.py | 4 ++-- .../notifications/objects/test_notification.py | 2 +- nova/tests/unit/objects/test_fields.py | 17 +++++++++++++++++ nova/tests/unit/objects/test_image_meta.py | 18 ++++++++++++++++++ nova/tests/unit/objects/test_objects.py | 2 +- 9 files changed, 63 insertions(+), 9 deletions(-) diff --git a/doc/notification_samples/common_payloads/ImageMetaPropsPayload.json b/doc/notification_samples/common_payloads/ImageMetaPropsPayload.json index e56e37ad72a7..96ee82e503c1 100644 --- a/doc/notification_samples/common_payloads/ImageMetaPropsPayload.json +++ b/doc/notification_samples/common_payloads/ImageMetaPropsPayload.json @@ -4,5 +4,5 @@ "hw_architecture": "x86_64" }, "nova_object.name": "ImageMetaPropsPayload", - "nova_object.version": "1.17" -} \ No newline at end of file + "nova_object.version": "1.18" +} diff --git a/nova/notifications/objects/image.py b/nova/notifications/objects/image.py index 68247b082cd6..b13c18fe8d68 100644 --- a/nova/notifications/objects/image.py +++ b/nova/notifications/objects/image.py @@ -135,7 +135,8 @@ class ImageMetaPropsPayload(base.NotificationPayloadBase): # Version 1.15: Added igb value to 'hw_vif_model' enum # Version 1.16: Added 'hw_sound_model' field # Version 1.17: Added 'hw_usb_model' and 'hw_redirected_usb_ports' fields - VERSION = '1.17' + # Version 1.18: Added 'hw_mem_encryption_model' field + VERSION = '1.18' # NOTE(efried): This logic currently relies on all of the fields of # ImageMetaProps being initialized with no arguments. See the docstring. diff --git a/nova/objects/fields.py b/nova/objects/fields.py index 147ef70de43e..d866bff56d2d 100644 --- a/nova/objects/fields.py +++ b/nova/objects/fields.py @@ -562,6 +562,13 @@ class TPMVersion(BaseNovaEnum): ALL = (v1_2, v2_0) +class MemEncryptionModel(BaseNovaEnum): + AMD_SEV = "amd-sev" + AMD_SEV_ES = "amd-sev-es" + + ALL = (AMD_SEV, AMD_SEV_ES) + + class MaxPhyAddrMode(BaseNovaEnum): PASSTHROUGH = "passthrough" EMULATE = "emulate" @@ -1366,6 +1373,10 @@ class TPMVersionField(BaseEnumField): AUTO_TYPE = TPMVersion() +class MemEncryptionModelField(BaseEnumField): + AUTO_TYPE = MemEncryptionModel() + + class SCSIModelField(BaseEnumField): AUTO_TYPE = SCSIModel() diff --git a/nova/objects/image_meta.py b/nova/objects/image_meta.py index 3ccb267cb7d2..caa9c0f8b981 100644 --- a/nova/objects/image_meta.py +++ b/nova/objects/image_meta.py @@ -200,15 +200,18 @@ class ImageMetaProps(base.NovaObject): # Version 1.39: Added igb value to 'hw_vif_model' enum # Version 1.40: Added 'hw_sound_model' field # Version 1.41: Added 'hw_usb_model' and 'hw_redirected_usb_ports' fields + # Version 1.42: Added 'hw_mem_encryption_model' field # NOTE(efried): When bumping this version, the version of # ImageMetaPropsPayload must also be bumped. See its docstring for details. - VERSION = '1.41' + VERSION = '1.42' - def obj_make_compatible(self, primitive, target_version): + def obj_make_compatible(self, primitive, target_version): # noqa: C901 super(ImageMetaProps, self).obj_make_compatible(primitive, target_version) target_version = versionutils.convert_version_to_tuple(target_version) + if target_version < (1, 42): + primitive.pop('hw_mem_encryption_model', None) if target_version < (1, 41): primitive.pop('hw_usb_model', None) primitive.pop('hw_redirected_usb_ports', None) @@ -406,6 +409,10 @@ class ImageMetaProps(base.NovaObject): # encrypted memory 'hw_mem_encryption': fields.FlexibleBooleanField(), + # string = used to determine the CPU feature for guest memory + # encryption + 'hw_mem_encryption_model': fields.MemEncryptionModelField(), + # One of the magic strings 'small', 'any', 'large' # or an explicit page size in KB (eg 4, 2048, ...) 'hw_mem_page_size': fields.StringField(), diff --git a/nova/tests/functional/notification_sample_tests/test_instance.py b/nova/tests/functional/notification_sample_tests/test_instance.py index 1f96029d607f..8c5e1f46013a 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -1244,7 +1244,7 @@ class TestInstanceNotificationSample( 'nova_object.data': {}, 'nova_object.name': 'ImageMetaPropsPayload', 'nova_object.namespace': 'nova', - 'nova_object.version': '1.17', + 'nova_object.version': '1.18', }, 'image.size': 58145823, 'image.tags': [], @@ -1340,7 +1340,7 @@ class TestInstanceNotificationSample( 'nova_object.data': {}, 'nova_object.name': 'ImageMetaPropsPayload', 'nova_object.namespace': 'nova', - 'nova_object.version': '1.17', + 'nova_object.version': '1.18', }, 'image.size': 58145823, 'image.tags': [], diff --git a/nova/tests/unit/notifications/objects/test_notification.py b/nova/tests/unit/notifications/objects/test_notification.py index 46f68b5dfb5e..57e5cbe22e78 100644 --- a/nova/tests/unit/notifications/objects/test_notification.py +++ b/nova/tests/unit/notifications/objects/test_notification.py @@ -385,7 +385,7 @@ notification_object_data = { # ImageMetaProps, so when you see a fail here for that reason, you must # *also* bump the version of ImageMetaPropsPayload. See its docstring for # more information. - 'ImageMetaPropsPayload': '1.17-60ebfe97483b0abee1ec22220613da40', + 'ImageMetaPropsPayload': '1.18-9d551c98a62b766cb94fb472aa3e73f9', 'InstanceActionNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'InstanceActionPayload': '1.9-525dcf81b6e4592d935712a2675309dc', 'InstanceActionRebuildNotification': diff --git a/nova/tests/unit/objects/test_fields.py b/nova/tests/unit/objects/test_fields.py index 461dc0ff6f55..3c48806eaad4 100644 --- a/nova/tests/unit/objects/test_fields.py +++ b/nova/tests/unit/objects/test_fields.py @@ -691,6 +691,23 @@ class TestXenAddress(TestField): self.from_primitive_values = self.coerce_good_values +class TestMemEncryptionModel(TestField): + def setUp(self): + super(TestMemEncryptionModel, self).setUp() + self.field = fields.MemEncryptionModel() + self.coerce_good_values = [('amd-sev', 'amd-sev'), + ('amd-sev-es', 'amd-sev-es')] + self.coerce_bad_values = ['amd-sev-foo'] + self.to_primitive_values = self.coerce_good_values[0:1] + self.from_primitive_values = self.coerce_good_values[0:1] + + def test_stringify(self): + self.assertEqual("'amd-sev'", self.field.stringify('amd-sev')) + + def test_stringify_invalid(self): + self.assertRaises(ValueError, self.field.stringify, 'amd-sev-foo') + + class TestSecureBoot(TestField): def setUp(self): super(TestSecureBoot, self).setUp() diff --git a/nova/tests/unit/objects/test_image_meta.py b/nova/tests/unit/objects/test_image_meta.py index fab3ae81d5ca..b23a08fb9007 100644 --- a/nova/tests/unit/objects/test_image_meta.py +++ b/nova/tests/unit/objects/test_image_meta.py @@ -657,3 +657,21 @@ class TestImageMetaProps(test.NoDBTestCase): exception.ObjectActionError, obj.obj_to_primitive, '1.38') self.assertIn( 'hw_vif_model=igb not supported in version (1, 38)', str(ex)) + + def test_obj_make_compatible_mem_encryption_model(self): + """Check 'hw_mem_encryption_model' compatibility.""" + obj = objects.ImageMetaProps( + hw_mem_encryption_model=fields.MemEncryptionModel.AMD_SEV) + + primitive = obj.obj_to_primitive('1.42') + self.assertIn( + 'hw_mem_encryption_model', + primitive['nova_object.data']) + self.assertEqual( + fields.MemEncryptionModel.AMD_SEV, + primitive['nova_object.data']['hw_mem_encryption_model']) + + primitive = obj.obj_to_primitive('1.41') + self.assertNotIn( + 'hw_mem_encryption_model', + primitive['nova_object.data']) diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py index 7601ffa8c15e..4a60fd4086cd 100644 --- a/nova/tests/unit/objects/test_objects.py +++ b/nova/tests/unit/objects/test_objects.py @@ -1105,7 +1105,7 @@ object_data = { 'HyperVLiveMigrateData': '1.5-b424b27305f259fb3c15d720856585c7', 'IDEDeviceBus': '1.0-29d4c9f27ac44197f01b6ac1b7e16502', 'ImageMeta': '1.8-642d1b2eb3e880a367f37d72dd76162d', - 'ImageMetaProps': '1.41-1b67f6d0ae2292c3e50b838564e329c8', + 'ImageMetaProps': '1.42-e2e85f8e6d66bfa2a32f3ee13506bb58', 'Instance': '2.8-2727dba5e4a078e6cc848c1f94f7eb24', 'InstanceAction': '1.2-9a5abc87fdd3af46f45731960651efb5', 'InstanceActionEvent': '1.4-5b1f361bd81989f8bb2c20bb7e8a4cb4',