summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Salkeld <asalkeld@redhat.com>2013-10-09 17:12:45 +1100
committerSteven Hardy <shardy@redhat.com>2013-10-10 17:24:44 +0100
commitf5b1d2ff20a194e64ea55afc5a2faeea0f1b62d0 (patch)
tree053d5efd7326529178c60e17d6882f23bf4313b8
parent243b872d2c935c6fb7fbb22fb4951f36de8bab6d (diff)
downloadheat-f5b1d2ff20a194e64ea55afc5a2faeea0f1b62d0.tar.gz
Make templateResource not replace on update
Updating a template resource is never destructive as it defers to the nested stack to determine if any sub-resources needs to be replaced. Closes-bug: #1236676 Change-Id: Iae7e6b7e2f41d2f5bd9e75256be7533c15762d9f
-rw-r--r--heat/engine/resources/template_resource.py17
-rw-r--r--heat/tests/test_provider_template.py71
2 files changed, 88 insertions, 0 deletions
diff --git a/heat/engine/resources/template_resource.py b/heat/engine/resources/template_resource.py
index 0c1f26c75..a1fa1cad6 100644
--- a/heat/engine/resources/template_resource.py
+++ b/heat/engine/resources/template_resource.py
@@ -63,6 +63,12 @@ class TemplateResource(stack_resource.StackResource):
self.attributes_schema = (attributes.Attributes
.schema_from_outputs(tmpl[template.OUTPUTS]))
+ self.update_allowed_keys = ('Properties',)
+ # assume all properties are updatable, as they just get passed to
+ # the nested stack and that handles the updating/replacing.
+ self.update_allowed_properties = [pname
+ for pname in self.properties_schema]
+
super(TemplateResource, self).__init__(name, json_snippet, stack)
def _to_parameters(self):
@@ -174,6 +180,17 @@ class TemplateResource(stack_resource.StackResource):
return self.create_with_template(self.parsed_nested,
self._to_parameters())
+ def handle_update(self, json_snippet, tmpl_diff, prop_diff):
+ # The stack template may be changed even if the prop_diff is empty.
+ self.properties = properties.Properties(
+ self.properties_schema,
+ json_snippet.get('Properties', {}),
+ self.stack.resolve_runtime_data,
+ self.name)
+
+ return self.update_with_template(self.parsed_nested,
+ self._to_parameters())
+
def handle_delete(self):
return self.delete_nested()
diff --git a/heat/tests/test_provider_template.py b/heat/tests/test_provider_template.py
index 08c96af79..500cc5979 100644
--- a/heat/tests/test_provider_template.py
+++ b/heat/tests/test_provider_template.py
@@ -24,6 +24,7 @@ from heat.engine import parser
from heat.engine import properties
from heat.engine import resource
from heat.engine import resources
+from heat.engine import scheduler
from heat.engine.resources import template_resource
from heat.openstack.common import uuidutils
@@ -495,3 +496,73 @@ class ProviderTemplateTest(HeatTestCase):
stack)
self.assertRaises(exception.StackValidationFailed, temp_res.validate)
self.m.VerifyAll()
+
+ def create_stack(self, template):
+ t = template_format.parse(template)
+ stack = self.parse_stack(t)
+ stack.create()
+ self.assertEqual(stack.state, (stack.CREATE, stack.COMPLETE))
+ return stack
+
+ def parse_stack(self, t):
+ ctx = utils.dummy_context('test_username', 'aaaa', 'password')
+ stack_name = 'test_stack'
+ tmpl = parser.Template(t)
+ stack = parser.Stack(ctx, stack_name, tmpl)
+ stack.store()
+ return stack
+
+ def test_template_resource_update(self):
+ # assertion: updating a template resource is never destructive
+ # as it defers to the nested stack to determine if anything
+ # needs to be replaced.
+
+ utils.setup_dummy_db()
+ resource._register_class('GenericResource',
+ generic_rsrc.GenericResource)
+
+ templ_resource_name = 'http://server.test/the.yaml'
+ test_template = '''
+HeatTemplateFormatVersion: '2012-12-12'
+Resources:
+ the_nested:
+ Type: %s
+ Properties:
+ one: myname
+''' % templ_resource_name
+
+ self.m.StubOutWithMock(urlfetch, "get")
+ urlfetch.get(templ_resource_name,
+ allowed_schemes=('http',
+ 'https')).MultipleTimes().\
+ AndReturn('''
+HeatTemplateFormatVersion: '2012-12-12'
+Parameters:
+ one:
+ Type: String
+Resources:
+ NestedResource:
+ Type: GenericResource
+Outputs:
+ Foo:
+ Value: {Ref: one}
+''')
+
+ self.m.ReplayAll()
+
+ stack = self.create_stack(test_template)
+ templ_resource = stack['the_nested']
+ self.assertEqual('myname', templ_resource.FnGetAtt('Foo'))
+
+ update_snippet = {
+ "Type": templ_resource_name,
+ "Properties": {
+ "one": "yourname"
+ }
+ }
+ # test that update() does NOT raise UpdateReplace.
+ updater = scheduler.TaskRunner(templ_resource.update, update_snippet)
+ self.assertEqual(None, updater())
+ self.assertEqual('yourname', templ_resource.FnGetAtt('Foo'))
+
+ self.m.VerifyAll()