Don't re-bind parameters during stack update
While we're in the process of updating a stack, we set the stack's parameters to the new, updated values. However, we don't want to change existing resources' idea of their own values until we have explicitly done an update of them to bring them into line with the new template/parameters. So when parsing a template snippet, store the parameters object to which it will refer. References will resolve to the new parameters only when the template has been re-resolved. Closes-bug: #1291411 Change-Id: Iebbb518c5d15cfba858db001648f3412a7d8b1c0
This commit is contained in:
parent
96f427b592
commit
a674ac35d1
|
@ -75,11 +75,16 @@ class ParamRef(function.Function):
|
|||
{ "Ref" : "<param_name>" }
|
||||
'''
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
super(ParamRef, self).__init__(stack, fn_name, args)
|
||||
|
||||
self.parameters = self.stack.parameters
|
||||
|
||||
def result(self):
|
||||
param_name = function.resolve(self.args)
|
||||
|
||||
try:
|
||||
return self.stack.parameters[param_name]
|
||||
return self.parameters[param_name]
|
||||
except (KeyError, ValueError):
|
||||
raise exception.UserParameterMissing(key=param_name)
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@ class GetParam(function.Function):
|
|||
- ...
|
||||
'''
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
super(GetParam, self).__init__(stack, fn_name, args)
|
||||
|
||||
self.parameters = self.stack.parameters
|
||||
|
||||
def result(self):
|
||||
args = function.resolve(self.args)
|
||||
|
||||
|
@ -57,7 +62,7 @@ class GetParam(function.Function):
|
|||
self.fn_name)
|
||||
|
||||
try:
|
||||
parameter = self.stack.parameters[param_name]
|
||||
parameter = self.parameters[param_name]
|
||||
except KeyError:
|
||||
raise exception.UserParameterMissing(key=param_name)
|
||||
|
||||
|
|
|
@ -642,6 +642,53 @@ class StackTest(test_parser.StackTest):
|
|||
self.assertEqual(newstack.parameters['OS::stack_id'],
|
||||
stack_identifier.stack_id)
|
||||
|
||||
@utils.stack_delete_after
|
||||
def test_update_modify_param_ok_replace(self):
|
||||
tmpl = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'parameters': {
|
||||
'foo': {'type': 'string'}
|
||||
},
|
||||
'resources': {
|
||||
'AResource': {
|
||||
'type': 'ResourceWithPropsType',
|
||||
'properties': {'Foo': {'get_param': 'foo'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.m.StubOutWithMock(generic_rsrc.ResourceWithProps,
|
||||
'update_template_diff')
|
||||
|
||||
self.stack = parser.Stack(self.ctx, 'update_test_stack',
|
||||
template.Template(tmpl),
|
||||
environment.Environment({'foo': 'abc'}))
|
||||
self.stack.store()
|
||||
self.stack.create()
|
||||
self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE),
|
||||
self.stack.state)
|
||||
|
||||
updated_stack = parser.Stack(self.ctx, 'updated_stack',
|
||||
template.Template(tmpl),
|
||||
environment.Environment({'foo': 'xyz'}))
|
||||
|
||||
def check_props(*args):
|
||||
self.assertEqual('abc', self.stack['AResource'].properties['Foo'])
|
||||
|
||||
generic_rsrc.ResourceWithProps.update_template_diff(
|
||||
{'Type': 'ResourceWithPropsType',
|
||||
'Properties': {'Foo': 'xyz'}},
|
||||
{'Type': 'ResourceWithPropsType',
|
||||
'Properties': {'Foo': 'abc'}}).WithSideEffects(check_props) \
|
||||
.AndRaise(resource.UpdateReplace)
|
||||
self.m.ReplayAll()
|
||||
|
||||
self.stack.update(updated_stack)
|
||||
self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE),
|
||||
self.stack.state)
|
||||
self.assertEqual('xyz', self.stack['AResource'].properties['Foo'])
|
||||
self.m.VerifyAll()
|
||||
|
||||
|
||||
class StackAttributesTest(HeatTestCase):
|
||||
"""
|
||||
|
|
|
@ -1638,6 +1638,53 @@ class StackTest(HeatTestCase):
|
|||
self.assertEqual('xyz', self.stack['AResource'].properties['Foo'])
|
||||
self.m.VerifyAll()
|
||||
|
||||
@utils.stack_delete_after
|
||||
def test_update_modify_param_ok_replace(self):
|
||||
tmpl = {
|
||||
'HeatTemplateFormatVersion': '2012-12-12',
|
||||
'Parameters': {
|
||||
'foo': {'Type': 'String'}
|
||||
},
|
||||
'Resources': {
|
||||
'AResource': {
|
||||
'Type': 'ResourceWithPropsType',
|
||||
'Properties': {'Foo': {'Ref': 'foo'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.m.StubOutWithMock(generic_rsrc.ResourceWithProps,
|
||||
'update_template_diff')
|
||||
|
||||
self.stack = parser.Stack(self.ctx, 'update_test_stack',
|
||||
template.Template(tmpl),
|
||||
environment.Environment({'foo': 'abc'}))
|
||||
self.stack.store()
|
||||
self.stack.create()
|
||||
self.assertEqual((parser.Stack.CREATE, parser.Stack.COMPLETE),
|
||||
self.stack.state)
|
||||
|
||||
updated_stack = parser.Stack(self.ctx, 'updated_stack',
|
||||
template.Template(tmpl),
|
||||
environment.Environment({'foo': 'xyz'}))
|
||||
|
||||
def check_props(*args):
|
||||
self.assertEqual('abc', self.stack['AResource'].properties['Foo'])
|
||||
|
||||
generic_rsrc.ResourceWithProps.update_template_diff(
|
||||
{'Type': 'ResourceWithPropsType',
|
||||
'Properties': {'Foo': 'xyz'}},
|
||||
{'Type': 'ResourceWithPropsType',
|
||||
'Properties': {'Foo': 'abc'}}).WithSideEffects(check_props) \
|
||||
.AndRaise(resource.UpdateReplace)
|
||||
self.m.ReplayAll()
|
||||
|
||||
self.stack.update(updated_stack)
|
||||
self.assertEqual((parser.Stack.UPDATE, parser.Stack.COMPLETE),
|
||||
self.stack.state)
|
||||
self.assertEqual('xyz', self.stack['AResource'].properties['Foo'])
|
||||
self.m.VerifyAll()
|
||||
|
||||
@utils.stack_delete_after
|
||||
def test_update_modify_update_failed(self):
|
||||
tmpl = {'Resources': {'AResource': {'Type': 'ResourceWithPropsType',
|
||||
|
|
Loading…
Reference in New Issue