From de96d030ff0530c906ba1f9525d5881edad605a0 Mon Sep 17 00:00:00 2001 From: Thomas Herve Date: Thu, 26 May 2016 11:32:20 +0200 Subject: [PATCH] Fix resource loading in resource filtering We try to be careful when filtering resources from stack, to not load all of them, but unfortunately it breaks as soon as you have dependencies with resources that are not returned. To be on the safe side we need to load them all and filter them afterwards. Change-Id: I399545a6a4fd77d9707505ec9c4058d384877dec Closes-Bug: #1585931 --- heat/engine/stack.py | 36 +++++++--------- .../functional/test_resources_list.py | 43 +++++++++++++++++++ 2 files changed, 58 insertions(+), 21 deletions(-) create mode 100644 heat_integrationtests/functional/test_resources_list.py diff --git a/heat/engine/stack.py b/heat/engine/stack.py index 21196ba937..98e948845c 100644 --- a/heat/engine/stack.py +++ b/heat/engine/stack.py @@ -286,38 +286,32 @@ class Stack(collections.Mapping): def resources(self): return self._find_resources() - def _find_resources(self, filters=None): + def _find_resources(self): if self._resources is None: res_defns = self.t.resource_definitions(self) - if not filters: - self._resources = dict((name, - resource.Resource(name, data, self)) - for (name, data) in res_defns.items()) - else: - self._resources = dict() - self._db_resources = dict() - for rsc in six.itervalues( - resource_objects.Resource.get_all_by_stack( - self.context, self.id, True, filters)): - self._db_resources[rsc.name] = rsc - res = resource.Resource(rsc.name, - res_defns[rsc.name], - self) - self._resources[rsc.name] = res - - # There is no need to continue storing the db resources - # after resource creation - self._db_resources = None + self._resources = dict((name, + resource.Resource(name, data, self)) + for (name, data) in res_defns.items()) return self._resources + def _find_filtered_resources(self, filters): + for rsc in six.itervalues( + resource_objects.Resource.get_all_by_stack( + self.context, self.id, True, filters)): + yield self.resources[rsc.name] + def iter_resources(self, nested_depth=0, filters=None): """Iterates over all the resources in a stack. Iterating includes nested stacks up to `nested_depth` levels below. """ - for res in six.itervalues(self._find_resources(filters)): + if not filters: + resources = six.itervalues(self.resources) + else: + resources = self._find_filtered_resources(filters) + for res in resources: yield res if not res.has_nested() or nested_depth == 0: diff --git a/heat_integrationtests/functional/test_resources_list.py b/heat_integrationtests/functional/test_resources_list.py new file mode 100644 index 0000000000..257afc5651 --- /dev/null +++ b/heat_integrationtests/functional/test_resources_list.py @@ -0,0 +1,43 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from heat_integrationtests.functional import functional_base + + +test_template_depend = { + 'heat_template_version': '2013-05-23', + 'resources': { + 'test1': { + 'type': 'OS::Heat::TestResource', + 'properties': { + 'value': 'Test1', + } + }, + 'test2': { + 'type': 'OS::Heat::TestResource', + 'depends_on': ['test1'], + 'properties': { + 'value': 'Test2', + } + } + } +} + + +class ResourcesList(functional_base.FunctionalTestsBase): + + def test_filtering_with_depend(self): + stack_identifier = self.stack_create(template=test_template_depend) + [test2] = self.client.resources.list(stack_identifier, + filters={'name': 'test2'}) + + self.assertEqual('CREATE_COMPLETE', test2.resource_status)