From 82622652920e9912b2cbb8c3724b2e4de8892527 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Thu, 8 Sep 2016 17:00:48 -0400 Subject: [PATCH] Make cfn functions inherit from HOT HOT is our canonical native format, so define the cfn intrinsic functions in terms of the HOT functions instead of the other way around. Ensure each function has a consistently-formatted docstring appropriate to its template type. Change-Id: I743446bdef3fd7472537db75bf9e0fbfb164e36a --- heat/engine/cfn/functions.py | 270 +++++------------ heat/engine/cfn/template.py | 9 +- heat/engine/hot/functions.py | 278 ++++++++++++++++-- heat/engine/hot/template.py | 12 +- heat/engine/translation.py | 2 +- .../neutron/test_neutron_floating_ip.py | 6 +- .../openstack/neutron/test_neutron_subnet.py | 4 +- heat/tests/test_properties.py | 4 +- heat/tests/test_translation_rule.py | 4 +- 9 files changed, 333 insertions(+), 256 deletions(-) diff --git a/heat/engine/cfn/functions.py b/heat/engine/cfn/functions.py index 1e236f50f4..085fde05b4 100644 --- a/heat/engine/cfn/functions.py +++ b/heat/engine/cfn/functions.py @@ -12,7 +12,6 @@ # under the License. import collections -import itertools from oslo_serialization import jsonutils import six @@ -21,6 +20,7 @@ from heat.api.aws import utils as aws_utils from heat.common import exception from heat.common.i18n import _ from heat.engine import function +from heat.engine.hot import functions as hot_funcs class FindInMap(function.Function): @@ -88,31 +88,6 @@ class ParamRef(function.Function): key='unknown') -class ResourceRef(function.Function): - """A function for resolving resource references. - - Takes the form:: - - { "Ref" : "" } - """ - - def _resource(self, path='unknown'): - resource_name = function.resolve(self.args) - - try: - return self.stack[resource_name] - except KeyError: - raise exception.InvalidTemplateReference(resource=resource_name, - key=path) - - def dependencies(self, path): - return itertools.chain(super(ResourceRef, self).dependencies(path), - [self._resource(path)]) - - def result(self): - return self._resource().FnGetRefId() - - def Ref(stack, fn_name, args): """A function for resolving parameters or resource references. @@ -125,26 +100,21 @@ def Ref(stack, fn_name, args): { "Ref" : "" } """ if args in stack: - RefClass = ResourceRef + RefClass = hot_funcs.GetResource else: RefClass = ParamRef return RefClass(stack, fn_name, args) -class GetAtt(function.Function): +class GetAtt(hot_funcs.GetAttThenSelect): """A function for resolving resource attributes. Takes the form:: { "Fn::GetAtt" : [ "", - "" ] } """ - def __init__(self, stack, fn_name, args): - super(GetAtt, self).__init__(stack, fn_name, args) - - self._resource_name, self._attribute = self._parse_args() - def _parse_args(self): try: resource_name, attribute = self.args @@ -152,62 +122,7 @@ class GetAtt(function.Function): raise ValueError(_('Arguments to "%s" must be of the form ' '[resource_name, attribute]') % self.fn_name) - return resource_name, attribute - - def _resource(self, path='unknown'): - resource_name = function.resolve(self._resource_name) - - try: - return self.stack[resource_name] - except KeyError: - raise exception.InvalidTemplateReference(resource=resource_name, - key=path) - - def dep_attrs(self, resource_name): - if self._resource().name == resource_name: - attrs = [function.resolve(self._attribute)] - else: - attrs = [] - return itertools.chain(super(GetAtt, self).dep_attrs(resource_name), - attrs) - - def dependencies(self, path): - return itertools.chain(super(GetAtt, self).dependencies(path), - [self._resource(path)]) - - def _allow_without_attribute_name(self): - return False - - def validate(self): - super(GetAtt, self).validate() - res = self._resource() - - if self._allow_without_attribute_name(): - # if allow without attribute_name, then don't check - # when attribute_name is None - if self._attribute is None: - return - - attr = function.resolve(self._attribute) - from heat.engine import resource - if (type(res).get_attribute == resource.Resource.get_attribute and - attr not in res.attributes_schema): - raise exception.InvalidTemplateAttribute( - resource=self._resource_name, key=attr) - - def result(self): - attribute = function.resolve(self._attribute) - - r = self._resource() - if r.action in (r.CREATE, r.ADOPT, r.SUSPEND, r.RESUME, - r.UPDATE, r.ROLLBACK, r.SNAPSHOT, r.CHECK): - return r.FnGetAtt(attribute) - # NOTE(sirushtim): Add r.INIT to states above once convergence - # is the default. - elif r.stack.has_cache_data(r.name) and r.action == r.INIT: - return r.FnGetAtt(attribute) - else: - return None + return resource_name, attribute, [] class Select(function.Function): @@ -217,7 +132,7 @@ class Select(function.Function): { "Fn::Select" : [ "", [ "", "", ... ] ] } - Takes the form (for a map lookup):: + or (for a map lookup):: { "Fn::Select" : [ "", { "": "", ... } ] } @@ -283,7 +198,7 @@ class Select(function.Function): self.fn_name) -class Join(function.Function): +class Join(hot_funcs.Join): """A function for joining strings. Takes the form:: @@ -295,47 +210,6 @@ class Join(function.Function): "..." """ - def __init__(self, stack, fn_name, args): - super(Join, self).__init__(stack, fn_name, args) - - example = '"%s" : [ " ", [ "str1", "str2"]]' % self.fn_name - fmt_data = {'fn_name': self.fn_name, - 'example': example} - - if not isinstance(self.args, list): - raise TypeError(_('Incorrect arguments to "%(fn_name)s" ' - 'should be: %(example)s') % fmt_data) - - try: - self._delim, self._strings = self.args - except ValueError: - raise ValueError(_('Incorrect arguments to "%(fn_name)s" ' - 'should be: %(example)s') % fmt_data) - - def result(self): - strings = function.resolve(self._strings) - if strings is None: - strings = [] - if (isinstance(strings, six.string_types) or - not isinstance(strings, collections.Sequence)): - raise TypeError(_('"%s" must operate on a list') % self.fn_name) - - delim = function.resolve(self._delim) - if not isinstance(delim, six.string_types): - raise TypeError(_('"%s" delimiter must be a string') % - self.fn_name) - - def ensure_string(s): - if s is None: - return '' - if not isinstance(s, six.string_types): - raise TypeError( - _('Items to join must be strings not %s' - ) % (repr(s)[:200])) - return s - - return delim.join(ensure_string(s) for s in strings) - class Split(function.Function): """A function for splitting strings. @@ -379,7 +253,7 @@ class Split(function.Function): return strings.split(self._delim) -class Replace(function.Function): +class Replace(hot_funcs.Replace): """A function for performing string substitutions. Takes the form:: @@ -398,15 +272,6 @@ class Replace(function.Function): performed is otherwise undefined. """ - def __init__(self, stack, fn_name, args): - super(Replace, self).__init__(stack, fn_name, args) - - self._mapping, self._string = self._parse_args() - if not isinstance(self._mapping, - (collections.Mapping, function.Function)): - raise TypeError(_('"%s" parameters must be a mapping') % - self.fn_name) - def _parse_args(self): example = ('{"%s": ' @@ -427,39 +292,6 @@ class Replace(function.Function): else: return mapping, string - def result(self): - template = function.resolve(self._string) - mapping = function.resolve(self._mapping) - - if not isinstance(template, six.string_types): - raise TypeError(_('"%s" template must be a string') % self.fn_name) - - if not isinstance(mapping, collections.Mapping): - raise TypeError(_('"%s" params must be a map') % self.fn_name) - - def replace(string, change): - placeholder, value = change - - if not isinstance(placeholder, six.string_types): - raise TypeError(_('"%s" param placeholders must be strings') % - self.fn_name) - - if value is None: - value = '' - - if not isinstance(value, - (six.string_types, six.integer_types, - float, bool)): - raise TypeError(_('"%s" params must be strings or numbers') % - self.fn_name) - - return string.replace(placeholder, six.text_type(value)) - - mapping = collections.OrderedDict(sorted(mapping.items(), - key=lambda t: len(t[0]), - reverse=True)) - return six.moves.reduce(replace, six.iteritems(mapping), template) - class Base64(function.Function): """A placeholder function for converting to base64. @@ -535,7 +367,7 @@ class MemberListToMap(function.Function): valuename=self._valuename) -class ResourceFacade(function.Function): +class ResourceFacade(hot_funcs.ResourceFacade): """A function for retrieving data in a parent provider template. A function for obtaining data from the facade resource from within the @@ -555,40 +387,46 @@ class ResourceFacade(function.Function): 'Metadata', 'DeletionPolicy', 'UpdatePolicy' ) - def __init__(self, stack, fn_name, args): - super(ResourceFacade, self).__init__(stack, fn_name, args) - if self.args not in self._RESOURCE_ATTRIBUTES: - fmt_data = {'fn_name': self.fn_name, - 'allowed': ', '.join(self._RESOURCE_ATTRIBUTES)} - raise ValueError(_('Incorrect arguments to "%(fn_name)s" ' - 'should be one of: %(allowed)s') % fmt_data) - - def result(self): - attr = function.resolve(self.args) - - if attr == self.METADATA: - return self.stack.parent_resource.metadata_get() - elif attr == self.UPDATE_POLICY: - up = self.stack.parent_resource.t._update_policy or {} - return function.resolve(up) - elif attr == self.DELETION_POLICY: - return self.stack.parent_resource.t.deletion_policy() - - -class Not(function.Function): - """A function acts as a NOT operator. +class If(hot_funcs.If): + """A function to return corresponding value based on condition evaluation. Takes the form:: - { "Fn::Not" : [condition] } + { "Fn::If" : [ "", + "", + "" ] } + + The value_if_true to be returned if the specified condition evaluates + to true, the value_if_false to be returned if the specified condition + evaluates to false. + """ + + +class Equals(hot_funcs.Equals): + """A function for comparing whether two values are equal. + + Takes the form:: + + { "Fn::Equals" : [ "", "" ] } + + The value can be any type that you want to compare. Returns true + if the two values are equal or false if they aren't. + """ + + +class Not(hot_funcs.Not): + """A function that acts as a NOT operator on a condition. + + Takes the form:: + + { "Fn::Not" : [ "" ] } Returns true for a condition that evaluates to false or returns false for a condition that evaluates to true. """ - def __init__(self, stack, fn_name, args): - super(Not, self).__init__(stack, fn_name, args) + def _get_condition(self): try: if (not self.args or not isinstance(self.args, collections.Sequence) or @@ -596,7 +434,7 @@ class Not(function.Function): raise ValueError() if len(self.args) != 1: raise ValueError() - self.condition = self.args[0] + return self.args[0] except ValueError: msg = _('Arguments to "%s" must be of the form: ' '[condition]') @@ -609,3 +447,29 @@ class Not(function.Function): 'after resolved the value is: %s') raise ValueError(msg % resolved_value) return not resolved_value + + +class And(hot_funcs.And): + """A function that acts as an AND operator on conditions. + + Takes the form:: + + { "Fn::And" : [ "", "", ... ] } + + Returns true if all the specified conditions evaluate to true, or returns + false if any one of the conditions evaluates to false. The minimum number + of conditions that you can include is 2. + """ + + +class Or(hot_funcs.Or): + """A function that acts as an OR operator on conditions. + + Takes the form:: + + { "Fn::Or" : [ "", "", ... ] } + + Returns true if any one of the specified conditions evaluate to true, + or returns false if all of the conditions evaluates to false. The minimum + number of conditions that you can include is 2. + """ diff --git a/heat/engine/cfn/template.py b/heat/engine/cfn/template.py index e7f3b65eb4..5993347ee7 100644 --- a/heat/engine/cfn/template.py +++ b/heat/engine/cfn/template.py @@ -17,7 +17,6 @@ from heat.common import exception from heat.common.i18n import _ from heat.engine.cfn import functions as cfn_funcs from heat.engine import function -from heat.engine.hot import functions as hot_funcs from heat.engine import parameters from heat.engine import rsrc_defn from heat.engine import template_common @@ -212,16 +211,16 @@ class CfnTemplate(CfnTemplateBase): 'Fn::Base64': cfn_funcs.Base64, 'Fn::MemberListToMap': cfn_funcs.MemberListToMap, 'Fn::ResourceFacade': cfn_funcs.ResourceFacade, - 'Fn::If': hot_funcs.If, + 'Fn::If': cfn_funcs.If, } condition_functions = { - 'Fn::Equals': hot_funcs.Equals, + 'Fn::Equals': cfn_funcs.Equals, 'Ref': cfn_funcs.ParamRef, 'Fn::FindInMap': cfn_funcs.FindInMap, 'Fn::Not': cfn_funcs.Not, - 'Fn::And': hot_funcs.And, - 'Fn::Or': hot_funcs.Or + 'Fn::And': cfn_funcs.And, + 'Fn::Or': cfn_funcs.Or } def __init__(self, tmpl, template_id=None, files=None, env=None): diff --git a/heat/engine/hot/functions.py b/heat/engine/hot/functions.py index a24f4a81dd..08801ae36f 100644 --- a/heat/engine/hot/functions.py +++ b/heat/engine/hot/functions.py @@ -24,7 +24,6 @@ from yaql.language import exceptions from heat.common import exception from heat.common.i18n import _ from heat.engine import attributes -from heat.engine.cfn import functions as cfn_funcs from heat.engine import function opts = [ @@ -113,7 +112,32 @@ class GetParam(function.Function): return '' -class GetAttThenSelect(cfn_funcs.GetAtt): +class GetResource(function.Function): + """A function for resolving resource references. + + Takes the form:: + + get_resource: + """ + + def _resource(self, path='unknown'): + resource_name = function.resolve(self.args) + + try: + return self.stack[resource_name] + except KeyError: + raise exception.InvalidTemplateReference(resource=resource_name, + key=path) + + def dependencies(self, path): + return itertools.chain(super(GetResource, self).dependencies(path), + [self._resource(path)]) + + def result(self): + return self._resource().FnGetRefId() + + +class GetAttThenSelect(function.Function): """A function for resolving resource attributes. Takes the form:: @@ -125,6 +149,13 @@ class GetAttThenSelect(cfn_funcs.GetAtt): - ... """ + def __init__(self, stack, fn_name, args): + super(GetAttThenSelect, self).__init__(stack, fn_name, args) + + (self._resource_name, + self._attribute, + self._path_components) = self._parse_args() + def _parse_args(self): if (not isinstance(self.args, collections.Sequence) or isinstance(self.args, six.string_types)): @@ -136,12 +167,65 @@ class GetAttThenSelect(cfn_funcs.GetAtt): '[resource_name, attribute, (path), ...]') % self.fn_name) - self._path_components = self.args[2:] + return self.args[0], self.args[1], self.args[2:] - return tuple(self.args[:2]) + def _resource(self, path='unknown'): + resource_name = function.resolve(self._resource_name) + + try: + return self.stack[resource_name] + except KeyError: + raise exception.InvalidTemplateReference(resource=resource_name, + key=path) + + def dep_attrs(self, resource_name): + if self._resource().name == resource_name: + attrs = [function.resolve(self._attribute)] + else: + attrs = [] + return itertools.chain(super(GetAttThenSelect, + self).dep_attrs(resource_name), + attrs) + + def dependencies(self, path): + return itertools.chain(super(GetAttThenSelect, + self).dependencies(path), + [self._resource(path)]) + + def _allow_without_attribute_name(self): + return False + + def validate(self): + super(GetAttThenSelect, self).validate() + res = self._resource() + + if self._allow_without_attribute_name(): + # if allow without attribute_name, then don't check + # when attribute_name is None + if self._attribute is None: + return + + attr = function.resolve(self._attribute) + from heat.engine import resource + if (type(res).get_attribute == resource.Resource.get_attribute and + attr not in res.attributes_schema): + raise exception.InvalidTemplateAttribute( + resource=self._resource_name, key=attr) def result(self): - attribute = super(GetAttThenSelect, self).result() + attr_name = function.resolve(self._attribute) + + r = self._resource() + if r.action in (r.CREATE, r.ADOPT, r.SUSPEND, r.RESUME, + r.UPDATE, r.ROLLBACK, r.SNAPSHOT, r.CHECK): + attribute = r.FnGetAtt(attr_name) + # NOTE(sirushtim): Add r.INIT to states above once convergence + # is the default. + elif r.stack.has_cache_data(r.name) and r.action == r.INIT: + attribute = r.FnGetAtt(attr_name) + else: + attribute = None + if attribute is None: return None @@ -213,7 +297,7 @@ class GetAttAllAttributes(GetAtt): if len(self.args) > 1: return super(GetAttAllAttributes, self)._parse_args() else: - return self.args[0], None + return self.args[0], None, [] else: raise TypeError(_('Argument to "%s" must be a list') % self.fn_name) @@ -246,7 +330,7 @@ class GetAttAllAttributes(GetAtt): return True -class Replace(cfn_funcs.Replace): +class Replace(function.Function): """A function for performing string substitutions. Takes the form:: @@ -267,6 +351,15 @@ class Replace(cfn_funcs.Replace): performed is otherwise undefined. """ + def __init__(self, stack, fn_name, args): + super(Replace, self).__init__(stack, fn_name, args) + + self._mapping, self._string = self._parse_args() + if not isinstance(self._mapping, + (collections.Mapping, function.Function)): + raise TypeError(_('"%s" parameters must be a mapping') % + self.fn_name) + def _parse_args(self): if not isinstance(self.args, collections.Mapping): raise TypeError(_('Arguments to "%s" must be a map') % @@ -286,6 +379,39 @@ class Replace(cfn_funcs.Replace): else: return mapping, string + def result(self): + template = function.resolve(self._string) + mapping = function.resolve(self._mapping) + + if not isinstance(template, six.string_types): + raise TypeError(_('"%s" template must be a string') % self.fn_name) + + if not isinstance(mapping, collections.Mapping): + raise TypeError(_('"%s" params must be a map') % self.fn_name) + + def replace(string, change): + placeholder, value = change + + if not isinstance(placeholder, six.string_types): + raise TypeError(_('"%s" param placeholders must be strings') % + self.fn_name) + + if value is None: + value = '' + + if not isinstance(value, + (six.string_types, six.integer_types, + float, bool)): + raise TypeError(_('"%s" params must be strings or numbers') % + self.fn_name) + + return string.replace(placeholder, six.text_type(value)) + + mapping = collections.OrderedDict(sorted(mapping.items(), + key=lambda t: len(t[0]), + reverse=True)) + return six.moves.reduce(replace, six.iteritems(mapping), template) + class ReplaceJson(Replace): """A function for performing string substitutions. @@ -387,25 +513,75 @@ class GetFile(function.Function): return f -class Join(cfn_funcs.Join): +class Join(function.Function): """A function for joining strings. Takes the form:: - { "list_join" : [ "", [ "", "", ... ] ] } + list_join: + - + - - + - + - ... And resolves to:: "..." """ + def __init__(self, stack, fn_name, args): + super(Join, self).__init__(stack, fn_name, args) + + example = '"%s" : [ " ", [ "str1", "str2"]]' % self.fn_name + fmt_data = {'fn_name': self.fn_name, + 'example': example} + + if not isinstance(self.args, list): + raise TypeError(_('Incorrect arguments to "%(fn_name)s" ' + 'should be: %(example)s') % fmt_data) + + try: + self._delim, self._strings = self.args + except ValueError: + raise ValueError(_('Incorrect arguments to "%(fn_name)s" ' + 'should be: %(example)s') % fmt_data) + + def result(self): + strings = function.resolve(self._strings) + if strings is None: + strings = [] + if (isinstance(strings, six.string_types) or + not isinstance(strings, collections.Sequence)): + raise TypeError(_('"%s" must operate on a list') % self.fn_name) + + delim = function.resolve(self._delim) + if not isinstance(delim, six.string_types): + raise TypeError(_('"%s" delimiter must be a string') % + self.fn_name) + + def ensure_string(s): + if s is None: + return '' + if not isinstance(s, six.string_types): + raise TypeError( + _('Items to join must be strings not %s' + ) % (repr(s)[:200])) + return s + + return delim.join(ensure_string(s) for s in strings) + class JoinMultiple(function.Function): """A function for joining one or more lists of strings. Takes the form:: - { "list_join" : [ "", [ "", "", ... ] ] } + list_join: + - + - - + - + - ... + - - ... And resolves to:: @@ -476,11 +652,14 @@ class MapMerge(function.Function): Takes the form:: - { "map_merge" : [{'k1': 'v1', 'k2': 'v2'}, {'k1': 'v2'}] } + map_merge: + - : + : + - : And resolves to:: - {'k1': 'v2', 'k2': 'v2'} + {"": "", "": ""} """ @@ -517,13 +696,17 @@ class MapReplace(function.Function): Takes the form:: - {"map_replace" : [{'k1': 'v1', 'k2': 'v2'}, - {'keys': {'k1': 'K1'}, - 'values': {'v2': 'V2'}}]} + map_replace: + - : + : + - keys: + : + values: + : And resolves to:: - {'K1': 'v1', 'k2': 'V2'} + {"": "", "": ""} """ @@ -588,7 +771,7 @@ class MapReplace(function.Function): return ret_map -class ResourceFacade(cfn_funcs.ResourceFacade): +class ResourceFacade(function.Function): """A function for retrieving data in a parent provider template. A function for obtaining data from the facade resource from within the @@ -608,6 +791,26 @@ class ResourceFacade(cfn_funcs.ResourceFacade): 'metadata', 'deletion_policy', 'update_policy' ) + def __init__(self, stack, fn_name, args): + super(ResourceFacade, self).__init__(stack, fn_name, args) + + if self.args not in self._RESOURCE_ATTRIBUTES: + fmt_data = {'fn_name': self.fn_name, + 'allowed': ', '.join(self._RESOURCE_ATTRIBUTES)} + raise ValueError(_('Incorrect arguments to "%(fn_name)s" ' + 'should be one of: %(allowed)s') % fmt_data) + + def result(self): + attr = function.resolve(self.args) + + if attr == self.METADATA: + return self.stack.parent_resource.metadata_get() + elif attr == self.UPDATE_POLICY: + up = self.stack.parent_resource.t._update_policy or {} + return function.resolve(up) + elif attr == self.DELETION_POLICY: + return self.stack.parent_resource.t.deletion_policy() + class Removed(function.Function): """This function existed in previous versions of HOT, but has been removed. @@ -767,14 +970,11 @@ class StrSplit(function.Function): Takes the form:: - str_split: [delimiter, string, ] - - or:: - str_split: - - delimiter - - string + - + - - + If is specified, the specified list item will be returned otherwise, the whole list is returned, similar to get_attr with path based attributes accessing lists. @@ -901,7 +1101,9 @@ class Equals(function.Function): Takes the form:: - { "equals" : ["value_1", "value_2"] } + equals: + - + - The value can be any type that you want to compare. Returns true if the two values are equal or false if they aren't. @@ -931,7 +1133,10 @@ class If(function.Macro): Takes the form:: - { "if" : [condition_name, value_if_true, value_if_false] } + if: + - + - + - The value_if_true to be returned if the specified condition evaluates to true, the value_if_false to be returned if the specified condition @@ -958,11 +1163,11 @@ class If(function.Macro): class Not(function.Function): - """A function acts as a NOT operator. + """A function that acts as a NOT operator on a condition. Takes the form:: - { "not" : condition } + not: Returns true for a condition that evaluates to false or returns false for a condition that evaluates to true. @@ -970,10 +1175,13 @@ class Not(function.Function): def __init__(self, stack, fn_name, args): super(Not, self).__init__(stack, fn_name, args) + self.condition = self._get_condition() + + def _get_condition(self): try: if not self.args: raise ValueError() - self.condition = self.args + return self.args except ValueError: msg = _('Arguments to "%s" must be of the form: ' 'condition') @@ -989,11 +1197,14 @@ class Not(function.Function): class And(function.Function): - """A function acts as an AND operator. + """A function that acts as an AND operator on conditions. Takes the form:: - { "and" : [{condition_1}, {condition_2}, {...}, {condition_n}] } + and: + - + - + - ... Returns true if all the specified conditions evaluate to true, or returns false if any one of the conditions evaluates to false. The minimum number @@ -1025,11 +1236,14 @@ class And(function.Function): class Or(function.Function): - """A function acts as an OR operator to evaluate all the conditions. + """A function that acts as an OR operator on conditions. Takes the form:: - { "or" : [{condition_1}, {condition_2}, {...}, {condition_n}] } + or: + - + - + - ... Returns true if any one of the specified conditions evaluate to true, or returns false if all of the conditions evaluates to false. The minimum diff --git a/heat/engine/hot/template.py b/heat/engine/hot/template.py index 7cd5221c20..2aa608e700 100644 --- a/heat/engine/hot/template.py +++ b/heat/engine/hot/template.py @@ -73,7 +73,7 @@ class HOTemplate20130523(template_common.CommonTemplate): functions = { 'Fn::GetAZs': cfn_funcs.GetAZs, 'get_param': hot_funcs.GetParam, - 'get_resource': cfn_funcs.ResourceRef, + 'get_resource': hot_funcs.GetResource, 'Ref': cfn_funcs.Ref, 'get_attr': hot_funcs.GetAttThenSelect, 'Fn::Select': cfn_funcs.Select, @@ -302,7 +302,7 @@ class HOTemplate20141016(HOTemplate20130523): 'get_attr': hot_funcs.GetAtt, 'get_file': hot_funcs.GetFile, 'get_param': hot_funcs.GetParam, - 'get_resource': cfn_funcs.ResourceRef, + 'get_resource': hot_funcs.GetResource, 'list_join': hot_funcs.Join, 'resource_facade': hot_funcs.ResourceFacade, 'str_replace': hot_funcs.Replace, @@ -326,7 +326,7 @@ class HOTemplate20150430(HOTemplate20141016): 'get_attr': hot_funcs.GetAtt, 'get_file': hot_funcs.GetFile, 'get_param': hot_funcs.GetParam, - 'get_resource': cfn_funcs.ResourceRef, + 'get_resource': hot_funcs.GetResource, 'list_join': hot_funcs.Join, 'repeat': hot_funcs.Repeat, 'resource_facade': hot_funcs.ResourceFacade, @@ -354,7 +354,7 @@ class HOTemplate20151015(HOTemplate20150430): 'get_attr': hot_funcs.GetAttAllAttributes, 'get_file': hot_funcs.GetFile, 'get_param': hot_funcs.GetParam, - 'get_resource': cfn_funcs.ResourceRef, + 'get_resource': hot_funcs.GetResource, 'list_join': hot_funcs.JoinMultiple, 'repeat': hot_funcs.Repeat, 'resource_facade': hot_funcs.ResourceFacade, @@ -386,7 +386,7 @@ class HOTemplate20160408(HOTemplate20151015): 'get_attr': hot_funcs.GetAttAllAttributes, 'get_file': hot_funcs.GetFile, 'get_param': hot_funcs.GetParam, - 'get_resource': cfn_funcs.ResourceRef, + 'get_resource': hot_funcs.GetResource, 'list_join': hot_funcs.JoinMultiple, 'repeat': hot_funcs.Repeat, 'resource_facade': hot_funcs.ResourceFacade, @@ -459,7 +459,7 @@ class HOTemplate20161014(HOTemplate20160408): 'get_attr': hot_funcs.GetAttAllAttributes, 'get_file': hot_funcs.GetFile, 'get_param': hot_funcs.GetParam, - 'get_resource': cfn_funcs.ResourceRef, + 'get_resource': hot_funcs.GetResource, 'list_join': hot_funcs.JoinMultiple, 'repeat': hot_funcs.RepeatWithMap, 'resource_facade': hot_funcs.ResourceFacade, diff --git a/heat/engine/translation.py b/heat/engine/translation.py index 8e777c063d..0cf5faf65e 100644 --- a/heat/engine/translation.py +++ b/heat/engine/translation.py @@ -276,7 +276,7 @@ class TranslationRule(object): def _exec_resolve(self, translation_key, translation_data): def resolve_and_find(translation_value): - if isinstance(translation_value, cfn_funcs.ResourceRef): + if isinstance(translation_value, hot_funcs.GetResource): return if isinstance(translation_value, function.Function): translation_value = function.resolve(translation_value) diff --git a/heat/tests/openstack/neutron/test_neutron_floating_ip.py b/heat/tests/openstack/neutron/test_neutron_floating_ip.py index 8d63e1e1ce..1f53e1cfc8 100644 --- a/heat/tests/openstack/neutron/test_neutron_floating_ip.py +++ b/heat/tests/openstack/neutron/test_neutron_floating_ip.py @@ -22,8 +22,8 @@ from neutronclient.v2_0 import client as neutronclient from heat.common import exception from heat.common import template_format from heat.common import timeutils -from heat.engine.cfn import functions as cfn_funcs from heat.engine.clients.os import neutron +from heat.engine.hot import functions as hot_funcs from heat.engine import rsrc_defn from heat.engine import scheduler from heat.engine import stack as parser @@ -498,7 +498,7 @@ class NeutronFloatingIPTest(common.HeatTestCase): t = template_format.parse(neutron_floating_no_assoc_template) stack = utils.parse_stack(t) - p_result = self.patchobject(cfn_funcs.ResourceRef, 'result') + p_result = self.patchobject(hot_funcs.GetResource, 'result') p_result.return_value = 'subnet_uuid' # check dependencies for fip resource required_by = set(stack.dependencies.required_by( @@ -515,7 +515,7 @@ class NeutronFloatingIPTest(common.HeatTestCase): p_show = self.patchobject(neutronclient.Client, 'show_network') p_show.return_value = {'network': {'subnets': ['subnet_uuid']}} - p_result = self.patchobject(cfn_funcs.ResourceRef, 'result', + p_result = self.patchobject(hot_funcs.GetResource, 'result', autospec=True) def return_uuid(self): diff --git a/heat/tests/openstack/neutron/test_neutron_subnet.py b/heat/tests/openstack/neutron/test_neutron_subnet.py index d0d89d44ac..5275a090f6 100644 --- a/heat/tests/openstack/neutron/test_neutron_subnet.py +++ b/heat/tests/openstack/neutron/test_neutron_subnet.py @@ -20,8 +20,8 @@ import six from heat.common import exception from heat.common import template_format -from heat.engine.cfn import functions as cfn_funcs from heat.engine.clients.os import neutron +from heat.engine.hot import functions as hot_funcs from heat.engine.resources.openstack.neutron import subnet from heat.engine import rsrc_defn from heat.engine import scheduler @@ -710,6 +710,6 @@ class NeutronSubnetTest(common.HeatTestCase): rsrc = stack['subnet'] stack.create() - self.assertEqual(cfn_funcs.ResourceRef(stack, 'get_resource', 'net'), + self.assertEqual(hot_funcs.GetResource(stack, 'get_resource', 'net'), rsrc.properties.get('network')) self.assertIsNone(rsrc.properties.get('network_id')) diff --git a/heat/tests/test_properties.py b/heat/tests/test_properties.py index 2276da5238..09c8c39faa 100644 --- a/heat/tests/test_properties.py +++ b/heat/tests/test_properties.py @@ -15,8 +15,8 @@ from oslo_serialization import jsonutils import six from heat.common import exception -from heat.engine.cfn import functions as cfn_funcs from heat.engine import constraints +from heat.engine.hot import functions as hot_funcs from heat.engine.hot import parameters as hot_param from heat.engine import parameters from heat.engine import plugin_manager @@ -1235,7 +1235,7 @@ class PropertiesTest(common.HeatTestCase): # define properties with function and constraint props = properties.Properties( schema, - {'foo': cfn_funcs.ResourceRef( + {'foo': hot_funcs.GetResource( stack, 'get_resource', 'another_res')}, test_resolver) diff --git a/heat/tests/test_translation_rule.py b/heat/tests/test_translation_rule.py index 8f2a063503..0b070b6638 100644 --- a/heat/tests/test_translation_rule.py +++ b/heat/tests/test_translation_rule.py @@ -530,7 +530,7 @@ class TestTranslationRule(common.HeatTestCase): pass stack = DummyStack(another_res=rsrc()) - ref = cfn_funcs.ResourceRef(stack, 'get_resource', + ref = hot_funcs.GetResource(stack, 'get_resource', 'another_res') data = { 'far': [{'red': ref}], @@ -608,7 +608,7 @@ class TestTranslationRule(common.HeatTestCase): pass stack = DummyStack(another_res=rsrc()) - ref = cfn_funcs.ResourceRef(stack, 'get_resource', + ref = hot_funcs.GetResource(stack, 'get_resource', 'another_res') data = {'far': ref} props = properties.Properties(schema, data)