Merge "NFS update volume attachment format during volume snapshot"

This commit is contained in:
Zuul 2024-12-18 21:26:09 +00:00 committed by Gerrit Code Review
commit a7b1388932
5 changed files with 31 additions and 5 deletions

View File

@ -1066,17 +1066,19 @@ class NfsDriverTestCase(test.TestCase):
if file_format: if file_format:
volume.admin_metadata = {'format': file_format} volume.admin_metadata = {'format': file_format}
mock_get.return_value = volume mock_get.return_value = volume
path = 'path' local_vol_dir = 'dir'
newSize = volume['size'] + 1 newSize = volume['size'] + 1
with mock.patch.object(image_utils, 'resize_image') as resize: with mock.patch.object(image_utils, 'resize_image') as resize:
with mock.patch.object(drv, 'local_path', return_value=path): with mock.patch.object(drv, '_local_volume_dir',
return_value=local_vol_dir):
with mock.patch.object(drv, '_is_share_eligible', with mock.patch.object(drv, '_is_share_eligible',
return_value=True): return_value=True):
with mock.patch.object(drv, '_is_file_size_equal', with mock.patch.object(drv, '_is_file_size_equal',
return_value=True): return_value=True):
drv.extend_volume(volume, newSize) drv.extend_volume(volume, newSize)
path = os.path.join(local_vol_dir, volume.name)
resize.assert_called_once_with(path, newSize, resize.assert_called_once_with(path, newSize,
run_as_root=True, run_as_root=True,
file_format=file_format) file_format=file_format)

View File

@ -363,11 +363,13 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
self.context, connection_info=conn_info) self.context, connection_info=conn_info)
snapshot.volume.volume_attachment.objects.append(attachment) snapshot.volume.volume_attachment.objects.append(attachment)
mock_save = self.mock_object(attachment, 'save') mock_save = self.mock_object(attachment, 'save')
mock_vol_save = self.mock_object(snapshot.volume, 'save')
# After the snapshot the connection info should change the name of # After the snapshot the connection info should change the name of
# the file # the file
expected = copy.deepcopy(attachment.connection_info) expected = copy.deepcopy(attachment.connection_info)
expected['name'] = snapshot.volume.name + '.' + snapshot.id expected['name'] = snapshot.volume.name + '.' + snapshot.id
expected['format'] = 'qcow2'
else: else:
expected_method_called = '_do_create_snapshot' expected_method_called = '_do_create_snapshot'
@ -386,6 +388,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase):
if volume_in_use: if volume_in_use:
mock_save.assert_called_once() mock_save.assert_called_once()
# We should have updated the volume format after the snapshot
mock_vol_save.assert_called_once()
changed_fields = attachment.cinder_obj_get_changes() changed_fields = attachment.cinder_obj_get_changes()
self.assertEqual(expected, changed_fields['connection_info']) self.assertEqual(expected, changed_fields['connection_info'])

View File

@ -392,18 +392,22 @@ class NfsDriver(remotefs.RemoteFSSnapDriverDistributed):
raise exception.ExtendVolumeError(reason='Insufficient space to' raise exception.ExtendVolumeError(reason='Insufficient space to'
' extend volume %s to %sG' ' extend volume %s to %sG'
% (volume.id, new_size)) % (volume.id, new_size))
path = self.local_path(volume) # Use the active image file because this volume might have snapshot(s).
active_file = self.get_active_image_from_info(volume)
active_file_path = os.path.join(self._local_volume_dir(volume),
active_file)
LOG.info('Resizing file to %sG...', new_size) LOG.info('Resizing file to %sG...', new_size)
file_format = None file_format = None
admin_metadata = objects.Volume.get_by_id( admin_metadata = objects.Volume.get_by_id(
context.get_admin_context(), volume.id).admin_metadata context.get_admin_context(), volume.id).admin_metadata
if admin_metadata and 'format' in admin_metadata: if admin_metadata and 'format' in admin_metadata:
file_format = admin_metadata['format'] file_format = admin_metadata['format']
image_utils.resize_image(path, new_size, image_utils.resize_image(active_file_path, new_size,
run_as_root=self._execute_as_root, run_as_root=self._execute_as_root,
file_format=file_format) file_format=file_format)
if file_format == 'qcow2' and not self._is_file_size_equal( if file_format == 'qcow2' and not self._is_file_size_equal(
path, new_size): active_file_path, new_size):
raise exception.ExtendVolumeError( raise exception.ExtendVolumeError(
reason='Resizing image file failed.') reason='Resizing image file failed.')

View File

@ -1720,9 +1720,18 @@ class RemoteFSSnapDriverBase(RemoteFSDriver):
self._create_snapshot_online(snapshot, self._create_snapshot_online(snapshot,
backing_filename, backing_filename,
new_snap_path) new_snap_path)
# Update the format for the volume and the connection_info. The
# connection_info needs to reflect the current volume format in
# order for Nova to create the disk device correctly whenever the
# instance is stopped/started or rebooted.
new_format = 'qcow2'
snapshot.volume.admin_metadata['format'] = new_format
with snapshot.volume.obj_as_admin():
snapshot.volume.save()
# Update reference in the only attachment (no multi-attach support) # Update reference in the only attachment (no multi-attach support)
attachment = snapshot.volume.volume_attachment[0] attachment = snapshot.volume.volume_attachment[0]
attachment.connection_info['name'] = active attachment.connection_info['name'] = active
attachment.connection_info['format'] = new_format
# Let OVO know it has been updated # Let OVO know it has been updated
attachment.connection_info = attachment.connection_info attachment.connection_info = attachment.connection_info
attachment.save() attachment.save()

View File

@ -0,0 +1,7 @@
fixes:
- |
NFS driver `bug #1989514`_: When creating a snapshot of an attached volume,
the volume attachment format was not updated in its connection_info and
could have resulted in an unbootable guest. This has been fixed.
.. _bug #1989514: https://bugs.launchpad.net/cinder/+bug/1989514