diff --git a/heat/engine/cfn/functions.py b/heat/engine/cfn/functions.py index d354d8dba6..c0a1385240 100644 --- a/heat/engine/cfn/functions.py +++ b/heat/engine/cfn/functions.py @@ -99,7 +99,7 @@ def Ref(stack, fn_name, args): { "Ref" : "" } """ - if args in stack: + if stack is None or args in stack: RefClass = hot_funcs.GetResource else: RefClass = ParamRef diff --git a/heat/engine/resources/openstack/heat/autoscaling_group.py b/heat/engine/resources/openstack/heat/autoscaling_group.py index 54add09dc0..9410d574bc 100644 --- a/heat/engine/resources/openstack/heat/autoscaling_group.py +++ b/heat/engine/resources/openstack/heat/autoscaling_group.py @@ -219,28 +219,34 @@ class AutoScalingResourceGroup(aws_asg.AutoScalingGroup): raise exception.InvalidTemplateAttribute(resource=self.name, key=key) - def _nested_output_defns(self, resource_names, get_attr_fn): + def _nested_output_defns(self, resource_names, get_attr_fn, get_res_fn): for attr in self.referenced_attrs(): if isinstance(attr, six.string_types): key, path = attr, [] - output_name = attr else: key, path = attr[0], list(attr[1:]) - output_name = ', '.join(six.text_type(a) for a in attr) - + # Always use map types, as list order is not defined at + # template generation time. + if key == self.OUTPUTS_LIST: + key = self.OUTPUTS + if key == self.REFS: + key = self.REFS_MAP if key.startswith("resource."): keycomponents = key.split('.', 2) path = keycomponents[2:] + path if path: key = self.OUTPUTS - output_name = ', '.join([self.OUTPUTS] + path) + else: + key = self.REFS_MAP + output_name = ', '.join(six.text_type(a) for a in [key] + path) + value = None - if key == self.OUTPUTS and path: + if key == self.REFS_MAP: + value = {r: get_res_fn(r) for r in resource_names} + elif key == self.OUTPUTS and path: value = {r: get_attr_fn([r] + path) for r in resource_names} - yield output.OutputDefinition(output_name, value) - elif key == self.OUTPUTS_LIST and path: - value = [get_attr_fn([r] + path) for r in resource_names] + if value is not None: yield output.OutputDefinition(output_name, value) diff --git a/heat/engine/resources/openstack/heat/instance_group.py b/heat/engine/resources/openstack/heat/instance_group.py index 75f3c53a20..ebfd3d2cf3 100644 --- a/heat/engine/resources/openstack/heat/instance_group.py +++ b/heat/engine/resources/openstack/heat/instance_group.py @@ -274,12 +274,13 @@ class InstanceGroup(stack_resource.StackResource): child_env=child_env) # Subclasses use HOT templates - att_func = 'get_attr' - if att_func not in tmpl.functions: - att_func = 'Fn::GetAtt' + att_func, res_func = 'get_attr', 'get_resource' + if att_func not in tmpl.functions or res_func not in tmpl.functions: + att_func, res_func = 'Fn::GetAtt', 'Ref' get_attr = functools.partial(tmpl.functions[att_func], None, att_func) + get_res = functools.partial(tmpl.functions[res_func], None, res_func) for odefn in self._nested_output_defns([k for k, d in definitions], - get_attr): + get_attr, get_res): tmpl.add_output(odefn) return tmpl @@ -400,7 +401,7 @@ class InstanceGroup(stack_resource.StackResource): return u','.join(inst.FnGetAtt('PublicIp') or '0.0.0.0' for inst in grouputils.get_members(self)) or None - def _nested_output_defns(self, resource_names, get_attr_fn): + def _nested_output_defns(self, resource_names, get_attr_fn, get_res_fn): for attr in self.referenced_attrs(): if isinstance(attr, six.string_types): key = attr @@ -408,7 +409,8 @@ class InstanceGroup(stack_resource.StackResource): key = attr[0] if key == self.INSTANCE_LIST: - value = [get_attr_fn([r, 'PublicIp']) for r in resource_names] + value = {r: get_attr_fn([r, 'PublicIp']) + for r in resource_names} yield output.OutputDefinition(key, value) def child_template(self): diff --git a/heat/engine/resources/openstack/heat/resource_chain.py b/heat/engine/resources/openstack/heat/resource_chain.py index 330f7989f1..bdc11d8c07 100644 --- a/heat/engine/resources/openstack/heat/resource_chain.py +++ b/heat/engine/resources/openstack/heat/resource_chain.py @@ -130,8 +130,11 @@ class ResourceChain(stack_resource.StackResource): att_func = 'get_attr' get_attr = functools.partial(nested_template.functions[att_func], None, att_func) + res_func = 'get_resource' + get_res = functools.partial(nested_template.functions[res_func], + None, res_func) res_names = [k for k, d in name_def_tuples] - for odefn in self._nested_output_defns(res_names, get_attr): + for odefn in self._nested_output_defns(res_names, get_attr, get_res): nested_template.add_output(odefn) return nested_template @@ -159,7 +162,7 @@ class ResourceChain(stack_resource.StackResource): return [grouputils.get_rsrc_attr(self, key, False, n, *path) for n in names] - def _nested_output_defns(self, resource_names, get_attr_fn): + def _nested_output_defns(self, resource_names, get_attr_fn, get_res_fn): for attr in self.referenced_attrs(): if isinstance(attr, six.string_types): key, path = attr, [] @@ -167,21 +170,25 @@ class ResourceChain(stack_resource.StackResource): else: key, path = attr[0], list(attr[1:]) output_name = ', '.join(six.text_type(a) for a in attr) + value = None if key.startswith("resource."): keycomponents = key.split('.', 2) res_name = keycomponents[1] attr_path = keycomponents[2:] + path - if attr_path and (res_name in resource_names): - value = get_attr_fn([res_name] + attr_path) - yield output.OutputDefinition(output_name, value) - + if res_name in resource_names: + if attr_path: + value = get_attr_fn([res_name] + attr_path) + else: + value = get_res_fn(res_name) + elif key == self.REFS: + value = [get_res_fn(r) for r in resource_names] elif key == self.ATTR_ATTRIBUTES and path: value = {r: get_attr_fn([r] + path) for r in resource_names} - yield output.OutputDefinition(output_name, value) - elif key not in self.ATTRIBUTES: value = [get_attr_fn([r, key] + path) for r in resource_names] + + if value is not None: yield output.OutputDefinition(output_name, value) @staticmethod diff --git a/heat/engine/resources/openstack/heat/resource_group.py b/heat/engine/resources/openstack/heat/resource_group.py index d9a3a3dc4f..def39be388 100644 --- a/heat/engine/resources/openstack/heat/resource_group.py +++ b/heat/engine/resources/openstack/heat/resource_group.py @@ -480,7 +480,7 @@ class ResourceGroup(stack_resource.StackResource): return [grouputils.get_rsrc_attr(self, key, False, n, *path) for n in names] - def _nested_output_defns(self, resource_names, get_attr_fn): + def _nested_output_defns(self, resource_names, get_attr_fn, get_res_fn): for attr in self.referenced_attrs(): if isinstance(attr, six.string_types): key, path = attr, [] @@ -488,21 +488,28 @@ class ResourceGroup(stack_resource.StackResource): else: key, path = attr[0], list(attr[1:]) output_name = ', '.join(six.text_type(a) for a in attr) + value = None if key.startswith("resource."): keycomponents = key.split('.', 2) res_name = keycomponents[1] attr_path = keycomponents[2:] + path - if attr_path and (res_name in resource_names): - value = get_attr_fn([res_name] + attr_path) - yield output.OutputDefinition(output_name, value) - + if attr_path: + if res_name in resource_names: + value = get_attr_fn([res_name] + attr_path) + else: + output_name = key = self.REFS_MAP elif key == self.ATTR_ATTRIBUTES and path: value = {r: get_attr_fn([r] + path) for r in resource_names} - yield output.OutputDefinition(output_name, value) - elif key not in self.ATTRIBUTES: value = [get_attr_fn([r, key] + path) for r in resource_names] + + if key == self.REFS: + value = [get_res_fn(r) for r in resource_names] + elif key == self.REFS_MAP: + value = {r: get_res_fn(r) for r in resource_names} + + if value is not None: yield output.OutputDefinition(output_name, value) def build_resource_definition(self, res_name, res_defn): @@ -579,8 +586,10 @@ class ResourceGroup(stack_resource.StackResource): def _add_output_defns_to_template(self, tmpl, resource_names): att_func = 'get_attr' get_attr = functools.partial(tmpl.functions[att_func], None, att_func) + res_func = 'get_resource' + get_res = functools.partial(tmpl.functions[res_func], None, res_func) for odefn in self._nested_output_defns(resource_names, - get_attr): + get_attr, get_res): tmpl.add_output(odefn) def _assemble_nested(self, names, include_all=False, diff --git a/heat/engine/resources/openstack/heat/software_deployment.py b/heat/engine/resources/openstack/heat/software_deployment.py index 43c1ae1cd8..5bcc1680ce 100644 --- a/heat/engine/resources/openstack/heat/software_deployment.py +++ b/heat/engine/resources/openstack/heat/software_deployment.py @@ -735,7 +735,7 @@ class SoftwareDeploymentGroup(resource_group.ResourceGroup): rg_attr = rg.get_attribute(rg.ATTR_ATTRIBUTES, n_attr) return attributes.select_from_attribute(rg_attr, path) - def _nested_output_defns(self, resource_names, get_attr_fn): + def _nested_output_defns(self, resource_names, get_attr_fn, get_res_fn): for attr in self.referenced_attrs(): key = attr if isinstance(attr, six.string_types) else attr[0] n_attr = self._member_attribute_name(key)