summaryrefslogtreecommitdiffstats
path: root/tosca2heat/tosca-parser/toscaparser/functions.py
diff options
context:
space:
mode:
authorshangxdy <shang.xiaodong@zte.com.cn>2016-07-08 15:15:00 +0800
committershangxdy <shang.xiaodong@zte.com.cn>2016-07-10 00:38:59 +0800
commit0997552722dc4845a854e0e6f8d7f18058e26380 (patch)
treeb90d1e808bb326612211ba56b3b941516493398d /tosca2heat/tosca-parser/toscaparser/functions.py
parent7fe3011a67a239f7dc04153c54eaff78ef967eaf (diff)
Synchronise the openstack bugs
When run unittests through tox, some test cases are always error, the errors are already done in openstack community, so it's necessary to synchronise the fixes. Change-Id: Ib29078e6cc138a474e89c6a2cc90ad7a1db1bb46 JIRA: PARSER-63 Signed-off-by: shangxdy <shang.xiaodong@zte.com.cn>
Diffstat (limited to 'tosca2heat/tosca-parser/toscaparser/functions.py')
-rw-r--r--tosca2heat/tosca-parser/toscaparser/functions.py211
1 files changed, 172 insertions, 39 deletions
diff --git a/tosca2heat/tosca-parser/toscaparser/functions.py b/tosca2heat/tosca-parser/toscaparser/functions.py
index 011efde..1b64416 100644
--- a/tosca2heat/tosca-parser/toscaparser/functions.py
+++ b/tosca2heat/tosca-parser/toscaparser/functions.py
@@ -18,6 +18,8 @@ import six
from toscaparser.common.exception import ExceptionCollector
from toscaparser.common.exception import UnknownInputError
from toscaparser.dataentity import DataEntity
+from toscaparser.elements.constraints import Schema
+from toscaparser.elements.datatype import DataType
from toscaparser.elements.entity_type import EntityType
from toscaparser.elements.relationshiptype import RelationshipType
from toscaparser.utils.gettextutils import _
@@ -27,6 +29,7 @@ GET_PROPERTY = 'get_property'
GET_ATTRIBUTE = 'get_attribute'
GET_INPUT = 'get_input'
CONCAT = 'concat'
+TOKEN = 'token'
SELF = 'SELF'
HOST = 'HOST'
@@ -125,30 +128,67 @@ class GetAttribute(Function):
* { get_attribute: [ server, private_address ] }
* { get_attribute: [ HOST, private_address ] }
* { get_attribute: [ HOST, private_address, 0 ] }
+ * { get_attribute: [ HOST, private_address, 0, some_prop] }
"""
def validate(self):
- if len(self.args) != 2 and len(self.args) != 3:
+ if len(self.args) < 2:
ExceptionCollector.appendException(
ValueError(_('Illegal arguments for function "{0}". Expected '
- 'arguments: "node-template-name", '
- '"attribute-name"').format(GET_ATTRIBUTE)))
- node_tpl = self._find_node_template_containing_attribute()
- if len(self.args) > 2:
- # Currently we only check the first level
- attrs_def = node_tpl.type_definition.get_attributes_def()
- attr_def = attrs_def[self.attribute_name]
- if attr_def.schema['type'] == "list":
- if not isinstance(self.args[2], int):
- ExceptionCollector.appendException(
- ValueError(_('Illegal arguments for function "{0}". '
- 'Third argument must be a positive'
- ' integer') .format(GET_ATTRIBUTE)))
- elif attr_def.schema['type'] != "map":
- ExceptionCollector.appendException(
- ValueError(_('Illegal arguments for function "{0}". '
- 'Expected arguments: "node-template-name", '
- '"attribute-name"').format(GET_ATTRIBUTE)))
+ 'arguments: "node-template-name", "req-or-cap"'
+ '(optional), "property name"'
+ ).format(GET_ATTRIBUTE)))
+ return
+ elif len(self.args) == 2:
+ self._find_node_template_containing_attribute()
+ else:
+ node_tpl = self._find_node_template(self.args[0])
+ index = 2
+ attrs = node_tpl.type_definition.get_attributes_def()
+ found = [attrs[self.args[1]]] if self.args[1] in attrs else []
+ if found:
+ attr = found[0]
+ else:
+ index = 3
+ # then check the req or caps
+ attr = self._find_req_or_cap_attribute(self.args[1],
+ self.args[2])
+
+ value_type = attr.schema['type']
+ if len(self.args) > index:
+ for elem in self.args[index:]:
+ if value_type == "list":
+ if not isinstance(elem, int):
+ ExceptionCollector.appendException(
+ ValueError(_('Illegal arguments for function'
+ ' "{0}". "{1}" Expected positive'
+ ' integer argument'
+ ).format(GET_ATTRIBUTE, elem)))
+ value_type = attr.schema['entry_schema']['type']
+ elif value_type == "map":
+ value_type = attr.schema['entry_schema']['type']
+ elif value_type in Schema.PROPERTY_TYPES:
+ ExceptionCollector.appendException(
+ ValueError(_('Illegal arguments for function'
+ ' "{0}". Unexpected attribute/'
+ 'index value "{1}"'
+ ).format(GET_ATTRIBUTE, elem)))
+ return
+ else: # It is a complex type
+ data_type = DataType(value_type)
+ props = data_type.get_all_properties()
+ found = [props[elem]] if elem in props else []
+ if found:
+ prop = found[0]
+ value_type = prop.schema['type']
+ else:
+ ExceptionCollector.appendException(
+ KeyError(_('Illegal arguments for function'
+ ' "{0}". Attribute name "{1}" not'
+ ' found in "{2}"'
+ ).format(GET_ATTRIBUTE,
+ elem,
+ value_type)))
def result(self):
return self
@@ -163,25 +203,7 @@ class GetAttribute(Function):
return self._find_node_template_containing_attribute()
def _find_node_template_containing_attribute(self):
- if self.node_template_name == HOST:
- # Currently this is the only way to tell whether the function
- # is used within the outputs section of the TOSCA template.
- if isinstance(self.context, list):
- ExceptionCollector.appendException(
- ValueError(_(
- '"get_attribute: [ HOST, ... ]" is not allowed in '
- '"outputs" section of the TOSCA template.')))
- return
- node_tpl = self._find_host_containing_attribute()
- if not node_tpl:
- ExceptionCollector.appendException(
- ValueError(_(
- '"get_attribute: [ HOST, ... ]" was used in node '
- 'template "{0}" but "{1}" was not found in '
- 'the relationship chain.').format(self.context.name,
- HOSTED_ON)))
- else:
- node_tpl = self._find_node_template(self.args[0])
+ node_tpl = self._find_node_template(self.args[0])
if node_tpl and \
not self._attribute_exists_in_type(node_tpl.type_definition):
ExceptionCollector.appendException(
@@ -214,6 +236,25 @@ class GetAttribute(Function):
target_name)
def _find_node_template(self, node_template_name):
+ if node_template_name == HOST:
+ # Currently this is the only way to tell whether the function
+ # is used within the outputs section of the TOSCA template.
+ if isinstance(self.context, list):
+ ExceptionCollector.appendException(
+ ValueError(_(
+ '"get_attribute: [ HOST, ... ]" is not allowed in '
+ '"outputs" section of the TOSCA template.')))
+ return
+ node_tpl = self._find_host_containing_attribute()
+ if not node_tpl:
+ ExceptionCollector.appendException(
+ ValueError(_(
+ '"get_attribute: [ HOST, ... ]" was used in node '
+ 'template "{0}" but "{1}" was not found in '
+ 'the relationship chain.').format(self.context.name,
+ HOSTED_ON)))
+ return
+ return node_tpl
if node_template_name == TARGET:
if not isinstance(self.context.type_definition, RelationshipType):
ExceptionCollector.appendException(
@@ -240,6 +281,51 @@ class GetAttribute(Function):
'Node template "{0}" was not found.'
).format(node_template_name)))
+ def _find_req_or_cap_attribute(self, req_or_cap, attr_name):
+ node_tpl = self._find_node_template(self.args[0])
+ # Find attribute in node template's requirements
+ for r in node_tpl.requirements:
+ for req, node_name in r.items():
+ if req == req_or_cap:
+ node_template = self._find_node_template(node_name)
+ return self._get_capability_attribute(
+ node_template,
+ req,
+ attr_name)
+ # If requirement was not found, look in node template's capabilities
+ return self._get_capability_attribute(node_tpl,
+ req_or_cap,
+ attr_name)
+
+ def _get_capability_attribute(self,
+ node_template,
+ capability_name,
+ attr_name):
+ """Gets a node template capability attribute."""
+ caps = node_template.get_capabilities()
+ if caps and capability_name in caps.keys():
+ cap = caps[capability_name]
+ attribute = None
+ attrs = cap.definition.get_attributes_def()
+ if attrs and attr_name in attrs.keys():
+ attribute = attrs[attr_name]
+ if not attribute:
+ ExceptionCollector.appendException(
+ KeyError(_('Attribute "%(attr)s" was not found in '
+ 'capability "%(cap)s" of node template '
+ '"%(ntpl1)s" referenced from node template '
+ '"%(ntpl2)s".') % {'attr': attr_name,
+ 'cap': capability_name,
+ 'ntpl1': node_template.name,
+ 'ntpl2': self.context.name}))
+ return attribute
+ msg = _('Requirement/Capability "{0}" referenced from node template '
+ '"{1}" was not found in node template "{2}".').format(
+ capability_name,
+ self.context.name,
+ node_template.name)
+ ExceptionCollector.appendException(KeyError(msg))
+
@property
def node_template_name(self):
return self.args[0]
@@ -551,11 +637,58 @@ class Concat(Function):
def result(self):
return self
+
+class Token(Function):
+ """Validate the function and provide an instance of the function
+
+ The token function is used within a TOSCA service template on a string to
+ parse out (tokenize) substrings separated by one or more token characters
+ within a larger string.
+
+
+ Arguments:
+
+ * The composite string that contains one or more substrings separated by
+ token characters.
+ * The string that contains one or more token characters that separate
+ substrings within the composite string.
+ * The integer indicates the index of the substring to return from the
+ composite string. Note that the first substring is denoted by using
+ the '0' (zero) integer value.
+
+ Example:
+
+ [ get_attribute: [ my_server, data_endpoint, ip_address ], ':', 1 ]
+
+ """
+
+ def validate(self):
+ if len(self.args) < 3:
+ ExceptionCollector.appendException(
+ ValueError(_('Invalid arguments for function "{0}". Expected '
+ 'at least three arguments.').format(TOKEN)))
+ else:
+ if not isinstance(self.args[1], str) or len(self.args[1]) != 1:
+ ExceptionCollector.appendException(
+ ValueError(_('Invalid arguments for function "{0}". '
+ 'Expected single char value as second '
+ 'argument.').format(TOKEN)))
+
+ if not isinstance(self.args[2], int):
+ ExceptionCollector.appendException(
+ ValueError(_('Invalid arguments for function "{0}". '
+ 'Expected integer value as third '
+ 'argument.').format(TOKEN)))
+
+ def result(self):
+ return self
+
function_mappings = {
GET_PROPERTY: GetProperty,
GET_INPUT: GetInput,
GET_ATTRIBUTE: GetAttribute,
- CONCAT: Concat
+ CONCAT: Concat,
+ TOKEN: Token
}