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 5679a0bf99)
(cherry picked from commit 059dc01ae0)
This commit is contained in:
Lee Yarwood 2019-11-15 09:57:27 +00:00
parent a3bba2b320
commit 95bf4a1e15
2 changed files with 38 additions and 0 deletions

View File

@ -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

View File

@ -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)