Skip to content

Commit

Permalink
heat engine : store stack on failed update
Browse files Browse the repository at this point in the history
Store the stack even when the update fails, otherwise we
lose track of the resources which failed on create so they
are not removed on stack delete

fixes bug 1151989

Change-Id: Ic8aa5ef92e188fb704ed25563aa9b86aa69232b4
  • Loading branch information
Steven Hardy committed Mar 8, 2013
1 parent da6d678 commit b8aad78
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 7 deletions.
17 changes: 10 additions & 7 deletions heat/engine/parser.py
Expand Up @@ -426,13 +426,6 @@ def update(self, newstack, action=UPDATE):
raise exception.ResourceUpdateFailed(
resource_name=res.name)

# flip the template & parameters to the newstack values
self.t = newstack.t
self.parameters = newstack.parameters
template_outputs = self.t[template.OUTPUTS]
self.outputs = self.resolve_static_data(template_outputs)
self.store()

if action == self.UPDATE:
stack_status = self.UPDATE_COMPLETE
reason = 'Stack successfully updated'
Expand Down Expand Up @@ -469,6 +462,16 @@ def update(self, newstack, action=UPDATE):

self.state_set(stack_status, reason)

# flip the template & parameters to the newstack values
# Note we do this on success and failure, so the current
# stack resources are stored, even if one is in a failed
# state (otherwise we won't remove them on delete)
self.t = newstack.t
self.parameters = newstack.parameters
template_outputs = self.t[template.OUTPUTS]
self.outputs = self.resolve_static_data(template_outputs)
self.store()

def delete(self, action=DELETE):
'''
Delete all of the resources, and then the stack itself.
Expand Down
31 changes: 31 additions & 0 deletions heat/tests/test_parser.py
Expand Up @@ -674,6 +674,37 @@ def test_update_modify_replace_failed_create(self):
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.m.VerifyAll()

@stack_delete_after
def test_update_add_failed_create(self):
tmpl = {'Resources': {'AResource': {'Type': 'GenericResourceType'}}}

self.stack = parser.Stack(self.ctx, 'update_test_stack',
template.Template(tmpl))
self.stack.store()
self.stack.create()
self.assertEqual(self.stack.state, parser.Stack.CREATE_COMPLETE)

tmpl2 = {'Resources': {
'AResource': {'Type': 'GenericResourceType'},
'BResource': {'Type': 'GenericResourceType'}}}
updated_stack = parser.Stack(self.ctx, 'updated_stack',
template.Template(tmpl2))

# patch in a dummy handle_create making BResource fail creating
self.m.StubOutWithMock(generic_rsrc.GenericResource, 'handle_create')
generic_rsrc.GenericResource.handle_create().AndRaise(Exception)
self.m.ReplayAll()

self.stack.update(updated_stack)
self.assertEqual(self.stack.state, parser.Stack.UPDATE_FAILED)
self.assertTrue('BResource' in self.stack)

# Reload the stack from the DB and prove that it contains the failed
# resource (to ensure it will be deleted on stack delete)
re_stack = parser.Stack.load(self.ctx, stack_id=self.stack.id)
self.assertTrue('BResource' in re_stack)
self.m.VerifyAll()

@stack_delete_after
def test_update_rollback(self):
# patch in a dummy property schema for GenericResource
Expand Down

0 comments on commit b8aad78

Please sign in to comment.