Merge "Cache names of required resources in ResourceDefinition"

This commit is contained in:
Jenkins 2017-07-31 12:04:56 +00:00 committed by Gerrit Code Review
commit 8c7b66a8a3
2 changed files with 46 additions and 27 deletions

View File

@ -99,6 +99,7 @@ class ResourceDefinition(object):
self._hash = hash(self.resource_type)
self._rendering = None
self._dep_names = None
assert isinstance(self.description, six.string_types)
@ -202,11 +203,44 @@ class ResourceDefinition(object):
function.dep_attrs(self._metadata,
resource_name))
def required_resource_names(self):
"""Return a set of names of all resources on which this depends.
Note that this is done entirely in isolation from the rest of the
template, so the resource names returned may refer to resources that
don't actually exist, or would have strict_dependency=False. Use the
dependencies() method to get validated dependencies.
"""
if self._dep_names is None:
explicit_depends = [] if self._depends is None else self._depends
def path(section):
return '.'.join([self.name, section])
prop_deps = function.dependencies(self._properties,
path('Properties'))
metadata_deps = function.dependencies(self._metadata,
path('Metadata'))
implicit_depends = six.moves.map(lambda rp: rp.name,
itertools.chain(prop_deps,
metadata_deps))
# (ricolin) External resource should not depend on any other
# resources. This operation is not allowed for now.
if self.external_id():
if explicit_depends:
raise exception.InvalidExternalResourceDependency(
external_id=self.external_id(),
resource_type=self.resource_type
)
self._dep_names = set()
else:
self._dep_names = set(itertools.chain(explicit_depends,
implicit_depends))
return self._dep_names
def dependencies(self, stack):
"""Return the Resource objects in given stack on which this depends."""
def path(section):
return '.'.join([self.name, section])
def get_resource(res_name):
if res_name not in stack:
if res_name in stack.t.get(stack.t.RESOURCES):
@ -215,31 +249,13 @@ class ResourceDefinition(object):
return
raise exception.InvalidTemplateReference(resource=res_name,
key=self.name)
return stack[res_name]
res = stack[res_name]
if getattr(res, 'strict_dependency', True):
return res
def strict_func_deps(data, datapath):
return six.moves.filter(
lambda r: getattr(r, 'strict_dependency', True),
six.moves.map(lambda rp: stack[rp.name],
function.dependencies(data, datapath)))
explicit_depends = [] if self._depends is None else self._depends
prop_deps = strict_func_deps(self._properties, path('Properties'))
metadata_deps = strict_func_deps(self._metadata, path('Metadata'))
# (ricolin) External resource should not depend on any other resources.
# This operation is not allowed for now.
if self.external_id():
if explicit_depends:
raise exception.InvalidExternalResourceDependency(
external_id=self.external_id(),
resource_type=self.resource_type
)
return itertools.chain()
return itertools.chain(
filter(None, (get_resource(dep) for dep in explicit_depends)),
prop_deps, metadata_deps)
return six.moves.filter(None,
six.moves.map(get_resource,
self.required_resource_names()))
def set_translation_rules(self, rules=None, client_resolve=True):
"""Helper method to update properties with translation rules."""

View File

@ -92,11 +92,13 @@ class ResourceDefinitionTest(common.HeatTestCase):
def test_dependencies_default(self):
rd = rsrc_defn.ResourceDefinition('rsrc', 'SomeType')
stack = {'foo': 'FOO', 'bar': 'BAR'}
self.assertEqual(set(), rd.required_resource_names())
self.assertEqual([], list(rd.dependencies(stack)))
def test_dependencies_explicit(self):
rd = rsrc_defn.ResourceDefinition('rsrc', 'SomeType', depends=['foo'])
stack = {'foo': 'FOO', 'bar': 'BAR'}
self.assertEqual({'foo'}, rd.required_resource_names())
self.assertEqual(['FOO'], list(rd.dependencies(stack)))
def test_dependencies_explicit_ext(self):
@ -117,6 +119,7 @@ class ResourceDefinitionTest(common.HeatTestCase):
t = template_format.parse(TEMPLATE_WITH_INVALID_EXPLICIT_DEPEND)
stack = utils.parse_stack(t)
rd = stack.t.resource_definitions(stack)['test3']
self.assertEqual({'test2'}, rd.required_resource_names())
self.assertRaises(exception.InvalidTemplateReference,
lambda: list(rd.dependencies(stack)))