Merge "Allow functions to calculate dependencies"
This commit is contained in:
commit
0627b5bbf1
@ -12,6 +12,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import itertools
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import six
|
import six
|
||||||
@ -108,6 +109,10 @@ class ResourceRef(function.Function):
|
|||||||
raise exception.InvalidTemplateReference(resource=resource_name,
|
raise exception.InvalidTemplateReference(resource=resource_name,
|
||||||
key=path)
|
key=path)
|
||||||
|
|
||||||
|
def dependencies(self, path):
|
||||||
|
return itertools.chain(super(ResourceRef, self).dependencies(path),
|
||||||
|
[self._resource(path)])
|
||||||
|
|
||||||
def result(self):
|
def result(self):
|
||||||
return self._resource().FnGetRefId()
|
return self._resource().FnGetRefId()
|
||||||
|
|
||||||
@ -164,6 +169,10 @@ class GetAtt(function.Function):
|
|||||||
raise exception.InvalidTemplateReference(resource=resource_name,
|
raise exception.InvalidTemplateReference(resource=resource_name,
|
||||||
key=path)
|
key=path)
|
||||||
|
|
||||||
|
def dependencies(self, path):
|
||||||
|
return itertools.chain(super(GetAtt, self).dependencies(path),
|
||||||
|
[self._resource(path)])
|
||||||
|
|
||||||
def result(self):
|
def result(self):
|
||||||
attribute = function.resolve(self._attribute)
|
attribute = function.resolve(self._attribute)
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
import collections
|
import collections
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
class Function(object):
|
class Function(object):
|
||||||
@ -54,6 +55,9 @@ class Function(object):
|
|||||||
"""
|
"""
|
||||||
return {self.fn_name: self.args}
|
return {self.fn_name: self.args}
|
||||||
|
|
||||||
|
def dependencies(self, path):
|
||||||
|
return dependencies(self.args, '.'.join([path, self.fn_name]))
|
||||||
|
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
"""
|
"""
|
||||||
Return a representation of the function suitable for pickling.
|
Return a representation of the function suitable for pickling.
|
||||||
@ -130,3 +134,35 @@ def validate(snippet):
|
|||||||
isinstance(snippet, collections.Iterable)):
|
isinstance(snippet, collections.Iterable)):
|
||||||
for v in snippet:
|
for v in snippet:
|
||||||
validate(v)
|
validate(v)
|
||||||
|
|
||||||
|
|
||||||
|
def dependencies(snippet, path=''):
|
||||||
|
"""
|
||||||
|
Return an iterator over Resource dependencies in a template snippet.
|
||||||
|
|
||||||
|
The snippet should be already parsed to insert Function objects where
|
||||||
|
appropriate.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(snippet, Function):
|
||||||
|
return snippet.dependencies(path)
|
||||||
|
|
||||||
|
elif isinstance(snippet, collections.Mapping):
|
||||||
|
def mkpath(key):
|
||||||
|
return '.'.join([path, unicode(key)])
|
||||||
|
|
||||||
|
deps = (dependencies(value,
|
||||||
|
mkpath(key)) for key, value in snippet.items())
|
||||||
|
return itertools.chain.from_iterable(deps)
|
||||||
|
|
||||||
|
elif (not isinstance(snippet, basestring) and
|
||||||
|
isinstance(snippet, collections.Iterable)):
|
||||||
|
def mkpath(idx):
|
||||||
|
return ''.join([path, '[%d]' % idx])
|
||||||
|
|
||||||
|
deps = (dependencies(value,
|
||||||
|
mkpath(i)) for i, value in enumerate(snippet))
|
||||||
|
return itertools.chain.from_iterable(deps)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
@ -22,6 +22,9 @@ class TestFunction(function.Function):
|
|||||||
if len(self.args) < 2:
|
if len(self.args) < 2:
|
||||||
raise Exception(_('Need more arguments'))
|
raise Exception(_('Need more arguments'))
|
||||||
|
|
||||||
|
def dependencies(self, path):
|
||||||
|
return ['foo', 'bar']
|
||||||
|
|
||||||
def result(self):
|
def result(self):
|
||||||
return 'wibble'
|
return 'wibble'
|
||||||
|
|
||||||
@ -122,3 +125,20 @@ class ValidateTest(HeatTestCase):
|
|||||||
snippet = {'foo': 'bar', 'blarg': self.func}
|
snippet = {'foo': 'bar', 'blarg': self.func}
|
||||||
ex = self.assertRaises(Exception, function.validate, snippet)
|
ex = self.assertRaises(Exception, function.validate, snippet)
|
||||||
self.assertEqual('Need more arguments', str(ex))
|
self.assertEqual('Need more arguments', str(ex))
|
||||||
|
|
||||||
|
|
||||||
|
class DependenciesTest(HeatTestCase):
|
||||||
|
func = TestFunction(None, 'test', None)
|
||||||
|
|
||||||
|
scenarios = [
|
||||||
|
('function', dict(snippet=func)),
|
||||||
|
('nested_map', dict(snippet={'wibble': func})),
|
||||||
|
('nested_list', dict(snippet=['wibble', func])),
|
||||||
|
('deep_nested', dict(snippet=[{'wibble': ['wibble', func]}])),
|
||||||
|
]
|
||||||
|
|
||||||
|
def test_dependencies(self):
|
||||||
|
deps = list(function.dependencies(self.snippet))
|
||||||
|
self.assertIn('foo', deps)
|
||||||
|
self.assertIn('bar', deps)
|
||||||
|
self.assertEqual(2, len(deps))
|
||||||
|
Loading…
Reference in New Issue
Block a user