diff --git a/nova/compute/api.py b/nova/compute/api.py index 93283711b372..ea842e4c2eea 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1398,8 +1398,15 @@ class API(base.Base): instance.old_flavor = None instance.new_flavor = None if CONF.ephemeral_storage_encryption.enabled: + # NOTE(kfarr): dm-crypt expects the cipher in a + # hyphenated format: cipher-chainmode-ivmode + # (ex: aes-xts-plain64). The algorithm needs + # to be parsed out to pass to the key manager (ex: aes). + cipher = CONF.ephemeral_storage_encryption.cipher + algorithm = cipher.split('-')[0] if cipher else None instance.ephemeral_key_uuid = self.key_manager.create_key( context, + algorithm=algorithm, length=CONF.ephemeral_storage_encryption.key_size) else: instance.ephemeral_key_uuid = None diff --git a/nova/conf/ephemeral_storage.py b/nova/conf/ephemeral_storage.py index 8747cfc27287..4f21a12e180c 100644 --- a/nova/conf/ephemeral_storage.py +++ b/nova/conf/ephemeral_storage.py @@ -39,9 +39,10 @@ Enables/disables LVM ephemeral storage encryption. help=""" Cipher-mode string to be used -The cipher and mode to be used to encrypt ephemeral -storage. The set of cipher-mode combinations available -depends on kernel support. +The cipher and mode to be used to encrypt ephemeral storage. The set of +cipher-mode combinations available depends on kernel support. According +to the dm-crypt documentation, the cipher is expected to be in the format: +"--". Possible values: diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py index 49f0ea15b4e8..7d13b7688aa2 100644 --- a/nova/tests/unit/compute/test_compute.py +++ b/nova/tests/unit/compute/test_compute.py @@ -19,13 +19,14 @@ import base64 import datetime +from itertools import chain import operator import sys import time import traceback import uuid -from itertools import chain +from castellan import key_manager import mock from neutronclient.common import exceptions as neutron_exceptions from oslo_log import log as logging @@ -7935,6 +7936,36 @@ class ComputeAPITestCase(BaseTestCase): instance['display_name']) self.assertIsNotNone(instance.get('uuid')) self.assertEqual([], instance.security_groups.objects) + self.assertIsNone(instance.ephemeral_key_uuid) + + def test_populate_instance_for_create_encrypted(self, num_instances=1): + CONF.set_override('enabled', True, + group='ephemeral_storage_encryption', + enforce_type=True) + CONF.set_override('api_class', + 'castellan.tests.unit.key_manager.mock_key_manager.' + 'MockKeyManager', + group='key_manager', + enforce_type=True) + base_options = {'image_ref': self.fake_image['id'], + 'system_metadata': {'fake': 'value'}, + 'display_name': 'foo', + 'uuid': uuids.instance} + instance = objects.Instance() + instance.update(base_options) + inst_type = flavors.get_flavor_by_name("m1.tiny") + self.compute_api.key_manager = key_manager.API() + index = 1 + instance = self.compute_api._populate_instance_for_create( + self.context, + instance, + self.fake_image, + index, + security_groups=objects.SecurityGroupList(), + instance_type=inst_type, + num_instances=num_instances, + shutdown_terminate=False) + self.assertIsNotNone(instance.ephemeral_key_uuid) def test_default_hostname_generator(self): fake_uuids = [str(uuid.uuid4()) for x in range(4)]