Fix: Roll back volume status during reimage failure
When we try to reimage a volume, we update the status of volume to 'downloading'. We later validate the image metadata (like image is 'active', image size is less than volume size, etc), and in case the validation fails, we currently don't revert the volume status back to original ('available', 'in-use' etc) and volume stays in 'downloading' state. This patch fixes this by catching the failure exception and doing a DB update to restore the volume status back to it's previous state. Closes-Bug: #2036994 Change-Id: I05bf29e2a089b06398414b542b655a8083c9a21f
This commit is contained in:
parent
bd786113ce
commit
a752012c92
@ -108,6 +108,22 @@ class VolumeReimageTestCase(base.BaseVolumeTestCase):
|
|||||||
mock_reimage.assert_called_once_with(self.context, volume,
|
mock_reimage.assert_called_once_with(self.context, volume,
|
||||||
self.image_meta)
|
self.image_meta)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.check_image_metadata')
|
||||||
|
@mock.patch('cinder.volume.rpcapi.VolumeAPI.reimage')
|
||||||
|
@ddt.data('available', 'error')
|
||||||
|
def test_volume_reimage_check_meta_exception(self, status, mock_reimage,
|
||||||
|
mock_check):
|
||||||
|
volume = tests_utils.create_volume(self.context)
|
||||||
|
volume.status = status
|
||||||
|
volume.save()
|
||||||
|
self.assertEqual(volume.status, status)
|
||||||
|
mock_check.side_effect = exception.ImageUnacceptable(
|
||||||
|
image_id=self.image_meta['id'], reason='')
|
||||||
|
# The available or error volume can be reimaged directly
|
||||||
|
self.assertRaises(exception.ImageUnacceptable, self.volume_api.reimage,
|
||||||
|
self.context, volume, self.image_meta['id'])
|
||||||
|
self.assertEqual(status, volume.status)
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_utils.check_image_metadata')
|
@mock.patch('cinder.volume.volume_utils.check_image_metadata')
|
||||||
@mock.patch('cinder.volume.rpcapi.VolumeAPI.reimage')
|
@mock.patch('cinder.volume.rpcapi.VolumeAPI.reimage')
|
||||||
def test_volume_reimage_api_with_reimage_reserved(self, mock_reimage,
|
def test_volume_reimage_api_with_reimage_reserved(self, mock_reimage,
|
||||||
|
@ -2675,7 +2675,22 @@ class API(base.Base):
|
|||||||
'status': volume.status})
|
'status': volume.status})
|
||||||
raise exception.InvalidVolume(reason=msg)
|
raise exception.InvalidVolume(reason=msg)
|
||||||
image_meta = self.image_service.show(context, image_id)
|
image_meta = self.image_service.show(context, image_id)
|
||||||
volume_utils.check_image_metadata(image_meta, volume['size'])
|
try:
|
||||||
|
volume_utils.check_image_metadata(image_meta, volume['size'])
|
||||||
|
# Currently we only raise InvalidInput and ImageUnacceptable
|
||||||
|
# exceptions in the check_image_metadata call but having Exception
|
||||||
|
# here makes it more generic since we want to roll back to original
|
||||||
|
# state in any case and we re-raise anyway.
|
||||||
|
# Also this helps makes adding new exceptions easier in the future.
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
LOG.exception("Failed to reimage volume %(volume_id)s with "
|
||||||
|
"image %(image_id)s",
|
||||||
|
{'volume_id': volume.id, 'image_id': image_id})
|
||||||
|
volume.conditional_update(
|
||||||
|
{'status': volume.model.previous_status,
|
||||||
|
'previous_status': None},
|
||||||
|
{'status': 'downloading'})
|
||||||
self.volume_rpcapi.reimage(context,
|
self.volume_rpcapi.reimage(context,
|
||||||
volume,
|
volume,
|
||||||
image_meta)
|
image_meta)
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
`Bug #2036994 <https://bugs.launchpad.net/cinder/+bug/2036994>`_: Fixed
|
||||||
|
rollback of volume status if the reimage operation fails while
|
||||||
|
checking image metadata.
|
Loading…
Reference in New Issue
Block a user