From 95bf4a1e1594611e987f88b470cc02a626373ab4 Mon Sep 17 00:00:00 2001 From: Lee Yarwood Date: Fri, 15 Nov 2019 09:57:27 +0000 Subject: [PATCH] block_device: Copy original volume_type when missing for snapshot based volumes Attempts to launch an instance from an encrypted volume snapshot would previously fail if a volume_type was not specified in the block_device_mapping of the boot request. To avoid such failures DriverVolSnapshotBlockDevice will now attempt to lookup and use the volume_type of the original volume that the snapshot is based on. This should allow the eventual volume creation request based on the snapshot to succeed in cases where a volume_type is required but not provided in the boot request. Conflicts: nova/virt/block_device.py nova/tests/unit/virt/test_block_device.py NOTE(lyarwood): Due to I4205c00311f389907dcc390869414687ac03b7f5 not being present in stable/stein. As a result the call to the volume_api.create doesn't proivide the snapshot argument as a keyword. Closes-Bug: #1853495 Change-Id: Ic749c49e227e41732dbe04acea303b303acd264a (cherry picked from commit 5679a0bf99c17ff336fa520c9cdfad5156c6c9d2) (cherry picked from commit 059dc01ae027f00ffffbaa9ee8a3c958031829ce) --- nova/tests/unit/virt/test_block_device.py | 31 +++++++++++++++++++++++ nova/virt/block_device.py | 7 +++++ 2 files changed, 38 insertions(+) diff --git a/nova/tests/unit/virt/test_block_device.py b/nova/tests/unit/virt/test_block_device.py index 9eb7d9ce8ead..29660ac915c3 100644 --- a/nova/tests/unit/virt/test_block_device.py +++ b/nova/tests/unit/virt/test_block_device.py @@ -967,6 +967,37 @@ class TestDriverBlockDevice(test.NoDBTestCase): self.virt_driver) self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2') + def test_snapshot_attach_no_volume_and_no_volume_type(self): + bdm = self.driver_classes['volsnapshot'](self.volsnapshot_bdm) + instance = fake_instance.fake_instance_obj(self.context, + **{'uuid': uuids.uuid}) + snapshot = {'volume_id': uuids.original_volume_id} + original_volume = {'id': uuids.original_volume_id, + 'volume_type_id': 'original_volume_type'} + new_volume = {'id': uuids.new_volume_id} + with test.nested( + mock.patch.object(self.driver_classes['volume'], 'attach'), + mock.patch.object(self.volume_api, 'get_snapshot', + return_value=snapshot), + mock.patch.object(self.volume_api, 'get', + return_value=original_volume), + mock.patch.object(self.volume_api, 'create', + return_value=new_volume), + ) as (mock_attach, mock_get_snapshot, mock_get, mock_create): + bdm.volume_id = None + bdm.volume_type = None + bdm.attach(self.context, instance, self.volume_api, + self.virt_driver) + + # Assert that the original volume type is fetched, stored within + # the bdm and then used to create the new snapshot based volume. + mock_get.assert_called_once_with(self.context, + uuids.original_volume_id) + self.assertEqual('original_volume_type', bdm.volume_type) + mock_create.assert_called_once_with(self.context, bdm.volume_size, + '', '', snapshot, volume_type='original_volume_type', + availability_zone=None) + def test_image_attach_no_volume(self): no_volume_image = self.volimage_bdm_dict.copy() no_volume_image['volume_id'] = None diff --git a/nova/virt/block_device.py b/nova/virt/block_device.py index 236025596755..effbddc116e6 100644 --- a/nova/virt/block_device.py +++ b/nova/virt/block_device.py @@ -721,6 +721,13 @@ class DriverVolSnapshotBlockDevice(DriverVolumeBlockDevice): av_zone = _get_volume_create_az_value(instance) snapshot = volume_api.get_snapshot(context, self.snapshot_id) + # NOTE(lyarwood): Try to use the original volume type if one isn't + # set against the bdm but is on the original volume. + if not self.volume_type and snapshot.get('volume_id'): + snap_volume_id = snapshot.get('volume_id') + orig_volume = volume_api.get(context, snap_volume_id) + self.volume_type = orig_volume.get('volume_type_id') + vol = volume_api.create(context, self.volume_size, '', '', snapshot, volume_type=self.volume_type, availability_zone=av_zone)