From 3569bf2323baaab90c37a2f164f3a13bfee3c644 Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Mon, 28 Jan 2013 16:52:23 +0000 Subject: [PATCH] heat engine : add Resource update_template_diff method Add method to top-level Resource class update_template_diff() which allows us to determine the difference between old/new templates for a resource update, and also raise an error if the changed keys are not in the list of those defined as supported for update by the resource ref blueprint instance-update-stack Change-Id: Ibef07a0cecbc15f7f1d6c2c663743e3af8023057 Signed-off-by: Steven Hardy --- heat/engine/resource.py | 30 +++++++++++++++++++++++++++++ heat/tests/test_resource.py | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/heat/engine/resource.py b/heat/engine/resource.py index c8cd53d1b6..f8ea86b2b7 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -101,6 +101,10 @@ class Resource(object): metadata = Metadata() + # Resource implementation set this to the subset of template keys + # which are supported for handle_update, used by update_template_diff + update_allowed_keys = () + def __new__(cls, name, json, stack): '''Create a new Resource of the appropriate class for its type.''' @@ -174,6 +178,32 @@ class Resource(object): template = self.t.get(section, default) return self.stack.resolve_runtime_data(template) + def update_template_diff(self, json_snippet=None): + ''' + Returns the difference between json_template and self.t + If something has been removed in json_snippet which exists + in self.t we set it to None. If any keys have changed which + are not in update_allowed_keys, raises NotImplementedError + ''' + update_allowed_set = set(self.update_allowed_keys) + + # Create a set containing the keys in both current and update template + current_snippet = self.parsed_template() + template_keys = set(current_snippet.keys()) + template_keys.update(set(json_snippet.keys())) + + # Create a set of keys which differ (or are missing/added) + changed_keys_set = set([k for k in template_keys + if current_snippet.get(k, None) != + json_snippet.get(k, None)]) + + if not changed_keys_set.issubset(update_allowed_set): + badkeys = changed_keys_set - update_allowed_set + raise NotImplementedError("Cannot update keys %s for %s" % + (badkeys, self.name)) + + return dict((k, json_snippet.get(k, None)) for k in changed_keys_set) + def __str__(self): return '%s "%s"' % (self.__class__.__name__, self.name) diff --git a/heat/tests/test_resource.py b/heat/tests/test_resource.py index eee6754f65..71531b8ec5 100644 --- a/heat/tests/test_resource.py +++ b/heat/tests/test_resource.py @@ -115,6 +115,44 @@ class ResourceTest(unittest.TestCase): self.assertNotEqual(res1, res2) + def test_update_template_diff_empty(self): + tmpl = {'Type': 'Foo'} + update_snippet = {} + res = resource.GenericResource('test_resource', tmpl, self.stack) + self.assertRaises(NotImplementedError, res.update_template_diff, + update_snippet) + + def test_update_template_diff_changed_notallowed(self): + tmpl = {'Type': 'Foo'} + update_snippet = {'Type': 'Bar'} + res = resource.GenericResource('test_resource', tmpl, self.stack) + self.assertRaises(NotImplementedError, res.update_template_diff, + update_snippet) + + def test_update_template_diff_changed_modified(self): + tmpl = {'Type': 'Foo', 'Metadata': {'foo': 123}} + update_snippet = {'Type': 'Foo', 'Metadata': {'foo': 456}} + res = resource.GenericResource('test_resource', tmpl, self.stack) + res.update_allowed_keys = ['Metadata'] + diff = res.update_template_diff(json_snippet=update_snippet) + self.assertEqual(diff, {'Metadata': {'foo': 456}}) + + def test_update_template_diff_changed_add(self): + tmpl = {'Type': 'Foo'} + update_snippet = {'Type': 'Foo', 'Metadata': {'foo': 123}} + res = resource.GenericResource('test_resource', tmpl, self.stack) + res.update_allowed_keys = ['Metadata'] + diff = res.update_template_diff(json_snippet=update_snippet) + self.assertEqual(diff, {'Metadata': {'foo': 123}}) + + def test_update_template_diff_changed_remove(self): + tmpl = {'Type': 'Foo', 'Metadata': {'foo': 123}} + update_snippet = {'Type': 'Foo'} + res = resource.GenericResource('test_resource', tmpl, self.stack) + res.update_allowed_keys = ['Metadata'] + diff = res.update_template_diff(json_snippet=update_snippet) + self.assertEqual(diff, {'Metadata': None}) + @attr(tag=['unit', 'resource']) @attr(speed='fast')