Cleanup allocating networks when InstanceNotFound is raised

Allocated networks were not being cleaned up if InstanceNotFound was
raised after the allocation request was made.  This ensures that the
cleanup happens for this case.

Also bypasses exception logging that should not occur in this case.

Conflicts:
	nova/tests/compute/test_compute_mgr.py

NOTE(mriedem): The conflict is due to commit b1994711 which is on
master but not stable/icehouse. It's part of a blueprint so that
will not be backported.

Change-Id: Icd544752444415812714d91971e45b3ae2fb68ee
Closes-Bug: 1324934
(cherry picked from commit 5a364cb00a)
This commit is contained in:
Andrew Laski 2014-05-30 17:52:53 -04:00 committed by Matt Riedemann
parent 4c6b0f71c2
commit d1c573652d
2 changed files with 53 additions and 15 deletions

View File

@ -1860,19 +1860,17 @@ class ComputeManager(manager.Manager):
image, filter_properties, admin_password,
injected_files, requested_networks, security_groups,
block_device_mapping)
except exception.InstanceNotFound:
except (exception.InstanceNotFound,
exception.UnexpectedDeletingTaskStateError):
msg = _('Instance disappeared during build.')
LOG.debug(msg, instance=instance)
self._cleanup_allocated_networks(context, instance,
requested_networks)
except exception.BuildAbortException as e:
LOG.exception(e.format_message(), instance=instance)
self._cleanup_allocated_networks(context, instance,
requested_networks)
self._set_instance_error_state(context, instance.uuid)
except exception.UnexpectedDeletingTaskStateError as e:
# The instance is deleting, so clean up but don't error.
LOG.debug(e.format_message(), instance=instance)
self._cleanup_allocated_networks(context, instance,
requested_networks)
except Exception:
# Should not reach here.
msg = _('Unexpected build failure, not rescheduling build.')
@ -2006,9 +2004,12 @@ class ComputeManager(manager.Manager):
try:
yield resources
except Exception:
except Exception as exc:
with excutils.save_and_reraise_exception() as ctxt:
LOG.exception(_('Instance failed to spawn'), instance=instance)
if not isinstance(exc, (exception.InstanceNotFound,
exception.UnexpectedDeletingTaskStateError)):
LOG.exception(_('Instance failed to spawn'),
instance=instance)
# Make sure the async call finishes
if network_info is not None:
network_info.wait(do_raise=False)
@ -2026,11 +2027,19 @@ class ComputeManager(manager.Manager):
requested_networks):
try:
self._deallocate_network(context, instance, requested_networks)
instance.system_metadata['network_allocated'] = 'False'
instance.save()
except Exception:
msg = _('Failed to deallocate networks')
LOG.exception(msg, instance=instance)
return
instance.system_metadata['network_allocated'] = 'False'
try:
instance.save()
except exception.InstanceNotFound:
# NOTE(alaski): It's possible that we're cleaning up the networks
# because the instance was deleted. If that's the case then this
# exception will be raised by instance.save()
pass
def _cleanup_build_resources(self, context, instance,
block_device_mapping):

View File

@ -1365,10 +1365,9 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
block_device_mapping=self.block_device_mapping, node=self.node,
limits=self.limits)
def test_unexpected_exception(self):
def _test_build_and_run_exceptions(self, exc, set_error=False):
self.mox.StubOutWithMock(self.compute, '_build_and_run_instance')
self.mox.StubOutWithMock(self.compute, '_cleanup_allocated_networks')
self.mox.StubOutWithMock(self.compute, '_set_instance_error_state')
self.mox.StubOutWithMock(self.compute.compute_task_api,
'build_instances')
self.mox.StubOutWithMock(self.compute.conductor_api,
@ -1380,11 +1379,13 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
self.image, self.injected_files, self.admin_pass,
self.requested_networks, self.security_groups,
self.block_device_mapping, self.node, self.limits).AndRaise(
test.TestingException())
exc)
self.compute._cleanup_allocated_networks(self.context, self.instance,
self.requested_networks)
self.compute._set_instance_error_state(self.context,
self.instance['uuid'])
if set_error:
self.mox.StubOutWithMock(self.compute, '_set_instance_error_state')
self.compute._set_instance_error_state(self.context,
self.instance['uuid'])
self.compute.conductor_api.action_event_start(self.context,
mox.IgnoreArg())
self.compute.conductor_api.action_event_finish(self.context,
@ -1399,6 +1400,21 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
security_groups=self.security_groups,
block_device_mapping=self.block_device_mapping, node=self.node,
limits=self.limits)
self.mox.UnsetStubs()
def test_build_and_run_instance_exceptions(self):
exceptions = [
exception.InstanceNotFound(instance_id=''),
exception.UnexpectedDeletingTaskStateError(expected='',
actual='')]
error_exceptions = [
exception.BuildAbortException(instance_uuid='', reason=''),
test.TestingException()]
for exc in exceptions:
self._test_build_and_run_exceptions(exc)
for exc in error_exceptions:
self._test_build_and_run_exceptions(exc, set_error=True)
def test_instance_not_found(self):
exc = exception.InstanceNotFound(instance_id=1)
@ -1771,6 +1787,19 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
self.compute._build_networks_for_instance(self.context, instance,
self.requested_networks, self.security_groups)
def test_cleanup_allocated_networks_instance_not_found(self):
with contextlib.nested(
mock.patch.object(self.compute, '_deallocate_network'),
mock.patch.object(self.instance, 'save',
side_effect=exception.InstanceNotFound(instance_id=''))
) as (_deallocate_network, save):
# Testing that this doesn't raise an exeption
self.compute._cleanup_allocated_networks(self.context,
self.instance, self.requested_networks)
save.assert_called_once_with()
self.assertEqual('False',
self.instance.system_metadata['network_allocated'])
class ComputeManagerMigrationTestCase(test.NoDBTestCase):
def setUp(self):