From 370f3c98c5eccf8bce1be425acc31af5e7224171 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Thu, 16 Apr 2015 17:20:05 -0400 Subject: [PATCH] Don't re-bind environment for get_file during stack update While we're in the process of updating a stack, we set the stack's environment to the new, updated values. However, we don't want to change existing resources' idea of their own values until we have explivitly done an update of them to bring them into line with the new template/environment. So when parsing a template snippet containing the get_file intrinsic, store the files dict to which it will refer. get_file will resolve to the new file only when the template has been updated. Closes-Bug: #1445170 Change-Id: I8ec32b0e38389cd314e4b2b2d8c65f61f8a9c41e (cherry picked from commit e4447e7b66cf4691218b067643b5e25de72e31ba) --- heat/engine/hot/functions.py | 7 +++++- heat/tests/test_hot.py | 44 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/heat/engine/hot/functions.py b/heat/engine/hot/functions.py index c50fa3fd7b..e5814230a8 100644 --- a/heat/engine/hot/functions.py +++ b/heat/engine/hot/functions.py @@ -204,13 +204,18 @@ class GetFile(function.Function): key. """ + def __init__(self, stack, fn_name, args): + super(GetFile, self).__init__(stack, fn_name, args) + + self.files = self.stack.t.files + def result(self): args = function.resolve(self.args) if not (isinstance(args, six.string_types)): raise TypeError(_('Argument to "%s" must be a string') % self.fn_name) - f = self.stack.t.files.get(args) + f = self.files.get(args) if f is None: fmt_data = {'fn_name': self.fn_name, 'file_key': args} diff --git a/heat/tests/test_hot.py b/heat/tests/test_hot.py index e80823cc81..653c29a1ba 100644 --- a/heat/tests/test_hot.py +++ b/heat/tests/test_hot.py @@ -1083,6 +1083,50 @@ class HotStackTest(common.HeatTestCase): self.assertEqual('xyz', self.stack['AResource'].properties['Foo']) self.m.VerifyAll() + def test_update_modify_files_ok_replace(self): + tmpl = { + 'heat_template_version': '2013-05-23', + 'parameters': {}, + 'resources': { + 'AResource': { + 'type': 'ResourceWithPropsType', + 'properties': {'Foo': {'get_file': 'foo'}} + } + } + } + + self.m.StubOutWithMock(generic_rsrc.ResourceWithProps, + 'update_template_diff') + + self.stack = parser.Stack(self.ctx, 'update_test_stack', + template.Template(tmpl, + files={'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, + files={'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(common.HeatTestCase): """