Skip to content

Commit cb7c2b2

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Cleanup when hitting MaxRetriesExceeded from no host_available"
2 parents 9cd0fcd + b98d4ba commit cb7c2b2

File tree

3 files changed

+33
-37
lines changed

3 files changed

+33
-37
lines changed

nova/conductor/manager.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,11 @@ def build_instances(self, context, instances, image, filter_properties,
721721
msg = ("Exhausted all hosts available for retrying build "
722722
"failures for instance %(instance_uuid)s." %
723723
{"instance_uuid": instance.uuid})
724-
raise exception.MaxRetriesExceeded(reason=msg)
724+
exc = exception.MaxRetriesExceeded(reason=msg)
725+
self._cleanup_when_reschedule_fails(
726+
context, instance, exc, legacy_request_spec,
727+
requested_networks)
728+
return
725729
instance.availability_zone = (
726730
availability_zones.get_host_availability_zone(context,
727731
host.service_host))

nova/tests/functional/regressions/test_bug_1837955.py

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -84,31 +84,15 @@ def fake_instance_claim(_self, _context, _inst, nodename, *a, **kw):
8484
image_uuid=fake_image.get_valid_image_id(),
8585
networks=[{'port': self.neutron.port_1['id']}])
8686
server = self.api.post_server({'server': server})
87-
# FIXME(mriedem): This is bug 1837955 where the status is stuck in
88-
# BUILD rather than the vm_state being set to error and the task_state
89-
# being set to None. Uncomment this when the bug is fixed.
90-
# server = self._wait_for_state_change(self.api, server, 'ERROR')
87+
server = self._wait_for_state_change(self.api, server, 'ERROR')
9188

9289
# Wait for the MaxRetriesExceeded fault to be recorded.
9390
# set_vm_state_and_notify sets the vm_state to ERROR before the fault
9491
# is recorded but after the notification is sent. So wait for the
9592
# unversioned notification to show up and then get the fault.
96-
# FIXME(mriedem): Uncomment this when bug 1837955 is fixed.
97-
# self._wait_for_unversioned_notification(
98-
# 'compute_task.build_instances')
99-
# server = self.api.get_server(server['id'])
100-
# self.assertIn('fault', server)
101-
# self.assertIn('Exceeded maximum number of retries',
102-
# server['fault']['message'])
103-
104-
# TODO(mriedem): Remove this when the bug is fixed. We need to assert
105-
# something before the bug is fixed to show the failure so check the
106-
# logs.
107-
for x in range(20):
108-
logs = self.stdlog.logger.output
109-
if 'MaxRetriesExceeded' in logs:
110-
break
111-
time.sleep(.5)
112-
else:
113-
self.fail('Timed out waiting for MaxRetriesExceeded to show up '
114-
'in the logs.')
93+
self._wait_for_unversioned_notification(
94+
'compute_task.build_instances')
95+
server = self.api.get_server(server['id'])
96+
self.assertIn('fault', server)
97+
self.assertIn('Exceeded maximum number of retries',
98+
server['fault']['message'])

nova/tests/unit/conductor/test_conductor.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -694,28 +694,36 @@ def test_build_instances_no_instance_mapping(self, _mock_set_state,
694694
mock.call(self.context, instances[1].uuid)])
695695
self.assertFalse(mock_get_by_host.called)
696696

697-
@mock.patch("nova.scheduler.utils.claim_resources", return_value=False)
697+
@mock.patch('nova.compute.utils.notify_about_compute_task_error')
698698
@mock.patch.object(objects.Instance, 'save')
699-
def test_build_instances_exhaust_host_list(self, _mock_save, mock_claim):
699+
def test_build_instances_exhaust_host_list(self, _mock_save, mock_notify):
700700
# A list of three alternate hosts for one instance
701701
host_lists = copy.deepcopy(fake_host_lists_alt)
702702
instance = fake_instance.fake_instance_obj(self.context)
703703
image = {'fake-data': 'should_pass_silently'}
704-
expected_claim_count = len(host_lists[0])
705704

706705
# build_instances() is a cast, we need to wait for it to complete
707706
self.useFixture(cast_as_call.CastAsCall(self))
707+
708+
self.conductor.build_instances(
709+
context=self.context,
710+
instances=[instance], image=image,
711+
filter_properties={},
712+
admin_password='admin_password',
713+
injected_files='injected_files',
714+
requested_networks=None,
715+
security_groups='security_groups',
716+
block_device_mapping=None,
717+
legacy_bdm=None,
718+
host_lists=host_lists
719+
)
720+
708721
# Since claim_resources() is mocked to always return False, we will run
709-
# out of alternate hosts, and MaxRetriesExceeded should be raised.
710-
self.assertRaises(exc.MaxRetriesExceeded,
711-
self.conductor.build_instances, context=self.context,
712-
instances=[instance], image=image, filter_properties={},
713-
admin_password='admin_password',
714-
injected_files='injected_files', requested_networks=None,
715-
security_groups='security_groups',
716-
block_device_mapping=None, legacy_bdm=None,
717-
host_lists=host_lists)
718-
self.assertEqual(expected_claim_count, mock_claim.call_count)
722+
# out of alternate hosts, and complain about MaxRetriesExceeded.
723+
mock_notify.assert_called_once_with(
724+
self.context, 'build_instances',
725+
instance.uuid, test.MatchType(dict), 'error',
726+
test.MatchType(exc.MaxRetriesExceeded), test.MatchType(str))
719727

720728
@mock.patch.object(conductor_manager.ComputeTaskManager,
721729
'_destroy_build_request')

0 commit comments

Comments
 (0)