From 56abc9d5b9a07ca31791e385d93ca5b56b6bd74e Mon Sep 17 00:00:00 2001 From: melanie witt Date: Thu, 15 Sep 2022 00:00:31 +0000 Subject: [PATCH] NFS update volume attachment format during volume snapshot During a NFS volume snapshot of an attached volume, a QCOW2 snapshot is created and is made the active volume for the instance. The associated volume attachment is however not updated, resulting in an unbootable instance after a stop/start. This adds an update to the volume format and attachment connection_info format during the snapshot. Closes-Bug: #1989514 Change-Id: I3c638dab2f0b5a2128eaeeea533450d7cdfa1577 --- cinder/tests/unit/volume/drivers/test_nfs.py | 6 ++++-- cinder/tests/unit/volume/drivers/test_remotefs.py | 4 ++++ cinder/volume/drivers/nfs.py | 10 +++++++--- cinder/volume/drivers/remotefs.py | 9 +++++++++ .../attach-format-after-snapshot-9a1857456706aa72.yaml | 7 +++++++ 5 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 releasenotes/notes/attach-format-after-snapshot-9a1857456706aa72.yaml diff --git a/cinder/tests/unit/volume/drivers/test_nfs.py b/cinder/tests/unit/volume/drivers/test_nfs.py index ab9b46317ab..5208e38c95f 100644 --- a/cinder/tests/unit/volume/drivers/test_nfs.py +++ b/cinder/tests/unit/volume/drivers/test_nfs.py @@ -1066,17 +1066,19 @@ class NfsDriverTestCase(test.TestCase): if file_format: volume.admin_metadata = {'format': file_format} mock_get.return_value = volume - path = 'path' + local_vol_dir = 'dir' newSize = volume['size'] + 1 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', return_value=True): with mock.patch.object(drv, '_is_file_size_equal', return_value=True): drv.extend_volume(volume, newSize) + path = os.path.join(local_vol_dir, volume.name) resize.assert_called_once_with(path, newSize, run_as_root=True, file_format=file_format) diff --git a/cinder/tests/unit/volume/drivers/test_remotefs.py b/cinder/tests/unit/volume/drivers/test_remotefs.py index a8c69398ccb..1902920d57c 100644 --- a/cinder/tests/unit/volume/drivers/test_remotefs.py +++ b/cinder/tests/unit/volume/drivers/test_remotefs.py @@ -363,11 +363,13 @@ class RemoteFsSnapDriverTestCase(test.TestCase): self.context, connection_info=conn_info) snapshot.volume.volume_attachment.objects.append(attachment) 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 # the file expected = copy.deepcopy(attachment.connection_info) expected['name'] = snapshot.volume.name + '.' + snapshot.id + expected['format'] = 'qcow2' else: expected_method_called = '_do_create_snapshot' @@ -386,6 +388,8 @@ class RemoteFsSnapDriverTestCase(test.TestCase): if volume_in_use: 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() self.assertEqual(expected, changed_fields['connection_info']) diff --git a/cinder/volume/drivers/nfs.py b/cinder/volume/drivers/nfs.py index 95c33e0b756..a4151c3408c 100644 --- a/cinder/volume/drivers/nfs.py +++ b/cinder/volume/drivers/nfs.py @@ -392,18 +392,22 @@ class NfsDriver(remotefs.RemoteFSSnapDriverDistributed): raise exception.ExtendVolumeError(reason='Insufficient space to' ' extend volume %s to %sG' % (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) file_format = None admin_metadata = objects.Volume.get_by_id( context.get_admin_context(), volume.id).admin_metadata + if admin_metadata and 'format' in admin_metadata: 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, file_format=file_format) if file_format == 'qcow2' and not self._is_file_size_equal( - path, new_size): + active_file_path, new_size): raise exception.ExtendVolumeError( reason='Resizing image file failed.') diff --git a/cinder/volume/drivers/remotefs.py b/cinder/volume/drivers/remotefs.py index 40d14b8faac..64bbeb2259a 100644 --- a/cinder/volume/drivers/remotefs.py +++ b/cinder/volume/drivers/remotefs.py @@ -1720,9 +1720,18 @@ class RemoteFSSnapDriverBase(RemoteFSDriver): self._create_snapshot_online(snapshot, backing_filename, 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) attachment = snapshot.volume.volume_attachment[0] attachment.connection_info['name'] = active + attachment.connection_info['format'] = new_format # Let OVO know it has been updated attachment.connection_info = attachment.connection_info attachment.save() diff --git a/releasenotes/notes/attach-format-after-snapshot-9a1857456706aa72.yaml b/releasenotes/notes/attach-format-after-snapshot-9a1857456706aa72.yaml new file mode 100644 index 00000000000..4b0e6d80930 --- /dev/null +++ b/releasenotes/notes/attach-format-after-snapshot-9a1857456706aa72.yaml @@ -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