Merge "unquiesce instance on volume snapshot failure" into stable/ocata

This commit is contained in:
Zuul 2018-04-20 00:33:13 +00:00 committed by Gerrit Code Review
commit 62759e7380
2 changed files with 60 additions and 25 deletions

View File

@ -2894,6 +2894,8 @@ class API(base.Base):
quiesced = False
if instance.vm_state == vm_states.ACTIVE:
try:
LOG.info(_LI("Attempting to quiesce instance before volume "
"snapshot."), instance=instance)
self.compute_rpcapi.quiesce_instance(context, instance)
quiesced = True
except (exception.InstanceQuiesceNotSupported,
@ -2911,28 +2913,43 @@ class API(base.Base):
context, instance.uuid)
mapping = []
for bdm in bdms:
if bdm.no_device:
continue
try:
for bdm in bdms:
if bdm.no_device:
continue
if bdm.is_volume:
# create snapshot based on volume_id
volume = self.volume_api.get(context, bdm.volume_id)
# NOTE(yamahata): Should we wait for snapshot creation?
# Linux LVM snapshot creation completes in
# short time, it doesn't matter for now.
name = _('snapshot for %s') % image_meta['name']
LOG.debug('Creating snapshot from volume %s.', volume['id'],
instance=instance)
snapshot = self.volume_api.create_snapshot_force(
context, volume['id'], name, volume['display_description'])
mapping_dict = block_device.snapshot_from_bdm(snapshot['id'],
bdm)
mapping_dict = mapping_dict.get_image_mapping()
else:
mapping_dict = bdm.get_image_mapping()
if bdm.is_volume:
# create snapshot based on volume_id
volume = self.volume_api.get(context, bdm.volume_id)
# NOTE(yamahata): Should we wait for snapshot creation?
# Linux LVM snapshot creation completes in short time,
# it doesn't matter for now.
name = _('snapshot for %s') % image_meta['name']
LOG.debug('Creating snapshot from volume %s.',
volume['id'], instance=instance)
snapshot = self.volume_api.create_snapshot_force(
context, volume['id'],
name, volume['display_description'])
mapping_dict = block_device.snapshot_from_bdm(
snapshot['id'], bdm)
mapping_dict = mapping_dict.get_image_mapping()
else:
mapping_dict = bdm.get_image_mapping()
mapping.append(mapping_dict)
mapping.append(mapping_dict)
# NOTE(tasker): No error handling is done in the above for loop.
# This means that if the snapshot fails and throws an exception
# the traceback will skip right over the unquiesce needed below.
# Here, catch any exception, unquiesce the instance, and raise the
# error so that the calling function can do what it needs to in
# order to properly treat a failed snap.
except Exception:
with excutils.save_and_reraise_exception():
if quiesced:
LOG.info(_LI("Unquiescing instance after volume snapshot "
"failure."), instance=instance)
self.compute_rpcapi.unquiesce_instance(
context, instance, mapping)
if quiesced:
self.compute_rpcapi.unquiesce_instance(context, instance, mapping)

View File

@ -2755,7 +2755,8 @@ class _ComputeAPIUnitTestMixIn(object):
instance)
def _test_snapshot_volume_backed(self, quiesce_required, quiesce_fails,
vm_state=vm_states.ACTIVE):
vm_state=vm_states.ACTIVE,
snapshot_fails=False):
fake_sys_meta = {'image_min_ram': '11',
'image_min_disk': '22',
'image_container_format': 'ami',
@ -2801,6 +2802,8 @@ class _ComputeAPIUnitTestMixIn(object):
return {'id': volume_id, 'display_description': ''}
def fake_volume_create_snapshot(context, volume_id, name, description):
if snapshot_fails:
raise exception.OverQuota(overs="snapshots")
return {'id': '%s-snapshot' % volume_id}
def fake_quiesce_instance(context, instance):
@ -2850,8 +2853,13 @@ class _ComputeAPIUnitTestMixIn(object):
'tag': None})
# All the db_only fields and the volume ones are removed
self.compute_api.snapshot_volume_backed(
self.context, instance, 'test-snapshot')
if snapshot_fails:
self.assertRaises(exception.OverQuota,
self.compute_api.snapshot_volume_backed,
self.context, instance, "test-snapshot")
else:
self.compute_api.snapshot_volume_backed(
self.context, instance, 'test-snapshot')
self.assertEqual(quiesce_expected, quiesced[0])
self.assertEqual(quiesce_expected, quiesced[1])
@ -2889,8 +2897,13 @@ class _ComputeAPIUnitTestMixIn(object):
quiesced = [False, False]
# Check that the mappings from the image properties are not included
self.compute_api.snapshot_volume_backed(
self.context, instance, 'test-snapshot')
if snapshot_fails:
self.assertRaises(exception.OverQuota,
self.compute_api.snapshot_volume_backed,
self.context, instance, "test-snapshot")
else:
self.compute_api.snapshot_volume_backed(
self.context, instance, 'test-snapshot')
self.assertEqual(quiesce_expected, quiesced[0])
self.assertEqual(quiesce_expected, quiesced[1])
@ -2901,6 +2914,11 @@ class _ComputeAPIUnitTestMixIn(object):
def test_snapshot_volume_backed_with_quiesce(self):
self._test_snapshot_volume_backed(True, False)
def test_snapshot_volume_backed_with_quiesce_create_snap_fails(self):
self._test_snapshot_volume_backed(quiesce_required=True,
quiesce_fails=False,
snapshot_fails=True)
def test_snapshot_volume_backed_with_quiesce_skipped(self):
self._test_snapshot_volume_backed(False, True)