From 19d5610f93850dd27cf3847135289eb243c64bd8 Mon Sep 17 00:00:00 2001 From: lisali Date: Fri, 7 Aug 2015 14:35:27 +0800 Subject: [PATCH] Prevent creating encrypted volume with image When creating an encrypted volume with a unencrypted image, cinder just copies the unencrypted data to the volume, which keeps unencrypted data in the volume. But when booting/attaching the volume to Nova, it thinks encrypted data on the volume. As a result, Nova reads the data incorrectly. The fix is to prevent such action. Later, we can implement to write encrypted data in encrypted volumes when creating from unencrypted image. Change-Id: I0af8318222cee023451c38812bf83cdb4086faae Closes-bug: #1482464 --- .../volume/flows/test_create_volume_flow.py | 93 +++++++++++++++++++ cinder/volume/flows/api/create_volume.py | 7 ++ 2 files changed, 100 insertions(+) diff --git a/cinder/tests/unit/volume/flows/test_create_volume_flow.py b/cinder/tests/unit/volume/flows/test_create_volume_flow.py index 5ec263d0bce..5b7a4be1ab5 100644 --- a/cinder/tests/unit/volume/flows/test_create_volume_flow.py +++ b/cinder/tests/unit/volume/flows/test_create_volume_flow.py @@ -21,6 +21,8 @@ from cinder import exception from cinder import test from cinder.tests.unit import fake_snapshot from cinder.tests.unit import fake_volume +from cinder.tests.unit.image import fake as fake_image +from cinder.tests.unit.keymgr import mock_key_mgr from cinder.tests.unit.volume.flows import fake_volume_api from cinder.volume.flows.api import create_volume from cinder.volume.flows.manager import create_volume as create_volume_manager @@ -77,6 +79,97 @@ class CreateVolumeFlowTestCase(test.TestCase): task._cast_create_volume(self.ctxt, spec, props) + @mock.patch('cinder.volume.volume_types.is_encrypted') + @mock.patch('cinder.volume.flows.api.create_volume.' + 'ExtractVolumeRequestTask.' + '_get_volume_type_id') + def test_extract_volume_request_from_image_encrypted( + self, + fake_get_volume_type_id, + fake_is_encrypted): + + fake_image_service = fake_image.FakeImageService() + image_id = 1 + image_meta = {} + image_meta['id'] = image_id + image_meta['status'] = 'active' + image_meta['size'] = 1 + fake_image_service.create(self.ctxt, image_meta) + fake_key_manager = mock_key_mgr.MockKeyManager() + + task = create_volume.ExtractVolumeRequestTask( + fake_image_service, + {'nova'}) + + fake_is_encrypted.return_value = True + self.assertRaises(exception.InvalidInput, + task.execute, + self.ctxt, + size=1, + snapshot=None, + image_id=image_id, + source_volume=None, + availability_zone='nova', + volume_type=None, + metadata=None, + key_manager=fake_key_manager, + source_replica=None, + consistencygroup=None, + cgsnapshot=None) + + @mock.patch('cinder.volume.volume_types.is_encrypted') + @mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs') + @mock.patch('cinder.volume.flows.api.create_volume.' + 'ExtractVolumeRequestTask.' + '_get_volume_type_id') + def test_extract_volume_request_from_image( + self, + fake_get_type_id, + fake_get_qos, + fake_is_encrypted): + + fake_image_service = fake_image.FakeImageService() + image_id = 2 + image_meta = {} + image_meta['id'] = image_id + image_meta['status'] = 'active' + image_meta['size'] = 1 + fake_image_service.create(self.ctxt, image_meta) + fake_key_manager = mock_key_mgr.MockKeyManager() + volume_type = 'type1' + + task = create_volume.ExtractVolumeRequestTask( + fake_image_service, + {'nova'}) + + fake_is_encrypted.return_value = False + fake_get_type_id.return_value = 1 + fake_get_qos.return_value = {'qos_specs': None} + result = task.execute(self.ctxt, + size=1, + snapshot=None, + image_id=image_id, + source_volume=None, + availability_zone='nova', + volume_type=volume_type, + metadata=None, + key_manager=fake_key_manager, + source_replica=None, + consistencygroup=None, + cgsnapshot=None) + expected_result = {'size': 1, + 'snapshot_id': None, + 'source_volid': None, + 'availability_zone': 'nova', + 'volume_type': volume_type, + 'volume_type_id': 1, + 'encryption_key_id': None, + 'qos_specs': None, + 'source_replicaid': None, + 'consistencygroup_id': None, + 'cgsnapshot_id': None, } + self.assertEqual(expected_result, result) + class CreateVolumeFlowManagerTestCase(test.TestCase): diff --git a/cinder/volume/flows/api/create_volume.py b/cinder/volume/flows/api/create_volume.py index 5f1a4adfcbb..4af58ba9686 100644 --- a/cinder/volume/flows/api/create_volume.py +++ b/cinder/volume/flows/api/create_volume.py @@ -382,6 +382,13 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask): volume_type_id = self._get_volume_type_id(volume_type, source_volume, snapshot) + if image_id and volume_types.is_encrypted(context, volume_type_id): + msg = _('Create encrypted volumes with type %(type)s ' + 'from image %(image)s is not supported.') + msg = msg % {'type': volume_type_id, + 'image': image_id, } + raise exception.InvalidInput(reason=msg) + encryption_key_id = self._get_encryption_key_id(key_manager, context, volume_type_id,