Convergence: add support for the path_component

store the attr name and path so attributes don't get shadowed
e.g. get_attr: [res1, attr_x, show]
     get_attr: [res1, attr_x, something]

Change-Id: I724e91b32776aa5813d2b821c2062424e0635a69
This commit is contained in:
Angus Salkeld 2015-08-18 12:10:52 +10:00 committed by Anant Patil
parent bdfd84e19d
commit dd0859a080
6 changed files with 77 additions and 5 deletions

View File

@ -125,6 +125,19 @@ class GetAttThenSelect(cfn_funcs.GetAtt):
path_components = function.resolve(self._path_components)
return attributes.select_from_attribute(attribute, path_components)
def dep_attrs(self, resource_name):
if self._resource().name == resource_name:
path = function.resolve(self._path_components)
attr = [function.resolve(self._attribute)]
if path:
attrs = [tuple(attr + path)]
else:
attrs = attr
else:
attrs = []
return itertools.chain(function.dep_attrs(self.args, resource_name),
attrs)
class GetAtt(GetAttThenSelect):
'''

View File

@ -1474,8 +1474,11 @@ class Resource(object):
'''
if self.stack.has_cache_data(self.name):
# Load from cache for lightweight resources.
complex_key = key
if path:
complex_key = tuple([key] + list(path))
attribute = self.stack.cache_data_resource_attribute(
self.name, key)
self.name, complex_key)
else:
try:
attribute = self.attributes[key]

View File

@ -315,7 +315,10 @@ def construct_input_data(rsrc):
resolved_attributes = {}
for attr in attributes:
try:
resolved_attributes[attr] = rsrc.FnGetAtt(attr)
if isinstance(attr, six.string_types):
resolved_attributes[attr] = rsrc.FnGetAtt(attr)
else:
resolved_attributes[attr] = rsrc.FnGetAtt(*attr)
except exception.InvalidTemplateAttribute as ita:
LOG.info(six.text_type(ita))

View File

@ -520,12 +520,15 @@ class MiscMethodsTest(common.HeatTestCase):
self.ctx = utils.dummy_context()
self.stack = tools.get_stack(
'check_workflow_create_stack', self.ctx,
template=tools.string_template_five, convergence=True)
template=tools.attr_cache_template, convergence=True)
self.stack.converge_stack(self.stack.t)
self.resource = self.stack['A']
def test_construct_input_data_ok(self):
expected_input_data = {'attrs': {'value': None},
expected_input_data = {'attrs': {(u'flat_dict', u'key2'): 'val2',
(u'flat_dict', u'key3'): 'val3',
(u'nested_dict', u'dict', u'a'): 1,
(u'nested_dict', u'dict', u'b'): 2},
'id': mock.ANY,
'reference_id': 'A',
'name': 'A'}

View File

@ -123,6 +123,32 @@ resources:
salt: {get_param: salt}
'''
attr_cache_template = '''
heat_template_version: 2013-05-23
resources:
A:
type: ResourceWithComplexAttributesType
B:
type: OS::Heat::RandomString
properties:
salt: {get_attr: [A, flat_dict, key2]}
C:
type: OS::Heat::RandomString
depends_on: [A, B]
properties:
salt: {get_attr: [A, nested_dict, dict, a]}
D:
type: OS::Heat::RandomString
depends_on: C
properties:
salt: {get_attr: [A, nested_dict, dict, b]}
E:
type: OS::Heat::RandomString
depends_on: C
properties:
salt: {get_attr: [A, flat_dict, key3]}
'''
def get_stack(stack_name, ctx, template=None, with_params=True,
convergence=False):

View File

@ -130,6 +130,23 @@ outputs:
{get_attr: [BResource, attr_B3]}]
"""
tmpl6 = """
heat_template_version: 2015-04-30
resources:
AResource:
type: ResourceWithComplexAttributesType
BResource:
type: ResourceWithPropsType
properties:
Foo: {get_attr: [AResource, list, 1]}
Doo: {get_attr: [AResource, nested_dict, dict, b]}
outputs:
out1:
value: [{get_attr: [AResource, flat_dict, key2]},
{get_attr: [AResource, nested_dict, string]},
{get_attr: [BResource, attr_B3]}]
"""
class DepAttrsTest(common.HeatTestCase):
@ -159,7 +176,14 @@ class DepAttrsTest(common.HeatTestCase):
'attr_A3', 'attr_A4'},
'BResource': {'attr_B1', 'attr_B2', 'meta_B2',
'attr_B3'},
'CResource': set()}))
'CResource': set()})),
('nested_attr',
dict(tmpl=tmpl6,
expected={'AResource': set([(u'flat_dict', u'key2'),
(u'list', 1),
(u'nested_dict', u'dict', u'b'),
(u'nested_dict', u'string')]),
'BResource': set(['attr_B3'])}))
]
def setUp(self):