Save updated-in-place resources to backup stack
The patch changes the approach of resource backup during stack update. It stores the definition of resource that needs to be updated in-place to backup stack(if it was not created before). Without this functionality, InvalidTemplateReference will be thrown every time when update-replaced resource has a reference to updated in-place resource and stack update was failed. In this case, backup stack has a resource that refers to not-presented another resource and backup stack deletion generates an exception. Change-Id: I436c44a579bb4df3031d1a17b9ca5b62da37afeb Closes-bug: #1446575
This commit is contained in:
@@ -135,6 +135,15 @@ class StackUpdate(object):
|
|||||||
except resource.UpdateReplace:
|
except resource.UpdateReplace:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
# Save resource definition to backup stack if it is not
|
||||||
|
# present in backup stack template already
|
||||||
|
if res_name not in self.previous_stack.t[
|
||||||
|
self.previous_stack.t.RESOURCES]:
|
||||||
|
definition = existing_res.t.reparse(self.previous_stack,
|
||||||
|
existing_res.stack.t)
|
||||||
|
self.previous_stack.t.add_resource(definition)
|
||||||
|
self.previous_stack.t.store(self.previous_stack.context)
|
||||||
|
|
||||||
LOG.info(_LI("Resource %(res_name)s for stack %(stack_name)s "
|
LOG.info(_LI("Resource %(res_name)s for stack %(stack_name)s "
|
||||||
"updated"),
|
"updated"),
|
||||||
{'res_name': res_name,
|
{'res_name': res_name,
|
||||||
|
|||||||
@@ -1535,3 +1535,71 @@ class StackUpdateTest(common.HeatTestCase):
|
|||||||
self.assertEqual((stack.Stack.UPDATE, stack.Stack.COMPLETE),
|
self.assertEqual((stack.Stack.UPDATE, stack.Stack.COMPLETE),
|
||||||
self.stack.state)
|
self.stack.state)
|
||||||
self.assertEqual('foo', self.stack['AResource'].properties['Foo'])
|
self.assertEqual('foo', self.stack['AResource'].properties['Foo'])
|
||||||
|
|
||||||
|
def test_delete_stack_when_update_failed_twice(self):
|
||||||
|
"""Test when stack update failed twice and delete the stack.
|
||||||
|
|
||||||
|
Test checks the following scenario:
|
||||||
|
1. Create stack
|
||||||
|
2. Update stack (failed)
|
||||||
|
3. Update stack (failed)
|
||||||
|
4. Delete stack
|
||||||
|
The test checks the behavior of backup stack when update is failed.
|
||||||
|
If some resources were not backed up correctly then test will fail.
|
||||||
|
"""
|
||||||
|
tmpl_create = {
|
||||||
|
'heat_template_version': '2013-05-23',
|
||||||
|
'resources': {
|
||||||
|
'Ares': {'type': 'GenericResourceType'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# create a stack
|
||||||
|
self.stack = stack.Stack(self.ctx, 'update_fail_test_stack',
|
||||||
|
template.Template(tmpl_create),
|
||||||
|
disable_rollback=True)
|
||||||
|
self.stack.store()
|
||||||
|
self.stack.create()
|
||||||
|
self.assertEqual((stack.Stack.CREATE, stack.Stack.COMPLETE),
|
||||||
|
self.stack.state)
|
||||||
|
|
||||||
|
tmpl_update = {
|
||||||
|
'heat_template_version': '2013-05-23',
|
||||||
|
'resources': {
|
||||||
|
'Ares': {'type': 'GenericResourceType'},
|
||||||
|
'Bres': {'type': 'GenericResourceType'},
|
||||||
|
'Cres': {
|
||||||
|
'type': 'ResourceWithPropsType',
|
||||||
|
'properties': {
|
||||||
|
'Foo': {'get_resource': 'Bres'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_create = self.patchobject(
|
||||||
|
generic_rsrc.ResourceWithProps,
|
||||||
|
'handle_create',
|
||||||
|
side_effect=[Exception, Exception])
|
||||||
|
|
||||||
|
updated_stack_first = stack.Stack(self.ctx,
|
||||||
|
'update_fail_test_stack',
|
||||||
|
template.Template(tmpl_update))
|
||||||
|
self.stack.update(updated_stack_first)
|
||||||
|
self.stack.resources['Cres'].resource_id_set('c_res')
|
||||||
|
self.assertEqual((stack.Stack.UPDATE, stack.Stack.FAILED),
|
||||||
|
self.stack.state)
|
||||||
|
|
||||||
|
# try to update the stack again
|
||||||
|
updated_stack_second = stack.Stack(self.ctx,
|
||||||
|
'update_fail_test_stack',
|
||||||
|
template.Template(tmpl_update))
|
||||||
|
self.stack.update(updated_stack_second)
|
||||||
|
self.assertEqual((stack.Stack.UPDATE, stack.Stack.FAILED),
|
||||||
|
self.stack.state)
|
||||||
|
|
||||||
|
self.assertEqual(mock_create.call_count, 2)
|
||||||
|
|
||||||
|
# delete the failed stack
|
||||||
|
self.stack.delete()
|
||||||
|
self.assertEqual((stack.Stack.DELETE, stack.Stack.COMPLETE),
|
||||||
|
self.stack.state)
|
||||||
|
|||||||
Reference in New Issue
Block a user