Retry resource creation on conflict

If resource creation fails with an HTTP Conflict error, this is presumably
due to a race condition with one of the underlying services. In this case,
allow Heat to retry the resource creation so that hopefully in most cases
the user will never have to deal with the error.

Change-Id: I301bb28231fcdc249f86ec1a2f09cb993023785b
Story: #1745010
Task: 17344
This commit is contained in:
Zane Bitter 2018-01-24 17:44:51 -05:00
parent 714d9eea4c
commit c4318eff65
2 changed files with 25 additions and 5 deletions

View File

@ -1259,19 +1259,21 @@ class Resource(status.ResourceStatus):
else:
action = self.CREATE
except exception.ResourceFailure as failure:
if isinstance(failure.exc, exception.StackValidationFailed):
exc = failure.exc
if isinstance(exc, exception.StackValidationFailed):
path = [self.t.name]
path.extend(failure.exc.path)
path.extend(exc.path)
raise exception.ResourceFailure(
exception_or_error=exception.StackValidationFailed(
error=failure.exc.error,
error=exc.error,
path=path,
message=failure.exc.error_message
message=exc.error_message
),
resource=failure.resource,
action=failure.action
)
if not isinstance(failure.exc, exception.ResourceInError):
if not (isinstance(exc, exception.ResourceInError) or
self._default_client_plugin().is_conflict(exc)):
raise failure
count[action] += 1

View File

@ -540,6 +540,24 @@ class NeutronRouterTest(common.HeatTestCase):
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
scheduler.TaskRunner(rsrc.delete)()
def test_router_interface_conflict(self):
self.add_if_mock.side_effect = [qe.Conflict, None]
t = template_format.parse(neutron_template)
stack = utils.parse_stack(t)
props = {
'router': '3e46229d-8fce-4733-819a-b5fe630550f8',
'subnet': '91e47a57-7508-46fe-afc9-fc454e8580e1'
}
def find_rsrc(resource, name_or_id, cmd_resource=None):
return props.get(resource, resource)
self.find_rsrc_mock.side_effect = find_rsrc
self.create_router_interface(
t, stack, 'router_interface', properties=props)
self.assertEqual(2, self.add_if_mock.call_count)
def test_router_interface_validate(self):
def find_rsrc(resource, name_or_id, cmd_resource=None):
id_mapping = {