diff options
Diffstat (limited to 'tosca2heat/tosca-parser')
76 files changed, 1888 insertions, 215 deletions
diff --git a/tosca2heat/tosca-parser/README.rst b/tosca2heat/tosca-parser/README.rst index d80d75b..0f94072 100644 --- a/tosca2heat/tosca-parser/README.rst +++ b/tosca2heat/tosca-parser/README.rst @@ -1,3 +1,12 @@ +======================== +Team and repository tags +======================== + +.. image:: http://governance.openstack.org/badges/tosca-parser.svg + :target: http://governance.openstack.org/reference/tags/index.html + +.. Change things from this point on + =============== TOSCA Parser =============== diff --git a/tosca2heat/tosca-parser/doc/source/conf.py b/tosca2heat/tosca-parser/doc/source/conf.py index e461246..d5d9189 100644 --- a/tosca2heat/tosca-parser/doc/source/conf.py +++ b/tosca2heat/tosca-parser/doc/source/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at diff --git a/tosca2heat/tosca-parser/doc/source/installation.rst b/tosca2heat/tosca-parser/doc/source/installation.rst index f3805a5..5476d41 100644 --- a/tosca2heat/tosca-parser/doc/source/installation.rst +++ b/tosca2heat/tosca-parser/doc/source/installation.rst @@ -2,8 +2,17 @@ Installation ============ -You can clone the project and use it as below:: +PyPI Installation +----------------- +Tosca-Parser can be installed via a PyPI package. Refer to https://pypi.python.org/pypi/tosca-parser for available packages. +The latest release can be simply installed by running the following command:: - git clone https://github.com/openstack/tosca-parser + sudo pip install tosca-parser + +Manual Installation +------------------- +You can manually install the latest code available at the TOSCA-Parser github repository by following these steps:: -Tosca-Parser can be installed via PyPI package as well. Refer to https://pypi.python.org/pypi/tosca-parser for available packages.
\ No newline at end of file + git clone https://github.com/openstack/tosca-parser + cd tosca-parser + sudo python setup.py install diff --git a/tosca2heat/tosca-parser/requirements.txt b/tosca2heat/tosca-parser/requirements.txt index b30cc51..45a19f0 100644 --- a/tosca2heat/tosca-parser/requirements.txt +++ b/tosca2heat/tosca-parser/requirements.txt @@ -1,10 +1,10 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.6 # Apache-2.0 +pbr>=1.8 # Apache-2.0 Babel>=2.3.4 # BSD -cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0 -PyYAML>=3.1.0 # MIT +cliff>=2.3.0 # Apache-2.0 +PyYAML>=3.10.0 # MIT python-dateutil>=2.4.2 # BSD six>=1.9.0 # MIT -requests>=2.10.0 # Apache-2.0 +requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0 diff --git a/tosca2heat/tosca-parser/setup.cfg b/tosca2heat/tosca-parser/setup.cfg index c109228..77e1b2e 100644 --- a/tosca2heat/tosca-parser/setup.cfg +++ b/tosca2heat/tosca-parser/setup.cfg @@ -1,11 +1,12 @@ [metadata] name = tosca-parser +url = https://launchpad.net/tosca-parser summary = Parser for TOSCA Simple Profile in YAML. description-file = README.rst author = OpenStack author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ +home-page = http://docs.openstack.org/developer/tosca-parser/ classifier = Environment :: OpenStack Intended Audience :: Information Technology diff --git a/tosca2heat/tosca-parser/test-requirements.txt b/tosca2heat/tosca-parser/test-requirements.txt index 1bb6623..d4b59c3 100644 --- a/tosca2heat/tosca-parser/test-requirements.txt +++ b/tosca2heat/tosca-parser/test-requirements.txt @@ -2,12 +2,12 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. hacking<0.11,>=0.10.0 -coverage>=3.6 # Apache-2.0 +coverage>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD oslotest>=1.10.0 # Apache-2.0 -oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 +oslosphinx>=4.7.0 # Apache-2.0 python-subunit>=0.0.18 # Apache-2.0/BSD -sphinx!=1.3b1,<1.3,>=1.2.1 # BSD +sphinx>=1.5.1 # BSD testrepository>=0.0.18 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=1.4.0 # MIT diff --git a/tosca2heat/tosca-parser/tools/tox_install.sh b/tosca2heat/tosca-parser/tools/tox_install.sh new file mode 100644 index 0000000..e61b63a --- /dev/null +++ b/tosca2heat/tosca-parser/tools/tox_install.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# Client constraint file contains this client version pin that is in conflict +# with installing the client from source. We should remove the version pin in +# the constraints file before applying it for from-source installation. + +CONSTRAINTS_FILE="$1" +shift 1 + +set -e + +# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get +# published to logs.openstack.org for easy debugging. +localfile="$VIRTUAL_ENV/log/upper-constraints.txt" + +if [[ "$CONSTRAINTS_FILE" != http* ]]; then + CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE" +fi +# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep +curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile" + +pip install -c"$localfile" openstack-requirements + +# This is the main purpose of the script: Allow local installation of +# the current repo. It is listed in constraints file and thus any +# install will be constrained and we need to unconstrain it. +edit-constraints "$localfile" -- "$CLIENT_NAME" + +pip install -c"$localfile" -U "$@" +exit $? diff --git a/tosca2heat/tosca-parser/toscaparser/__init__.py b/tosca2heat/tosca-parser/toscaparser/__init__.py index d6fa60c..d9745ed 100644 --- a/tosca2heat/tosca-parser/toscaparser/__init__.py +++ b/tosca2heat/tosca-parser/toscaparser/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at diff --git a/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml b/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml index 6f3b331..9f3369e 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml +++ b/tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml @@ -70,6 +70,8 @@ node_types: type: tosca.capabilities.OperatingSystem scalable: type: tosca.capabilities.Scalable + endpoint: + type: tosca.capabilities.Endpoint.Admin requirements: - local_storage: capability: tosca.capabilities.Attachment @@ -527,6 +529,7 @@ capability_types: network_name: type: string required: false + default: PRIVATE initiator: type: string required: false @@ -671,7 +674,7 @@ capability_types: publish_ports: type: list entry_schema: - type: PortSpec + type: tosca.datatypes.network.PortSpec required: false description: > List of ports mappings from source (Docker container) @@ -679,7 +682,7 @@ capability_types: expose_ports: type: list entry_schema: - type: PortSpec + type: tosca.datatypes.network.PortSpec required: false description: > List of ports mappings from source (Docker container) to expose @@ -799,7 +802,7 @@ data_types: constraints: - valid_values: [ udp, tcp, igmp ] target: - type: PortDef + type: tosca.datatypes.network.PortDef required: false target_range: type: range @@ -807,7 +810,7 @@ data_types: constraints: - in_range: [ 1, 65535 ] source: - type: PortDef + type: tosca.datatypes.network.PortDef required: false source_range: type: range diff --git a/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py b/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py index 865690e..54cd9fe 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py @@ -44,7 +44,7 @@ class CapabilityTypeDef(StatefulEntityType): for prop, schema in props.items(): # add parent property if not overridden by children type if not self.properties or \ - prop not in self.properties.keys(): + prop not in self.properties.keys(): properties.append(PropertyDef(prop, None, schema)) return properties diff --git a/tosca2heat/tosca-parser/toscaparser/elements/constraints.py b/tosca2heat/tosca-parser/toscaparser/elements/constraints.py index 8594b85..70863bc 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/constraints.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/constraints.py @@ -27,10 +27,10 @@ class Schema(collections.Mapping): KEYS = ( TYPE, REQUIRED, DESCRIPTION, - DEFAULT, CONSTRAINTS, ENTRYSCHEMA + DEFAULT, CONSTRAINTS, ENTRYSCHEMA, STATUS ) = ( 'type', 'required', 'description', - 'default', 'constraints', 'entry_schema' + 'default', 'constraints', 'entry_schema', 'status' ) PROPERTY_TYPES = ( @@ -86,6 +86,10 @@ class Schema(collections.Mapping): return self.schema.get(self.DEFAULT) @property + def status(self): + return self.schema.get(self.STATUS, '') + + @property def constraints(self): if not self.constraints_list: constraint_schemata = self.schema.get(self.CONSTRAINTS) diff --git a/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py b/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py index d7fcb18..9fd6c4d 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/entity_type.py @@ -93,7 +93,7 @@ class EntityType(object): return False def entity_value(self, defs, key): - if key in defs: + if defs and key in defs: return defs[key] def get_value(self, ndtype, defs=None, parent=None): @@ -102,7 +102,7 @@ class EntityType(object): if not hasattr(self, 'defs'): return None defs = self.defs - if ndtype in defs: + if defs and ndtype in defs: # copy the value to avoid that next operations add items in the # item definitions value = copy.copy(defs[ndtype]) @@ -110,7 +110,7 @@ class EntityType(object): p = self if p: while p: - if ndtype in p.defs: + if p.defs and ndtype in p.defs: # get the parent value parent_value = p.defs[ndtype] if value: @@ -159,7 +159,6 @@ class EntityType(object): def update_definitions(version): exttools = ExtTools() extension_defs_file = exttools.get_defs_file(version) - loader = toscaparser.utils.yamlparser.load_yaml nfv_def_file = loader(extension_defs_file) nfv_def = {} diff --git a/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py b/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py index 02c285a..4e58d64 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/grouptype.py @@ -87,7 +87,7 @@ class GroupType(StatefulEntityType): 'metadata' % (meta_data.get('type')))) for entry_schema, entry_schema_type in meta_data.items(): if isinstance(entry_schema_type, dict) and not \ - entry_schema_type.get('type') == 'string': + entry_schema_type.get('type') == 'string': ExceptionCollector.appendException( InvalidTypeError(what='"%s" defined in group for ' 'metadata "%s"' diff --git a/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py b/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py index 88fb8ab..47ec90a 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/interfaces.py @@ -22,6 +22,9 @@ SECTIONS = (LIFECYCLE, CONFIGURE, LIFECYCLE_SHORTNAME, INTERFACEVALUE = (IMPLEMENTATION, INPUTS) = ('implementation', 'inputs') +INTERFACE_DEF_RESERVED_WORDS = ['type', 'inputs', 'derived_from', 'version', + 'description'] + class InterfacesDef(StatefulEntityType): '''TOSCA built-in interfaces type.''' @@ -40,8 +43,16 @@ class InterfacesDef(StatefulEntityType): interfacetype = LIFECYCLE if interfacetype == CONFIGURE_SHORTNAME: interfacetype = CONFIGURE + if hasattr(self.ntype, 'interfaces') \ + and self.ntype.interfaces \ + and interfacetype in self.ntype.interfaces: + interfacetype = self.ntype.interfaces[interfacetype]['type'] if node_type: - self.defs = self.TOSCA_DEF[interfacetype] + if self.node_template and self.node_template.custom_def \ + and interfacetype in self.node_template.custom_def: + self.defs = self.node_template.custom_def[interfacetype] + else: + self.defs = self.TOSCA_DEF[interfacetype] if value: if isinstance(self.value, dict): for i, j in self.value.items(): diff --git a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py index f5e4eb0..7d68c0b 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/nodetype.py @@ -98,10 +98,6 @@ class NodeType(StatefulEntityType): provided capability. ''' - # All types,include normative and custom types, here will - # be substituted because the global moification of TOSCA_DEF - self.TOSCA_DEF.update(self.custom_def) - # Filter the node types node_types = [node_type for node_type in self.TOSCA_DEF.keys() if node_type.startswith(self.NODE_PREFIX) and @@ -141,8 +137,6 @@ class NodeType(StatefulEntityType): '''Return a list of capability objects.''' typecapabilities = [] caps = self.get_value(self.CAPABILITIES, None, True) - if caps is None: - caps = self.get_value(self.CAPABILITIES, None, True) if caps: # 'name' is symbolic name of the capability # 'value' is a dict { 'type': <capability type name> } diff --git a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py index 8fbb0f0..a922d26 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/policytype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/policytype.py @@ -20,9 +20,10 @@ from toscaparser.utils.validateutils import TOSCAVersionProperty class PolicyType(StatefulEntityType): '''TOSCA built-in policies type.''' - SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, TARGETS) = \ + SECTIONS = (DERIVED_FROM, METADATA, PROPERTIES, VERSION, DESCRIPTION, + TARGETS, TRIGGERS, TYPE) = \ ('derived_from', 'metadata', 'properties', 'version', - 'description', 'targets') + 'description', 'targets', 'triggers', 'type') def __init__(self, ptype, custom_def=None): super(PolicyType, self).__init__(ptype, self.POLICY_PREFIX, diff --git a/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py b/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py index d32e97e..0218305 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/portspectype.py @@ -58,7 +58,7 @@ class PortSpec(object): # verify one of the specified values is set if source is None and source_range is None and \ - target is None and target_range is None: + target is None and target_range is None: ExceptionCollector.appendException( InvalidTypeAdditionalRequirementsError( type=PortSpec.TYPE_URI)) diff --git a/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py b/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py index 25440ca..8eefbea 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py @@ -10,16 +10,25 @@ # License for the specific language governing permissions and limitations # under the License. +from toscaparser.common.exception import ExceptionCollector +from toscaparser.common.exception import UnknownFieldError from toscaparser.elements.statefulentitytype import StatefulEntityType class RelationshipType(StatefulEntityType): '''TOSCA built-in relationship type.''' + SECTIONS = (DERIVED_FROM, VALID_TARGET_TYPES, INTERFACES, + ATTRIBUTES, PROPERTIES, DESCRIPTION, VERSION, + CREDENTIAL) = ('derived_from', 'valid_target_types', + 'interfaces', 'attributes', 'properties', + 'description', 'version', 'credential') + def __init__(self, type, capability_name=None, custom_def=None): super(RelationshipType, self).__init__(type, self.RELATIONSHIP_PREFIX, custom_def) self.capability_name = capability_name self.custom_def = custom_def + self._validate_keys() @property def parent_type(self): @@ -31,3 +40,10 @@ class RelationshipType(StatefulEntityType): @property def valid_target_types(self): return self.entity_value(self.defs, 'valid_target_types') + + def _validate_keys(self): + for key in self.defs.keys(): + if key not in self.SECTIONS: + ExceptionCollector.appendException( + UnknownFieldError(what='Relationshiptype "%s"' % self.type, + field=key)) diff --git a/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py b/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py index be9933e..2f221b3 100644 --- a/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py +++ b/tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py @@ -35,6 +35,9 @@ class StatefulEntityType(EntityType): if UnsupportedType.validate_type(entire_entitytype): self.defs = None else: + if entitytype.startswith(self.TOSCA + ":"): + entitytype = entitytype[(len(self.TOSCA) + 1):] + entire_entitytype = prefix + entitytype if not entitytype.startswith(self.TOSCA): entire_entitytype = prefix + entitytype if entire_entitytype in list(self.TOSCA_DEF.keys()): diff --git a/tosca2heat/tosca-parser/toscaparser/entity_template.py b/tosca2heat/tosca-parser/toscaparser/entity_template.py index 7ce8cec..cc3d620 100644 --- a/tosca2heat/tosca-parser/toscaparser/entity_template.py +++ b/tosca2heat/tosca-parser/toscaparser/entity_template.py @@ -68,7 +68,6 @@ class EntityTemplate(object): ' a "type" ''attribute.') % dict(pname=name)) ExceptionCollector.appendException( ValidationError(msg)) - self.type_definition = PolicyType(type, custom_def) if entity_name == 'group_type': self.type_definition = GroupType(type, custom_def) \ diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0.yaml b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0_0.yaml index 365d70e..365d70e 100644 --- a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0.yaml +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0_0.yaml diff --git a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/nfv.py b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tosca_simple_profile_for_nfv_1_0_0.py index 0c7c2b9..24eabab 100644 --- a/tosca2heat/tosca-parser/toscaparser/extensions/nfv/nfv.py +++ b/tosca2heat/tosca-parser/toscaparser/extensions/nfv/tosca_simple_profile_for_nfv_1_0_0.py @@ -14,6 +14,6 @@ VERSION = 'tosca_simple_profile_for_nfv_1_0_0' -DEFS_FILE = "TOSCA_nfv_definition_1_0.yaml" +DEFS_FILE = "TOSCA_nfv_definition_1_0_0.yaml" SECTIONS = ('metadata') diff --git a/tosca2heat/tosca-parser/toscaparser/functions.py b/tosca2heat/tosca-parser/toscaparser/functions.py index 1b64416..d498229 100644 --- a/tosca2heat/tosca-parser/toscaparser/functions.py +++ b/tosca2heat/tosca-parser/toscaparser/functions.py @@ -14,6 +14,7 @@ import abc import six +import toscaparser.elements.interfaces from toscaparser.common.exception import ExceptionCollector from toscaparser.common.exception import UnknownInputError @@ -22,12 +23,14 @@ 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.elements.statefulentitytype import StatefulEntityType from toscaparser.utils.gettextutils import _ GET_PROPERTY = 'get_property' GET_ATTRIBUTE = 'get_attribute' GET_INPUT = 'get_input' +GET_OPERATION_OUTPUT = 'get_operation_output' CONCAT = 'concat' TOKEN = 'token' @@ -143,6 +146,8 @@ class GetAttribute(Function): self._find_node_template_containing_attribute() else: node_tpl = self._find_node_template(self.args[0]) + if node_tpl is None: + return index = 2 attrs = node_tpl.type_definition.get_attributes_def() found = [attrs[self.args[1]]] if self.args[1] in attrs else [] @@ -202,10 +207,13 @@ class GetAttribute(Function): """ return self._find_node_template_containing_attribute() + # Attributes can be explicitly created as part of the type definition + # or a property name can be implicitly used as an attribute name def _find_node_template_containing_attribute(self): node_tpl = self._find_node_template(self.args[0]) if node_tpl and \ - not self._attribute_exists_in_type(node_tpl.type_definition): + not self._attribute_exists_in_type(node_tpl.type_definition) \ + and self.attribute_name not in node_tpl.get_properties(): ExceptionCollector.appendException( KeyError(_('Attribute "%(att)s" was not found in node ' 'template "%(ntpl)s".') % @@ -229,7 +237,7 @@ class GetAttribute(Function): target_type = target_node.type_definition for capability in target_type.get_capabilities_objects(): if capability.type in \ - hosted_on_rel['valid_target_types']: + hosted_on_rel['valid_target_types']: if self._attribute_exists_in_type(target_type): return target_node return self._find_host_containing_attribute( @@ -609,6 +617,88 @@ class GetProperty(Function): return None +class GetOperationOutput(Function): + def validate(self): + if len(self.args) == 4: + self._find_node_template(self.args[0]) + interface_name = self._find_interface_name(self.args[1]) + self._find_operation_name(interface_name, self.args[2]) + else: + ExceptionCollector.appendException( + ValueError(_('Illegal arguments for function "{0}". Expected ' + 'arguments: "template_name","interface_name",' + '"operation_name","output_variable_name"' + ).format(GET_OPERATION_OUTPUT))) + return + + def _find_interface_name(self, interface_name): + if interface_name in toscaparser.elements.interfaces.SECTIONS: + return interface_name + else: + ExceptionCollector.appendException( + ValueError(_('Enter a valid interface name' + ).format(GET_OPERATION_OUTPUT))) + return + + def _find_operation_name(self, interface_name, operation_name): + if(interface_name == 'Configure' or + interface_name == 'tosca.interfaces.node.relationship.Configure'): + if(operation_name in + StatefulEntityType. + interfaces_relationship_configure_operations): + return operation_name + else: + ExceptionCollector.appendException( + ValueError(_('Enter an operation of Configure interface' + ).format(GET_OPERATION_OUTPUT))) + return + elif(interface_name == 'Standard' or + interface_name == 'tosca.interfaces.node.lifecycle.Standard'): + if(operation_name in + StatefulEntityType.interfaces_node_lifecycle_operations): + return operation_name + else: + ExceptionCollector.appendException( + ValueError(_('Enter an operation of Standard interface' + ).format(GET_OPERATION_OUTPUT))) + return + else: + ExceptionCollector.appendException( + ValueError(_('Enter a valid operation name' + ).format(GET_OPERATION_OUTPUT))) + return + + def _find_node_template(self, node_template_name): + if node_template_name == TARGET: + if not isinstance(self.context.type_definition, RelationshipType): + ExceptionCollector.appendException( + KeyError(_('"TARGET" keyword can only be used in context' + ' to "Relationships" target node'))) + return + return self.context.target + if node_template_name == SOURCE: + if not isinstance(self.context.type_definition, RelationshipType): + ExceptionCollector.appendException( + KeyError(_('"SOURCE" keyword can only be used in context' + ' to "Relationships" source node'))) + return + return self.context.source + name = self.context.name \ + if node_template_name == SELF and \ + not isinstance(self.context, list) \ + else node_template_name + for node_template in self.tosca_tpl.nodetemplates: + if node_template.name == name: + return node_template + ExceptionCollector.appendException( + KeyError(_( + 'Node template "{0}" was not found.' + ).format(node_template_name))) + + def result(self): + return self + + class Concat(Function): """Validate the function and provide an instance of the function @@ -687,6 +777,7 @@ function_mappings = { GET_PROPERTY: GetProperty, GET_INPUT: GetInput, GET_ATTRIBUTE: GetAttribute, + GET_OPERATION_OUTPUT: GetOperationOutput, CONCAT: Concat, TOKEN: Token } @@ -724,11 +815,12 @@ def get_function(tosca_tpl, node_template, raw_function): parsing was unsuccessful. """ if is_function(raw_function): - func_name = list(raw_function.keys())[0] - if func_name in function_mappings: - func = function_mappings[func_name] - func_args = list(raw_function.values())[0] - if not isinstance(func_args, list): - func_args = [func_args] - return func(tosca_tpl, node_template, func_name, func_args) + if isinstance(raw_function, dict): + func_name = list(raw_function.keys())[0] + if func_name in function_mappings: + func = function_mappings[func_name] + func_args = list(raw_function.values())[0] + if not isinstance(func_args, list): + func_args = [func_args] + return func(tosca_tpl, node_template, func_name, func_args) return raw_function diff --git a/tosca2heat/tosca-parser/toscaparser/imports.py b/tosca2heat/tosca-parser/toscaparser/imports.py index 451c952..b69bf4d 100644 --- a/tosca2heat/tosca-parser/toscaparser/imports.py +++ b/tosca2heat/tosca-parser/toscaparser/imports.py @@ -221,7 +221,7 @@ class ImportsLoader(object): dir_path = os.path.dirname(os.path.abspath( self.path)) if file_path[0] != '' and dir_path.endswith( - file_path[0]): + file_path[0]): import_template = dir_path + "/" +\ file_path[2] if not os.path.isfile(import_template): diff --git a/tosca2heat/tosca-parser/toscaparser/nodetemplate.py b/tosca2heat/tosca-parser/toscaparser/nodetemplate.py index 10eae33..ca855ad 100644 --- a/tosca2heat/tosca-parser/toscaparser/nodetemplate.py +++ b/tosca2heat/tosca-parser/toscaparser/nodetemplate.py @@ -22,6 +22,7 @@ from toscaparser.common.exception import ValidationError from toscaparser.dataentity import DataEntity from toscaparser.elements.interfaces import CONFIGURE from toscaparser.elements.interfaces import CONFIGURE_SHORTNAME +from toscaparser.elements.interfaces import INTERFACE_DEF_RESERVED_WORDS from toscaparser.elements.interfaces import InterfacesDef from toscaparser.elements.interfaces import LIFECYCLE from toscaparser.elements.interfaces import LIFECYCLE_SHORTNAME @@ -54,7 +55,7 @@ class NodeTemplate(EntityTemplate): def relationships(self): if not self._relationships: requires = self.requirements - if requires: + if requires and isinstance(requires, list): for r in requires: for r1, value in r.items(): explicit = self._get_explicit_relationship(r, value) @@ -206,13 +207,15 @@ class NodeTemplate(EntityTemplate): TypeMismatchError( what='"requirements" of template "%s"' % self.name, type='list')) - for req in requires: - for r1, value in req.items(): - if isinstance(value, dict): - self._validate_requirements_keys(value) - self._validate_requirements_properties(value) - allowed_reqs.append(r1) - self._common_validate_field(req, allowed_reqs, 'requirements') + else: + for req in requires: + for r1, value in req.items(): + if isinstance(value, dict): + self._validate_requirements_keys(value) + self._validate_requirements_properties(value) + allowed_reqs.append(r1) + self._common_validate_field(req, allowed_reqs, + 'requirements') def _validate_requirements_properties(self, requirements): # TODO(anyone): Only occurrences property of the requirements is @@ -229,7 +232,7 @@ class NodeTemplate(EntityTemplate): for value in occurrences: DataEntity.validate_datatype('integer', value) if len(occurrences) != 2 or not (0 <= occurrences[0] <= occurrences[1]) \ - or occurrences[1] == 0: + or occurrences[1] == 0: ExceptionCollector.appendException( InvalidPropertyValueError(what=(occurrences))) @@ -245,23 +248,42 @@ class NodeTemplate(EntityTemplate): ifaces = self.type_definition.get_value(self.INTERFACES, self.entity_tpl) if ifaces: - for i in ifaces: - for name, value in ifaces.items(): - if name in (LIFECYCLE, LIFECYCLE_SHORTNAME): - self._common_validate_field( - value, InterfacesDef. - interfaces_node_lifecycle_operations, - 'interfaces') - elif name in (CONFIGURE, CONFIGURE_SHORTNAME): - self._common_validate_field( - value, InterfacesDef. - interfaces_relationship_configure_operations, - 'interfaces') - else: - ExceptionCollector.appendException( - UnknownFieldError( - what='"interfaces" of template "%s"' % - self.name, field=name)) + for name, value in ifaces.items(): + if name in (LIFECYCLE, LIFECYCLE_SHORTNAME): + self._common_validate_field( + value, InterfacesDef. + interfaces_node_lifecycle_operations, + 'interfaces') + elif name in (CONFIGURE, CONFIGURE_SHORTNAME): + self._common_validate_field( + value, InterfacesDef. + interfaces_relationship_configure_operations, + 'interfaces') + elif name in self.type_definition.interfaces.keys(): + self._common_validate_field( + value, + self._collect_custom_iface_operations(name), + 'interfaces') + else: + ExceptionCollector.appendException( + UnknownFieldError( + what='"interfaces" of template "%s"' % + self.name, field=name)) + + def _collect_custom_iface_operations(self, name): + allowed_operations = [] + nodetype_iface_def = self.type_definition.interfaces[name] + allowed_operations.extend(nodetype_iface_def.keys()) + if 'type' in nodetype_iface_def: + iface_type = nodetype_iface_def['type'] + if iface_type in self.type_definition.custom_def: + iface_type_def = self.type_definition.custom_def[iface_type] + else: + iface_type_def = self.type_definition.TOSCA_DEF[iface_type] + allowed_operations.extend(iface_type_def.keys()) + allowed_operations = [op for op in allowed_operations if + op not in INTERFACE_DEF_RESERVED_WORDS] + return allowed_operations def _validate_fields(self, nodetemplate): for name in nodetemplate.keys(): diff --git a/tosca2heat/tosca-parser/toscaparser/parameters.py b/tosca2heat/tosca-parser/toscaparser/parameters.py index ca8e697..787db00 100644 --- a/tosca2heat/tosca-parser/toscaparser/parameters.py +++ b/tosca2heat/tosca-parser/toscaparser/parameters.py @@ -27,9 +27,10 @@ log = logging.getLogger('tosca') class Input(object): - INPUTFIELD = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS, REQUIRED, - STATUS) = ('type', 'description', 'default', - 'constraints', 'required', 'status') + INPUTFIELD = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS, REQUIRED, STATUS, + ENTRY_SCHEMA) = ('type', 'description', 'default', + 'constraints', 'required', 'status', + 'entry_schema') def __init__(self, name, schema_dict): self.name = name @@ -58,6 +59,10 @@ class Input(object): def constraints(self): return self.schema.constraints + @property + def status(self): + return self.schema.status + def validate(self, value=None): if value is not None: self._validate_value(value) diff --git a/tosca2heat/tosca-parser/toscaparser/policy.py b/tosca2heat/tosca-parser/toscaparser/policy.py index 61c09ec..fedbeb4 100644 --- a/tosca2heat/tosca-parser/toscaparser/policy.py +++ b/tosca2heat/tosca-parser/toscaparser/policy.py @@ -29,7 +29,8 @@ log = logging.getLogger('tosca') class Policy(EntityTemplate): '''Policies defined in Topology template.''' - def __init__(self, name, policy, targets, targets_type, custom_def=None): + def __init__(self, name, policy, targets=None, targets_type=None, + custom_def=None): super(Policy, self).__init__(name, policy, 'policy_type', @@ -41,6 +42,9 @@ class Policy(EntityTemplate): self.targets_list = targets self.targets_type = targets_type self.triggers = self._triggers(policy.get(TRIGGERS)) + self.properties = None + if 'properties' in policy: + self.properties = policy['properties'] self._validate_keys() @property diff --git a/tosca2heat/tosca-parser/toscaparser/shell.py b/tosca2heat/tosca-parser/toscaparser/shell.py index b41c024..1d98f1a 100644 --- a/tosca2heat/tosca-parser/toscaparser/shell.py +++ b/tosca2heat/tosca-parser/toscaparser/shell.py @@ -11,6 +11,7 @@ # under the License. +import argparse import os import sys @@ -40,19 +41,20 @@ e.g. class ParserShell(object): - def _validate(self, args): - if len(args) < 1: - msg = _('The program requires a template or a CSAR file as an ' - 'argument. Please refer to the usage documentation.') - raise ValueError(msg) - if "--template-file=" not in args[0]: - msg = _('The program expects "--template-file" as the first ' - 'argument. Please refer to the usage documentation.') - raise ValueError(msg) - - def main(self, args): - self._validate(args) - path = args[0].split('--template-file=')[1] + def get_parser(self, argv): + parser = argparse.ArgumentParser(prog="tosca-parser") + + parser.add_argument('--template-file', + metavar='<filename>', + required=True, + help=_('YAML template or CSAR file to parse.')) + + return parser + + def main(self, argv): + parser = self.get_parser(argv) + (args, extra_args) = parser.parse_known_args(argv) + path = args.template_file if os.path.isfile(path): self.parse(path) elif toscaparser.utils.urlutils.UrlUtils.validate_url(path): @@ -88,6 +90,18 @@ class ParserShell(object): for node in nodetemplates: print("\t" + node.name) + # example of retrieving policy object + '''if hasattr(tosca, 'policies'): + policies = tosca.policies + if policies: + print("policies:") + for policy in policies: + print("\t" + policy.name) + if policy.triggers: + print("\ttriggers:") + for trigger in policy.triggers: + print("\ttrigger name:" + trigger.name)''' + if hasattr(tosca, 'outputs'): outputs = tosca.outputs if outputs: diff --git a/tosca2heat/tosca-parser/toscaparser/tests/base.py b/tosca2heat/tosca-parser/toscaparser/tests/base.py index f6ff8d1..2619889 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/base.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/base.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - # Copyright 2010-2011 OpenStack Foundation # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar Binary files differindex 5fae801..a514dc6 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip Binary files differindex 5fae801..0d860d4 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml new file mode 100644 index 0000000..3fd4466 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml @@ -0,0 +1,44 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + TOSCA simple profile with mysql docker container. + +# Repositories to retrieve code artifacts from +repositories: + docker_hub: https://registry.hub.docker.com/ + +topology_template: + + inputs: + mysql_root_pwd: + type: string + description: Root password for MySQL. + + node_templates: + # The MYSQL container based on official MySQL image in Docker hub + mysql_container: + type: tosca.nodes.Container.Application.Docker + requirements: + - host: mysql_runtime + artifacts: + my_image: + file: mysql + type: tosca.artifacts.Deployment.Image.Container.Docker + repository: docker_hub + interfaces: + Standard: + create: + implementation: my_image + inputs: + MYSQL_ROOT_PASSWORD: { get_input: mysql_root_pwd } + + # The properties of the runtime to host the container + mysql_runtime: + type: tosca.nodes.Container.Runtime + capabilities: + host: + properties: + num_cpus: 1 + disk_size: 10 GB + mem_size: 2 MB + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml index f23a8a1..909a297 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml @@ -1,6 +1,6 @@ tosca_definitions_version: tosca_simple_yaml_1_0 -description: Compute node type with capability with an atribute of type list +description: Compute node type with capability with an attribute of type list capability_types: diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml new file mode 100644 index 0000000..2d9bec4 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml @@ -0,0 +1,20 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + This template contains custom defined interface type + and a node type which uses this custom interface + +interface_types: + tosca.interfaces.CustomInterface: + derived_from: tosca.interfaces.Root + CustomOp: + CustomOp2: + +node_types: + tosca.nodes.CustomInterfaceTest: + derived_from: tosca.nodes.WebApplication + interfaces: + CustomInterface: + type: tosca.interfaces.CustomInterface + CustomOp3: + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml index 70d0b0f..c8e4532 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml @@ -32,3 +32,7 @@ policy_types: type: map entry_schema: type: string +relationship_types1: +relationship_types: + test.relation.connects: + derived_from4: tosca.relationships.ConnectsTo diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml new file mode 100644 index 0000000..6155595 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: Test template demonstrating usage of nested dsl_definitions value. + +dsl_definitions: + caps: &caps + host: + properties: + disk_size: 10 GB + num_cpus: 2 + mem_size: 4096 MB + os: + properties: + architecture: x86_64 + type: Linux + distribution: Ubuntu + version: 14.04 + +topology_template: + node_templates: + my_server: + type: tosca.nodes.Compute + capabilities: *caps
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml index 923305c..34c1c33 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml @@ -26,3 +26,5 @@ topology_template: outputs: ip_address: value: { get_attribute: [ unknown_node_template, private_address ] } + network: + value: { get_attribute: [ unknown_node_template, networks, public ] } diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml new file mode 100644 index 0000000..a269005 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml @@ -0,0 +1,25 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + Attribute can be defined explicitly as part of type definition + or implicitly via property. This TOSCA template tests validation + of attribute name implicitly created as a property and referenced + via get_attribute function. + +node_types: + ServerNode: + derived_from: SoftwareComponent + properties: + notification_port: + type: integer + +topology_template: + node_templates: + my_server: + type: ServerNode + properties: + notification_port: 8000 + + outputs: + ip_address: + value: { get_attribute: [ my_server, notification_port ] }
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml index 1e5f5e6..1ca69ca 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml @@ -23,7 +23,6 @@ topology_template: db_root_pwd: type: string description: Root password for MySQL. - default: '12345678' db_port: type: PortDef description: Port for the MySQL database. diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml new file mode 100644 index 0000000..c23917c --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + TOSCA simple profile with valid custom interface and operations. + +imports: + - ../custom_types/custom_interface.yaml + +topology_template: + + node_templates: + customInterfaceTest: + type: tosca.nodes.CustomInterfaceTest + interfaces: + CustomInterface: + CustomOp: # operation from interface_type with additional inputs + inputs: + param: + type: string + CustomOp3: # operation from node_type with additional inputs + inputs: + param3: + type: string diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml new file mode 100644 index 0000000..d56ad9c --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml @@ -0,0 +1,19 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + TOSCA simple profile with invalid custom operation. + +imports: + - ../custom_types/custom_interface.yaml + +topology_template: + + node_templates: + customInterfaceTest: + type: tosca.nodes.CustomInterfaceTest + interfaces: + CustomInterface: + CustomOp4: # invalid operation + inputs: + param3: + type: string diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml new file mode 100644 index 0000000..2fcdb48 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml @@ -0,0 +1,75 @@ +# Note: this could eventually be translated to a Neutron Load Balancer +# However, in Heat/HOT the preferred way of doing this is creating an Autoscale Group +# +#heat_template_version: 2015-04-30 ... +#resources: +#load_bal_resource: +# type: OS::Neutron::Pool +# properties: +# admin_state_up: Boolean +# description: String +# lb_method: String +# monitors: [Value, Value, ...] +# name: String +# protocol: String +# provider: String +# subnet: String +# vip: { +# "description": String, +# "name": String, +# "connection_limit": Integer, +# "protocol_port": Integer, +# "subnet": String, +# "address": String, +# "admin_state_up": Boolean, +# "session_persistence": +# { +# "cookie_name": String, +# "type": String} +# } +# +# example from: https://gist.github.com/therve/9231701 +# +#resources: +# web_server_group: +# type: AWS::AutoScaling::AutoScalingGroup +# properties: +# AvailabilityZones: [nova] +# LaunchConfigurationName: {get_resource: launch_config} +# MinSize: 1 +# MaxSize: 3 +# LoadBalancerNames: +# - {get_resource: mylb} +# mypool: +# type: OS::Neutron::Pool +# properties: +# protocol: HTTP +# monitors: [{get_resource: mymonitor}] +# subnet_id: {get_param: subnet_id} +# lb_method: ROUND_ROBIN +# vip: +# protocol_port: 80 +# mylb: +# type: OS::Neutron::LoadBalancer +# properties: +# protocol_port: 80 +# pool_id: {get_resource: mypool} + +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: Template for deploying a load balancer with predefined endpoint properties. + +topology_template: + node_templates: + simple_load_balancer: + type: tosca.nodes.LoadBalancer + capabilities: + # properties: + # algorithm: DEFAULT (define new keyword, ROUND_ROBIN?) + # Client, public facing endpoint + client: + properties: + network_name: PUBLIC + floating: true + dns_name: http://mycompany.com/ + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml new file mode 100644 index 0000000..3dd8e26 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml @@ -0,0 +1,18 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: Template with requirements against hosting infrastructure. + +topology_template: + + node_templates: + test: + type: tosca.nodes.DBMS + requirements: + - host: + node_filter: + capabilities: + - host: + properties: + - num_cpus: { in_range: [ 1, 4 ] } + - mem_size: { greater_or_equal: 2 GB } + diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml new file mode 100644 index 0000000..96b0d45 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml @@ -0,0 +1,183 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 + +data_types: + tosca.datatypes.tacker.ActionMap: + properties: + trigger: + type: string + required: true + action: + type: string + required: true + params: + type: map + entry_schema: + type: string + required: false + + tosca.datatypes.tacker.MonitoringParams: + properties: + monitoring_delay: + type: int + required: false + count: + type: int + required: false + interval: + type: int + required: false + timeout: + type: int + required: false + retry: + type: int + required: false + port: + type: int + required: false + + tosca.datatypes.tacker.MonitoringType: + properties: + name: + type: string + required: true + actions: + type: map + required: true + parameters: + type: tosca.datatypes.tacker.MonitoringParams + required: false + + tosca.datatypes.compute_properties: + properties: + num_cpus: + type: integer + required: false + mem_size: + type: string + required: false + disk_size: + type: string + required: false + mem_page_size: + type: string + required: false + numa_node_count: + type: integer + constraints: + - greater_or_equal: 2 + required: false + numa_nodes: + type: map + required: false + cpu_allocation: + type: map + required: false + +policy_types: + tosca.policies.tacker.Placement: + derived_from: tosca.policies.Root + + tosca.policies.tacker.Failure: + derived_from: tosca.policies.Root + action: + type: string + + tosca.policies.tacker.Failure.Respawn: + derived_from: tosca.policies.tacker.Failure + action: respawn + + tosca.policies.tacker.Failure.Terminate: + derived_from: tosca.policies.tacker.Failure + action: log_and_kill + + tosca.policies.tacker.Failure.Log: + derived_from: tosca.policies.tacker.Failure + action: log + + tosca.policies.tacker.Monitoring: + derived_from: tosca.policies.Root + properties: + name: + type: string + required: true + parameters: + type: map + entry_schema: + type: string + required: false + actions: + type: map + entry_schema: + type: string + required: true + + tosca.policies.tacker.Monitoring.NoOp: + derived_from: tosca.policies.tacker.Monitoring + properties: + name: noop + + tosca.policies.tacker.Monitoring.Ping: + derived_from: tosca.policies.tacker.Monitoring + properties: + name: ping + + tosca.policies.tacker.Monitoring.HttpPing: + derived_from: tosca.policies.tacker.Monitoring.Ping + properties: + name: http-ping + + tosca.policies.tacker.Alarming: + derived_from: tosca.policies.Monitoring + triggers: + resize_compute: + event_type: + type: map + entry_schema: + type: string + required: true + metrics: + type: string + required: true + condition: + type: map + entry_schema: + type: string + required: false + action: + type: map + entry_schema: + type: string + required: true + + tosca.policies.tacker.Scaling: + derived_from: tosca.policies.Scaling + description: Defines policy for scaling the given targets. + properties: + increment: + type: integer + required: true + description: Number of nodes to add or remove during the scale out/in. + targets: + type: list + entry_schema: + type: string + required: true + description: List of Scaling nodes. + min_instances: + type: integer + required: true + description: Minimum number of instances to scale in. + max_instances: + type: integer + required: true + description: Maximum number of instances to scale out. + default_instances: + type: integer + required: true + description: Initial number of instances. + cooldown: + type: integer + required: false + default: 120 + description: Wait time (in seconds) between consecutive scaling operations. During the cooldown period... diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml new file mode 100644 index 0000000..1387509 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml @@ -0,0 +1,261 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 + +data_types: + tosca.nfv.datatypes.pathType: + properties: + forwarder: + type: string + required: true + capability: + type: string + required: true + + tosca.nfv.datatypes.aclType: + properties: + eth_type: + type: string + required: false + eth_src: + type: string + required: false + eth_dst: + type: string + required: false + vlan_id: + type: integer + constraints: + - in_range: [ 1, 4094 ] + required: false + vlan_pcp: + type: integer + constraints: + - in_range: [ 0, 7 ] + required: false + mpls_label: + type: integer + constraints: + - in_range: [ 16, 1048575] + required: false + mpls_tc: + type: integer + constraints: + - in_range: [ 0, 7 ] + required: false + ip_dscp: + type: integer + constraints: + - in_range: [ 0, 63 ] + required: false + ip_ecn: + type: integer + constraints: + - in_range: [ 0, 3 ] + required: false + ip_src_prefix: + type: string + required: false + ip_dst_prefix: + type: string + required: false + ip_proto: + type: integer + constraints: + - in_range: [ 1, 254 ] + required: false + destination_port_range: + type: string + required: false + source_port_range: + type: string + required: false + network_src_port_id: + type: string + required: false + network_dst_port_id: + type: string + required: false + network_id: + type: string + required: false + network_name: + type: string + required: false + tenant_id: + type: string + required: false + icmpv4_type: + type: integer + constraints: + - in_range: [ 0, 254 ] + required: false + icmpv4_code: + type: integer + constraints: + - in_range: [ 0, 15 ] + required: false + arp_op: + type: integer + constraints: + - in_range: [ 1, 25 ] + required: false + arp_spa: + type: string + required: false + arp_tpa: + type: string + required: false + arp_sha: + type: string + required: false + arp_tha: + type: string + required: false + ipv6_src: + type: string + required: false + ipv6_dst: + type: string + required: false + ipv6_flabel: + type: integer + constraints: + - in_range: [ 0, 1048575] + required: false + icmpv6_type: + type: integer + constraints: + - in_range: [ 0, 255] + required: false + icmpv6_code: + type: integer + constraints: + - in_range: [ 0, 7] + required: false + ipv6_nd_target: + type: string + required: false + ipv6_nd_sll: + type: string + required: false + ipv6_nd_tll: + type: string + required: false + + tosca.nfv.datatypes.policyType: + properties: + type: + type: string + required: false + constraints: + - valid_values: [ ACL ] + criteria: + type: list + required: true + entry_schema: + type: tosca.nfv.datatypes.aclType + +node_types: + tosca.nodes.nfv.VDU.Tacker: + derived_from: tosca.nodes.nfv.VDU + capabilities: + nfv_compute: + type: tosca.datatypes.compute_properties + properties: + name: + type: string + required: false + image: +# type: tosca.artifacts.Deployment.Image.VM + type: string + required: false + flavor: + type: string + required: false + availability_zone: + type: string + required: false + metadata: + type: map + entry_schema: + type: string + required: false + config_drive: + type: boolean + default: false + required: false + + placement_policy: +# type: tosca.policies.tacker.Placement + type: string + required: false + + monitoring_policy: +# type: tosca.policies.tacker.Monitoring +# type: tosca.datatypes.tacker.MonitoringType + type: map + required: false + + config: + type: string + required: false + + mgmt_driver: + type: string + default: noop + required: false + + service_type: + type: string + required: false + + user_data: + type: string + required: false + + user_data_format: + type: string + required: false + + key_name: + type: string + required: false + + tosca.nodes.nfv.CP.Tacker: + derived_from: tosca.nodes.nfv.CP + properties: + mac_address: + type: string + required: false + name: + type: string + required: false + management: + type: boolean + required: false + anti_spoofing_protection: + type: boolean + required: false + security_groups: + type: list + required: false + type: + type: string + required: false + constraints: + - valid_values: [ sriov, vnic ] + + tosca.nodes.nfv.FP.Tacker: + derived_from: tosca.nodes.Root + properties: + id: + type: integer + required: false + policy: + type: tosca.nfv.datatypes.policyType + required: true + description: policy to use to match traffic for this FP + path: + type: list + required: true + entry_schema: + type: tosca.nfv.datatypes.pathType diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml new file mode 100644 index 0000000..452dbb5 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml @@ -0,0 +1,95 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0 + +description: sample-tosca-vnfd-scaling + +imports: + - tacker_defs.yaml + - tacker_nfv_defs.yaml + +metadata: + template_name: sample-tosca-vnfd-scaling + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: cirros-0.3.4-x86_64-uec + mgmt_driver: noop + availability_zone: nova + flavor: m1.tiny + + CP1: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + order: 0 + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU1 + + VDU2: + type: tosca.nodes.nfv.VDU.Tacker + properties: + image: cirros-0.3.4-x86_64-uec + mgmt_driver: noop + availability_zone: nova + flavor: m1.tiny + + CP2: + type: tosca.nodes.nfv.CP.Tacker + properties: + management: true + order: 0 + anti_spoofing_protection: false + requirements: + - virtualLink: + node: VL1 + - virtualBinding: + node: VDU2 + + VL1: + type: tosca.nodes.nfv.VL + properties: + network_name: net_mgmt + vendor: Tacker + + policies: + - SP1: + type: tosca.policies.tacker.Scaling + targets: [VDU1] + properties: + increment: 1 + cooldown: 120 + min_instances: 1 + max_instances: 2 + default_instances: 1 + + - SP2: + type: tosca.policies.tacker.Scaling + targets: [VDU2] + properties: + increment: 1 + cooldown: 120 + min_instances: 1 + max_instances: 2 + default_instances: 1 + + - ALRM1: + type: tosca.policies.tacker.Monitoring + triggers: + resize_compute: + event_type: + type: tosca.events.resource.utilization + implementation: ceilometer + condition: + constraint: 50 + period: 600 + evaluations: 1 + method: avg + action: + resize_compute: + action_name: SP1 diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml index 92bebe5..47f7870 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml @@ -66,7 +66,7 @@ topology_template: requirement: host capability: Container condition: - constraint: utilization greater_than 50% + constraint: { greater_than: 50 } period: 60 evaluations: 1 method: average diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml new file mode 100644 index 0000000..81b92b4 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml @@ -0,0 +1,48 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: Test template for deploying a single server with predefined properties and custom relationship types + +imports: + - ../custom_types/custom_relationship_type_defs.yaml + +topology_template: + node_templates: + server1: + type: tosca.nodes.HACompute + capabilities: + # Host container properties + host: + properties: + num_cpus: 2 + disk_size: 10 GB + mem_size: 512 MB + # Guest Operating System properties + os: + properties: + # host Operating System image properties + architecture: x86_64 + type: Linux + distribution: RHEL + version: 6.5 + requirements: + - high_availability: server2 + + server2: + type: tosca.nodes.HACompute + capabilities: + # Host container properties + host: + properties: + num_cpus: 2 + disk_size: 10 GB + mem_size: 512 MB + # Guest Operating System properties + os: + properties: + # host Operating System image properties + architecture: x86_64 + type: Linux + distribution: RHEL + version: 6.5 + requirements: + - high_availability: server1 diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml new file mode 100644 index 0000000..c2856c8 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +repositories: + some_repository: + description: Some repo + url: https://raw.githubusercontent.com/openstack/tosca-parser/master/toscaparser/tests/data/custom_types/ + credential: #type: Credential + token_type: basic_auth + token: myusername:mypassword +imports: + - some_import: + file: compute_with_prop.yaml + repository: some_repository + +description: > + TOSCA test for testing repositories definition + + node_templates: + + server: + type: tosca.nodes.ComputeWithProp + properties: + test: yes diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml new file mode 100644 index 0000000..0001d06 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml @@ -0,0 +1,26 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: TOSCA simple profile with repositories validation and imports. + +repositories: + repo_code0: https://raw.githubusercontent.com/nandinivemula/intern + repo_code1: + description: My project's code Repository in github usercontent. + url: https://raw.githubusercontent.com/nandinivemula/intern/master + credential: #type: Credential + token_type: basic_auth + token: myusername:mypassword + + repo_code2: + description: My Project's code Repository in github. + url: https://github.com/nandinivemula/intern/master + credential: #type: Credential + token_type: basic_auth + token: myusername:mypassword + +imports: + - sample_import: + file: tosca_repository_import.yaml + repository: repo_code1 + namespace_uri: https://github.com/nandinivemula/intern + namespace_prefix: intern diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml new file mode 100644 index 0000000..bb67577 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml @@ -0,0 +1,67 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + Test Requirements. + +imports: + - ../custom_types/wordpress.yaml + +topology_template: + node_templates: + my_app: + description: > + Specify multiple requirement via node and relationship keyword, + as an explicit relationship. Also demonstrates relationship with + type keyword and without it as an in-line reference. + type: tosca.nodes.WebApplication.WordPress + requirements: + - req1: + node: my_webserver + relationship: tosca.relationships.HostedOn + - req2: + node: mysql_database + relationship: + type: tosca.relationships.ConnectsTo + mysql_database: + description: Specify requirement via a capability as an implicit relationship. + type: tosca.nodes.Database + requirements: + - host: + node: my_dbms + relationship: tosca.relationships.HostedOn + my_dbms: + type: tosca.nodes.DBMS + my_webserver: + type: tosca.nodes.WebServer + my_server: + description: > + Specify requirement via a relationship template, as an explicit relationship. + type: tosca.nodes.Compute + capabilities: + host: + properties: + num_cpus: 2 + disk_size: 10 GB + mem_size: 4 MB + os: + properties: + # host Operating System image properties + architecture: x86_64 + type: linux + distribution: rhel + version: 6.5 + requirements: + - req1: + node: my_storage + relationship: storage_attachment + my_storage: + type: tosca.nodes.BlockStorage + properties: + size: 1 GiB + snapshot_id: id + + relationship_templates: + storage_attachment: + type: tosca.relationships.AttachesTo + properties: + location: /temp diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml new file mode 100644 index 0000000..cf2ec94 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml @@ -0,0 +1,21 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +topology_template: + node_templates: + server: + type: tosca.nodes.Compute + capabilities: + host: + properties: + disk_size: 10 GB + num_cpus: 1 + mem_size: 4096 MB + os: + properties: + architecture: x86_64 + type: Linux + distribution: Ubuntu + version: 14.04 + endpoint: + properties: + network_name: PUBLIC diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml index ccae4eb..479a1ec 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml @@ -35,6 +35,9 @@ topology_template: default: 3306 node_templates: + xyz: + type: tosca.nodes.XYZ + wordpress: type: tosca.nodes.WebApplication.WordPress requirement: diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml new file mode 100644 index 0000000..3c3e272 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml @@ -0,0 +1,37 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + Test template for deploying a server with custom properties for image, + flavor and key_name. This template provides an example of how to + override TOSCA normative type's (e.g. Compute) properties. Here new + properties are injected in the tosca.nodes.myserver which derives from + tosca.nodes.Compute. Note that tosca.nodes.myserver can not be a name of + another normative type (e.g. tosca.nodes.WebServer or tosca.nodes.nfv.VDU) + because that will create conflict while resolving type definition by the + TOSCA Parser. + +node_types: + tosca.nodes.myserver: + derived_from: tosca.nodes.Compute + properties: + key_name: + type: string + image: + type: string + flavor: + type: string + +topology_template: + inputs: + key_name: + type: string + default: inputkey + + node_templates: + my_server: + type: tosca.nodes.myserver + properties: + flavor: m1.medium + image: rhel-6.5-test-image + key_name: + get_input: key_name diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml index 77829c6..ba5eac1 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml @@ -27,8 +27,10 @@ node_types: properties: mq_server_ip: type: string + required: False receiver_port: type: integer + required: False attributes: receiver_ip: type: string @@ -51,8 +53,10 @@ node_types: properties: admin_user: type: string + required: False pool_size: type: integer + required: False capabilities: message_receiver: type: example.capabilities.Receiver diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml new file mode 100644 index 0000000..718022a --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml @@ -0,0 +1,70 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: > + Template showing an example TOSCA type to demonstrate usage + of output in the substitution mappings. + +node_types: + example.app: + derived_from: tosca.nodes.WebApplication + properties: + mq_server_ip: + type: string + required: False + receiver_port: + type: integer + required: False + attributes: + receiver_ip: + type: string + receiver_port: + type: integer + +topology_template: + inputs: + mq_server_ip: + type: string + description: IP address of the message queuing server to receive messages from. + default: 127.0.0.1 + receiver_port: + type: integer + description: Port to be used for receiving messages. + default: 8080 + my_cpus: + type: integer + description: Number of CPUs for the server. + default: 2 + constraints: + - valid_values: [ 1, 2, 4, 8 ] + + substitution_mappings: + node_type: example.app + + node_templates: + app: + type: example.app + properties: + mq_server_ip: { get_input: mq_server_ip } + receiver_port: { get_input: receiver_port } + requirements: + - host: + node: websrv + websrv: + type: tosca.nodes.WebServer + requirements: + - host: + node: server + server: + type: tosca.nodes.Compute + capabilities: + host: + properties: + disk_size: 10 GB + num_cpus: { get_input: my_cpus } + mem_size: 4096 MB + os: + properties: + architecture: x86_64 + type: Linux + distribution: Ubuntu + version: 14.04 diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml new file mode 100644 index 0000000..ef21811 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml @@ -0,0 +1,31 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +imports: + - test_example_app_substitution_mappings.yaml + +topology_template: + description: > + Test template showing valid output section containing attribute defined + in the substitution mappings in the imported yaml file. + + inputs: + mq_server_ip: + type: string + default: 127.0.0.1 + description: IP address of the message queuing server to receive messages from. + mq_server_port: + type: integer + default: 8080 + description: Port to be used for receiving messages. + + node_templates: + substitute_app: + type: example.app + properties: + mq_server_ip: { get_input: mq_server_ip } + receiver_port: { get_input: mq_server_port } + + outputs: + receiver_ip: + description: private IP address of the message receiver application + value: { get_attribute: [ substitute_app, my_cpu_output ] }
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml new file mode 100644 index 0000000..766ca87 --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml @@ -0,0 +1,31 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +imports: + - test_example_app_substitution_mappings.yaml + +topology_template: + description: > + Test template showing valid output section containing attribute defined + in the substitution mappings in the imported yaml file. + + inputs: + mq_server_ip: + type: string + default: 127.0.0.1 + description: IP address of the message queuing server to receive messages from. + mq_server_port: + type: integer + default: 8080 + description: Port to be used for receiving messages. + + node_templates: + sustitute_app: + type: example.app + properties: + mq_server_ip: { get_input: mq_server_ip } + receiver_port: { get_input: mq_server_port } + + outputs: + receiver_ip: + description: private IP address of the message receiver application + value: { get_attribute: [ sustitute_app, receiver_ip ] }
\ No newline at end of file diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml index 9c3fef4..257beb8 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml @@ -37,3 +37,9 @@ topology_template: metadata: user1: 1001 user2: 1003 + relationship_templates: + my_custom_rel: + type: test.relation.connects + interfaces: + Configure: + pre_configure_source: scripts/wp_db_configure.sh diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml index f605b05..9e686ab 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml @@ -29,7 +29,6 @@ topology_template: db_root_pwd: type: string description: Root password for MySQL. - default: '12345678' db_port: type: PortDef description: Port for the MySQL database. diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml index 9a57eb0..6caac11 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml @@ -31,7 +31,6 @@ topology_template: db_root_pwd: type: string description: Root password for MySQL. - default: '12345678' db_port: type: PortDef description: Port for the MySQL database. diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml index 5d41749..e5f1580 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml @@ -29,7 +29,6 @@ topology_template: db_root_pwd: type: string description: Root password for MySQL. - default: '12345678' db_port: type: PortDef description: Port for the MySQL database. diff --git a/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml new file mode 100644 index 0000000..f47f33c --- /dev/null +++ b/tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml @@ -0,0 +1,19 @@ +tosca_definitions_version: tosca_simple_yaml_1_0 + +description: TOSCA simple profile to test the GET OPERATION OUTPUT functionality + +imports: + - custom_types/compute_with_prop.yaml + +topology_template: + + node_templates: + + front_end: + type: tosca.nodes.ComputeWithProp + interfaces: + Standard: + create: + implementation: nodejs/create.sh + inputs: + data_dir: {get_operation_output: [front_end,Standard,create,data_dir]} diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py b/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py index 71de0c2..9ae85d5 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py @@ -21,7 +21,7 @@ class CustomRelationshipTypesTest(TestCase): '''TOSCA template.''' tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/test_custom_relationships.yaml") + "data/relationship/test_custom_relationship.yaml") tosca = ToscaTemplate(tosca_tpl) def test_version(self): diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py b/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py index 81de909..fa60140 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_functions.py @@ -24,7 +24,8 @@ class IntrinsicFunctionsTest(TestCase): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/tosca_single_instance_wordpress.yaml") - params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user'} + params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user', + 'db_root_pwd': '12345678'} tosca = ToscaTemplate(tosca_tpl, parsed_params=params) def _get_node(self, node_name, tosca=None): @@ -56,7 +57,7 @@ class IntrinsicFunctionsTest(TestCase): wordpress = self._get_node('wordpress') operation = self._get_operation(wordpress.interfaces, 'configure') wp_db_password = operation.inputs['wp_db_password'] - self.assertTrue(isinstance(wp_db_password, functions.GetProperty)) + self.assertIsInstance(wp_db_password, functions.GetProperty) result = wp_db_password.result() self.assertEqual('wp_pass', result) @@ -64,7 +65,7 @@ class IntrinsicFunctionsTest(TestCase): wordpress = self._get_node('wordpress') operation = self._get_operation(wordpress.interfaces, 'configure') wp_db_user = operation.inputs['wp_db_user'] - self.assertTrue(isinstance(wp_db_user, functions.GetProperty)) + self.assertIsInstance(wp_db_user, functions.GetProperty) result = wp_db_user.result() self.assertEqual('my_db_user', result) @@ -83,7 +84,7 @@ class IntrinsicFunctionsTest(TestCase): props = mysql_dbms.get_properties() for key in props.keys(): prop = props[key] - self.assertTrue(isinstance(prop.value, functions.GetInput)) + self.assertIsInstance(prop.value, functions.GetInput) expected_inputs.remove(prop.value.input_name) self.assertListEqual(expected_inputs, []) @@ -116,21 +117,24 @@ class IntrinsicFunctionsTest(TestCase): self.assertEqual(3306, dbms_port.result()) dbms_root_password = self._get_property(mysql_dbms, 'root_password') - self.assertEqual(dbms_root_password.result(), "12345678") + self.assertEqual(dbms_root_password.result(), '12345678') def test_get_property_with_host(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/functions/test_get_property_with_host.yaml") mysql_database = self._get_node('mysql_database', - ToscaTemplate(tosca_tpl)) + ToscaTemplate(tosca_tpl, + parsed_params={ + 'db_root_pwd': '123' + })) operation = self._get_operation(mysql_database.interfaces, 'configure') db_port = operation.inputs['db_port'] - self.assertTrue(isinstance(db_port, functions.GetProperty)) + self.assertIsInstance(db_port, functions.GetProperty) result = db_port.result() self.assertEqual(3306, result) test = operation.inputs['test'] - self.assertTrue(isinstance(test, functions.GetProperty)) + self.assertIsInstance(test, functions.GetProperty) result = test.result() self.assertEqual(1, result) @@ -138,30 +142,37 @@ class IntrinsicFunctionsTest(TestCase): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/functions/tosca_nested_property_names_indexes.yaml") - webserver = self._get_node('wordpress', ToscaTemplate(tosca_tpl)) + webserver = self._get_node('wordpress', + ToscaTemplate(tosca_tpl, + parsed_params={ + 'db_root_pwd': '1234'})) operation = self._get_operation(webserver.interfaces, 'configure') wp_endpoint_prot = operation.inputs['wp_endpoint_protocol'] - self.assertTrue(isinstance(wp_endpoint_prot, functions.GetProperty)) + self.assertIsInstance(wp_endpoint_prot, functions.GetProperty) self.assertEqual('tcp', wp_endpoint_prot.result()) wp_list_prop = operation.inputs['wp_list_prop'] - self.assertTrue(isinstance(wp_list_prop, functions.GetProperty)) + self.assertIsInstance(wp_list_prop, functions.GetProperty) self.assertEqual(3, wp_list_prop.result()) def test_get_property_with_capabilties_inheritance(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/functions/test_capabilties_inheritance.yaml") - some_node = self._get_node('some_node', ToscaTemplate(tosca_tpl)) + some_node = self._get_node('some_node', + ToscaTemplate(tosca_tpl, + parsed_params={ + 'db_root_pwd': '1234'})) operation = self._get_operation(some_node.interfaces, 'configure') some_input = operation.inputs['some_input'] - self.assertTrue(isinstance(some_input, functions.GetProperty)) + self.assertIsInstance(some_input, functions.GetProperty) self.assertEqual('someval', some_input.result()) def test_get_property_source_target_keywords(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/functions/test_get_property_source_target_keywords.yaml") - tosca = ToscaTemplate(tosca_tpl) + tosca = ToscaTemplate(tosca_tpl, + parsed_params={'db_root_pwd': '1234'}) for node in tosca.nodetemplates: for relationship, trgt in node.relationships.items(): @@ -171,10 +182,10 @@ class IntrinsicFunctionsTest(TestCase): operation = self._get_operation(rel_template.interfaces, 'pre_configure_source') target_test = operation.inputs['target_test'] - self.assertTrue(isinstance(target_test, functions.GetProperty)) + self.assertIsInstance(target_test, functions.GetProperty) self.assertEqual(1, target_test.result()) source_port = operation.inputs['source_port'] - self.assertTrue(isinstance(source_port, functions.GetProperty)) + self.assertIsInstance(source_port, functions.GetProperty) self.assertEqual(3306, source_port.result()) @@ -184,7 +195,8 @@ class GetAttributeTest(TestCase): return ToscaTemplate(os.path.join( os.path.dirname(os.path.abspath(__file__)), 'data', - filename)) + filename), + parsed_params={'db_root_pwd': '1234'}) def _get_operation(self, interfaces, operation): return [ @@ -283,7 +295,8 @@ class GetAttributeTest(TestCase): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/functions/test_get_attribute_source_target_keywords.yaml") - tosca = ToscaTemplate(tosca_tpl) + tosca = ToscaTemplate(tosca_tpl, + parsed_params={'db_root_pwd': '12345678'}) for node in tosca.nodetemplates: for relationship, trgt in node.relationships.items(): @@ -293,14 +306,18 @@ class GetAttributeTest(TestCase): operation = self._get_operation(rel_template.interfaces, 'pre_configure_source') target_test = operation.inputs['target_test'] - self.assertTrue(isinstance(target_test, functions.GetAttribute)) + self.assertIsInstance(target_test, functions.GetAttribute) source_port = operation.inputs['source_port'] - self.assertTrue(isinstance(source_port, functions.GetAttribute)) + self.assertIsInstance(source_port, functions.GetAttribute) def test_get_attribute_with_nested_params(self): self._load_template( 'functions/test_get_attribute_with_nested_params.yaml') + def test_implicit_attribute(self): + self.assertIsNotNone(self._load_template( + 'functions/test_get_implicit_attribute.yaml')) + class ConcatTest(TestCase): diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py b/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py index fcd1c83..09a24b6 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py @@ -243,7 +243,7 @@ class GetNumFromScalarUnitSizeNegative(TestCase): (ScalarUnit_Size(self.InputMemSize). get_num_from_scalar_unit(self.UserInputUnit)) except Exception as error: - self.assertTrue(isinstance(error, ValueError)) + self.assertIsInstance(error, ValueError) self.assertEqual(_('The unit "qB" is not valid. Valid units are ' '"[\'B\', \'GB\', \'GiB\', \'KiB\', \'MB\', ' '\'MiB\', \'TB\', \'TiB\', \'kB\']".'), @@ -260,7 +260,7 @@ class GetNumFromScalarUnitFrequencyNegative(TestCase): (ScalarUnit_Frequency(self.InputFrequency). get_num_from_scalar_unit(self.UserInputUnit)) except Exception as error: - self.assertTrue(isinstance(error, ValueError)) + self.assertIsInstance(error, ValueError) self.assertEqual(_('The unit "Jz" is not valid. Valid units are ' '"[\'GHz\', \'Hz\', \'MHz\', \'kHz\']".'), error.__str__()) @@ -276,7 +276,7 @@ class GetNumFromScalarUnitTimeNegative(TestCase): (ScalarUnit_Time(self.InputTime). get_num_from_scalar_unit(self.UserInputUnit)) except Exception as error: - self.assertTrue(isinstance(error, ValueError)) + self.assertIsInstance(error, ValueError) self.assertEqual(_('"Jz" is not a valid scalar-unit.'), error.__str__()) diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py b/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py index e0b5a4e..bb163ff 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_shell.py @@ -29,16 +29,10 @@ class ShellTest(TestCase): "data/test_multiple_validation_errors.yaml") def test_missing_arg(self): - error = self.assertRaises(ValueError, shell.main, '') - err_msg = _('The program requires a template or a CSAR file as an ' - 'argument. Please refer to the usage documentation.') - self.assertEqual(err_msg, str(error)) + self.assertRaises(SystemExit, shell.main, '') def test_invalid_arg(self): - error = self.assertRaises(ValueError, shell.main, 'parse me') - err_msg = _('The program expects "--template-file" as the first ' - 'argument. Please refer to the usage documentation.') - self.assertEqual(err_msg, str(error)) + self.assertRaises(SystemExit, shell.main, 'parse me') def test_template_not_exist(self): error = self.assertRaises( diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py index 0c26b67..3aabc9b 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py @@ -220,48 +220,48 @@ class TopologyTemplateTest(TestCase): self.assertEqual(expected_message, err.__str__()) def test_invalid_nodetype(self): - tpl_snippet = ''' - substitution_mappings: - node_type: example.DatabaseSubsystem1 - capabilities: - database_endpoint: [ db_app, database_endpoint ] - requirements: - receiver1: [ tran_app, receiver1 ] - ''' - sub_mappings = (toscaparser.utils.yamlparser. - simple_parse(tpl_snippet))['substitution_mappings'] - custom_defs = self._get_custom_types() - expected_message = _('Node type "example.DatabaseSubsystem1" ' - 'is not a valid type.') - err = self.assertRaises( - exception.InvalidNodeTypeError, - lambda: SubstitutionMappings(sub_mappings, None, None, - None, None, custom_defs)) - self.assertEqual(expected_message, err.__str__()) + tpl_snippet = ''' + substitution_mappings: + node_type: example.DatabaseSubsystem1 + capabilities: + database_endpoint: [ db_app, database_endpoint ] + requirements: + receiver1: [ tran_app, receiver1 ] + ''' + sub_mappings = (toscaparser.utils.yamlparser. + simple_parse(tpl_snippet))['substitution_mappings'] + custom_defs = self._get_custom_types() + expected_message = _('Node type "example.DatabaseSubsystem1" ' + 'is not a valid type.') + err = self.assertRaises( + exception.InvalidNodeTypeError, + lambda: SubstitutionMappings(sub_mappings, None, None, + None, None, custom_defs)) + self.assertEqual(expected_message, err.__str__()) def test_system_with_input_validation(self): - tpl_path0 = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "data/topology_template/validate/system_invalid_input.yaml") - tpl_path1 = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - "data/topology_template/validate/" - "queuingsubsystem_invalid_input.yaml") - errormsg = _('SubstitutionMappings with node_type ' - 'example.QueuingSubsystem is missing ' - 'required input definition of input "server_port".') - - # It's invalid in nested template. - self.assertRaises(exception.ValidationError, - lambda: ToscaTemplate(tpl_path0)) - exception.ExceptionCollector.assertExceptionMessage( - exception.MissingRequiredInputError, errormsg) - - # Subtemplate deploy standaolone is also invalid. - self.assertRaises(exception.ValidationError, - lambda: ToscaTemplate(tpl_path1)) - exception.ExceptionCollector.assertExceptionMessage( - exception.MissingRequiredInputError, errormsg) + tpl_path0 = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/topology_template/validate/system_invalid_input.yaml") + tpl_path1 = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/topology_template/validate/" + "queuingsubsystem_invalid_input.yaml") + errormsg = _('SubstitutionMappings with node_type ' + 'example.QueuingSubsystem is missing ' + 'required input definition of input "server_port".') + + # It's invalid in nested template. + self.assertRaises(exception.ValidationError, + lambda: ToscaTemplate(tpl_path0)) + exception.ExceptionCollector.assertExceptionMessage( + exception.MissingRequiredInputError, errormsg) + + # Subtemplate deploy standaolone is also invalid. + self.assertRaises(exception.ValidationError, + lambda: ToscaTemplate(tpl_path1)) + exception.ExceptionCollector.assertExceptionMessage( + exception.MissingRequiredInputError, errormsg) def test_system_with_unknown_output_validation(self): tpl_path0 = os.path.join( diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py index 358bf28..2e97b0e 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py @@ -60,7 +60,7 @@ class ToscaDefTest(TestCase): def test_group(self): self.assertEqual(group_type.type, "tosca.groups.Root") - self.assertEqual(group_type.parent_type, None) + self.assertIsNone(group_type.parent_type) self.assertIn(ifaces.LIFECYCLE_SHORTNAME, group_type.interfaces) def test_capabilities(self): @@ -71,6 +71,7 @@ class ToscaDefTest(TestCase): # we SHOULD test symbolic capability names as well self.assertEqual( ['tosca.capabilities.Container', + 'tosca.capabilities.Endpoint.Admin', 'tosca.capabilities.Node', 'tosca.capabilities.OperatingSystem', 'tosca.capabilities.Scalable', @@ -184,12 +185,12 @@ class ToscaDefTest(TestCase): relation, node in network_port_type.relationship.items()]) def test_interfaces(self): - self.assertEqual(compute_type.interfaces, None) + self.assertIsNone(compute_type.interfaces) root_node = NodeType('tosca.nodes.Root') self.assertIn(ifaces.LIFECYCLE_SHORTNAME, root_node.interfaces) def test_artifacts(self): - self.assertEqual(artif_root_type.parent_type, None) + self.assertIsNone(artif_root_type.parent_type) self.assertEqual('tosca.artifacts.Root', artif_file_type.parent_type.type) self.assertEqual({}, artif_file_type.parent_artifacts) @@ -284,7 +285,7 @@ class ToscaDefTest(TestCase): key=lambda x: str(x))) def test_policies(self): - self.assertEqual(policy_root_type.parent_type, None) + self.assertIsNone(policy_root_type.parent_type) self.assertEqual('tosca.policies.Root', policy_placement_type.parent_type.type) self.assertEqual({}, policy_placement_type.parent_policies) diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py index e87b672..77232df 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py @@ -30,13 +30,15 @@ class ToscaTemplateTest(TestCase): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/tosca_single_instance_wordpress.yaml") - tosca = ToscaTemplate(tosca_tpl) + params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user', + 'db_root_pwd': '12345678'} + tosca = ToscaTemplate(tosca_tpl, parsed_params=params) tosca_elk_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/tosca_elk.yaml") tosca_repo_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/tosca_repositories_test_definition.yaml") + "data/repositories/tosca_repositories_test_definition.yaml") def test_version(self): self.assertEqual(self.tosca.version, "tosca_simple_yaml_1_0") @@ -145,8 +147,6 @@ class ToscaTemplateTest(TestCase): wordpress_node.is_derived_from("tosca.nodes.Root")) self.assertFalse( wordpress_node.is_derived_from("tosca.policies.Root")) - self.assertFalse( - wordpress_node.is_derived_from("tosca.groups.Root")) def test_outputs(self): self.assertEqual( @@ -174,14 +174,14 @@ class ToscaTemplateTest(TestCase): self.assertEqual(3, len(interface.inputs)) TestCase.skip(self, 'bug #1440247') wp_db_port = interface.inputs['wp_db_port'] - self.assertTrue(isinstance(wp_db_port, GetProperty)) + self.assertIsInstance(wp_db_port, GetProperty) self.assertEqual('get_property', wp_db_port.name) self.assertEqual(['SELF', 'database_endpoint', 'port'], wp_db_port.args) result = wp_db_port.result() - self.assertTrue(isinstance(result, GetInput)) + self.assertIsInstance(result, GetInput) else: raise AssertionError( 'Unexpected interface: {0}'.format(interface.name)) @@ -200,6 +200,7 @@ class ToscaTemplateTest(TestCase): compute_type = NodeType(tpl.type) self.assertEqual( sorted(['tosca.capabilities.Container', + 'tosca.capabilities.Endpoint.Admin', 'tosca.capabilities.Node', 'tosca.capabilities.OperatingSystem', 'tosca.capabilities.network.Bindable', @@ -286,7 +287,7 @@ class ToscaTemplateTest(TestCase): """ tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/test_requirements.yaml") + "data/requirements/test_requirements.yaml") tosca = ToscaTemplate(tosca_tpl) for node_tpl in tosca.nodetemplates: if node_tpl.name == 'my_app': @@ -438,14 +439,17 @@ class ToscaTemplateTest(TestCase): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/tosca_single_instance_wordpress.yaml") - tosca = ToscaTemplate(tosca_tpl) + params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user', + 'db_root_pwd': '12345678'} + tosca = ToscaTemplate(tosca_tpl, parsed_params=params) self.assertTrue(tosca.topology_template.custom_defs) def test_local_template_with_url_import(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/tosca_single_instance_wordpress_with_url_import.yaml") - tosca = ToscaTemplate(tosca_tpl) + tosca = ToscaTemplate(tosca_tpl, + parsed_params={'db_root_pwd': '123456'}) self.assertTrue(tosca.topology_template.custom_defs) def test_url_template_with_local_relpath_import(self): @@ -576,6 +580,10 @@ class ToscaTemplateTest(TestCase): exception.ExceptionCollector.assertExceptionMessage( exception.MissingRequiredFieldError, err9_msg) + err10_msg = _('Type "tosca.nodes.XYZ" is not a valid type.') + exception.ExceptionCollector.assertExceptionMessage( + exception.InvalidTypeError, err10_msg) + def test_invalid_section_names(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -673,9 +681,10 @@ class ToscaTemplateTest(TestCase): "data/tosca_single_instance_wordpress.yaml") yaml_dict_tpl = toscaparser.utils.yamlparser.load_yaml(test_tpl) - + params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user', + 'db_root_pwd': '12345678'} self.assertRaises(exception.ValidationError, ToscaTemplate, None, - None, False, yaml_dict_tpl) + params, False, yaml_dict_tpl) err_msg = (_('Relative file name "custom_types/wordpress.yaml" ' 'cannot be used in a pre-parsed input template.')) exception.ExceptionCollector.assertExceptionMessage(ImportError, @@ -747,7 +756,7 @@ class ToscaTemplateTest(TestCase): def test_node_filter(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/test_node_filter.yaml") + "data/node_filter/test_node_filter.yaml") ToscaTemplate(tosca_tpl) def test_attributes_inheritance(self): @@ -759,7 +768,7 @@ class ToscaTemplateTest(TestCase): def test_repositories_definition(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/test_repositories_definition.yaml") + "data/repositories/test_repositories_definition.yaml") ToscaTemplate(tosca_tpl) def test_custom_caps_def(self): @@ -819,5 +828,26 @@ class ToscaTemplateTest(TestCase): def test_containers(self): tosca_tpl = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/test_containers.yaml") + "data/containers/test_container_docker_mysql.yaml") ToscaTemplate(tosca_tpl, parsed_params={"mysql_root_pwd": "12345678"}) + + def test_endpoint_on_compute(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/test_endpoint_on_compute.yaml") + ToscaTemplate(tosca_tpl) + + def test_nested_dsl_def(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/dsl_definitions/test_nested_dsl_def.yaml") + self.assertIsNotNone(ToscaTemplate(tosca_tpl)) + + def test_multiple_policies(self): + tosca_tpl = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/policies/test_tosca_nfv_multiple_policies.yaml") + tosca = ToscaTemplate(tosca_tpl) + self.assertEqual( + ['ALRM1', 'SP1', 'SP2'], + sorted([policy.name for policy in tosca.policies])) diff --git a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py index 5a8f37a..911867f 100644 --- a/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py +++ b/tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py @@ -35,8 +35,28 @@ class ToscaTemplateValidationTest(TestCase): tpl_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "data/tosca_single_instance_wordpress.yaml") + params = {'db_name': 'my_wordpress', 'db_user': 'my_db_user', + 'db_root_pwd': '12345678'} + self.assertIsNotNone(ToscaTemplate(tpl_path, params)) + + def test_custom_interface_allowed(self): + tpl_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/interfaces/test_custom_interface_in_template.yaml") self.assertIsNotNone(ToscaTemplate(tpl_path)) + def test_custom_interface_invalid_operation(self): + tpl_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/interfaces/test_custom_interface_invalid_operation.yaml") + self.assertRaises(exception.ValidationError, + ToscaTemplate, tpl_path) + exception.ExceptionCollector.assertExceptionMessage( + exception.UnknownFieldError, + _('"interfaces" of template "customInterfaceTest" ' + 'contains unknown field "CustomOp4". ' + 'Refer to the definition to verify valid values.')) + def test_first_level_sections(self): tpl_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), @@ -97,6 +117,117 @@ class ToscaTemplateValidationTest(TestCase): _('Policy "mycompany.mytypes.myScalingPolicy" contains unknown ' 'field "derived1_from". Refer to the definition to ' 'verify valid values.')) + exception.ExceptionCollector.assertExceptionMessage( + exception.UnknownFieldError, + _('Relationshiptype "test.relation.connects" contains unknown ' + 'field "derived_from4". Refer to the definition to ' + 'verify valid values.')) + + def test_getoperation_IncorrectValue(self): + # test case 1 + tpl_snippet = ''' + node_templates: + front_end: + type: tosca.nodes.Compute + interfaces: + Standard: + create: + implementation: scripts/frontend/create.sh + configure: + implementation: scripts/frontend/configure.sh + inputs: + data_dir: {get_operation_output: [front_end,Standard1, + create,data_dir]} + ''' + tpl = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet)) + err = self.assertRaises(ValueError, + TopologyTemplate, tpl, None) + expectedmessage = _('Enter a valid interface name') + self.assertEqual(expectedmessage, err.__str__()) + # test case 2 + tpl_snippet2 = ''' + node_templates: + front_end: + type: tosca.nodes.Compute + interfaces: + Standard: + create: + implementation: scripts/frontend/create.sh + configure: + implementation: scripts/frontend/configure.sh + inputs: + data_dir: {get_operation_output: [front_end1,Standard, + create,data_dir]} + ''' + tpl2 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet2)) + err2 = self.assertRaises(KeyError, + TopologyTemplate, tpl2, None) + expectedmessage2 = _('\'Node template "front_end1" was not found.\'') + self.assertEqual(expectedmessage2, err2.__str__()) + # test case 3 + tpl_snippet3 = ''' + node_templates: + front_end: + type: tosca.nodes.Compute + interfaces: + Standard: + create: + implementation: scripts/frontend/create.sh + configure: + implementation: scripts/frontend/configure.sh + inputs: + data_dir: {get_operation_output: [front_end,Standard, + get_target,data_dir]} + ''' + tpl3 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet3)) + err3 = self.assertRaises(ValueError, + TopologyTemplate, tpl3, None) + expectedmessage3 = _('Enter an operation of Standard interface') + self.assertEqual(expectedmessage3, err3.__str__()) + # test case 4 + tpl_snippet4 = ''' + node_templates: + front_end: + type: tosca.nodes.Compute + interfaces: + Standard: + create: + implementation: scripts/frontend/create.sh + configure: + implementation: scripts/frontend/configure.sh + inputs: + data_dir: {get_operation_output: [front_end,Configure, + create,data_dir]} + ''' + tpl4 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet4)) + err4 = self.assertRaises(ValueError, + TopologyTemplate, tpl4, None) + expectedmessage4 = _('Enter an operation of Configure interface') + self.assertEqual(expectedmessage4, err4.__str__()) + # test case 5 + tpl_snippet5 = ''' + node_templates: + front_end: + type: tosca.nodes.Compute + interfaces: + Standard: + create: + implementation: scripts/frontend/create.sh + configure: + implementation: scripts/frontend/configure.sh + inputs: + data_dir: {get_operation_output: [front_end,Standard, + create]} + ''' + tpl5 = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet5)) + err5 = self.assertRaises(ValueError, + TopologyTemplate, tpl5, None) + expectedmessage5 = _('Illegal arguments for function' + ' "get_operation_output".' + ' Expected arguments: "template_name",' + '"interface_name",' + '"operation_name","output_variable_name"') + self.assertEqual(expectedmessage5, err5.__str__()) def test_unsupported_type(self): tpl_snippet = ''' @@ -135,6 +266,15 @@ class ToscaTemplateValidationTest(TestCase): required: yes status: supported ''' + tpl_snippet3 = ''' + inputs: + some_list: + type: list + description: List of items + entry_schema: + type: string + default: [] + ''' inputs1 = (toscaparser.utils.yamlparser. simple_parse(tpl_snippet1)['inputs']) name1, attrs1 = list(inputs1.items())[0] @@ -144,14 +284,13 @@ class ToscaTemplateValidationTest(TestCase): try: Input(name1, attrs1) except Exception as err: - # err=self.assertRaises(exception.UnknownFieldError, - # input1.validate) self.assertEqual(_('Input "cpus" contains unknown field ' '"constraint". Refer to the definition to ' 'verify valid values.'), err.__str__()) input2 = Input(name2, attrs2) self.assertTrue(input2.required) + toscaparser.utils.yamlparser.simple_parse(tpl_snippet3)['inputs'] def _imports_content_test(self, tpl_snippet, path, custom_type_def): imports = (toscaparser.utils.yamlparser. @@ -366,7 +505,7 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml try: output.validate() except Exception as err: - self.assertTrue(isinstance(err, exception.UnknownFieldError)) + self.assertIsInstance(err, exception.UnknownFieldError) self.assertEqual(_('Output "server_address" contains unknown ' 'field "descriptions". Refer to the definition ' 'to verify valid values.'), @@ -1456,7 +1595,7 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml requirement: host capability: Container condition: - constraint: utilization greater_than 50% + constraint: { greater_than: 50 } period: 60 evaluations: 1 method : average @@ -1555,3 +1694,91 @@ heat-translator/master/translator/tests/data/custom_types/wordpress.yaml 'unknown field "oss". Refer to the definition ' 'to verify valid values.') self.assertEqual(expectedmessage, err.__str__()) + + def test_qualified_name(self): + tpl_snippet_full_name = ''' + node_templates: + supported_type: + type: tosca.nodes.Compute + ''' + tpl = ( + toscaparser.utils.yamlparser.simple_parse( + tpl_snippet_full_name)) + TopologyTemplate(tpl, None) + + tpl_snippet_short_name = ''' + node_templates: + supported_type: + type: Compute + ''' + tpl = ( + toscaparser.utils.yamlparser.simple_parse( + tpl_snippet_short_name)) + TopologyTemplate(tpl, None) + + tpl_snippet_qualified_name = ''' + node_templates: + supported_type: + type: tosca:Compute + ''' + tpl = ( + toscaparser.utils.yamlparser.simple_parse( + tpl_snippet_qualified_name)) + TopologyTemplate(tpl, None) + + def test_requirements_as_list(self): + """Node template with requirements provided with or without list + + Node template requirements are required to be provided as list. + """ + + expectedmessage = _('"requirements" of template "my_webserver"' + ' must be of type "list".') + + # requirements provided as dictionary + tpl_snippet1 = ''' + node_templates: + my_webserver: + type: tosca.nodes.WebServer + requirements: + host: server + server: + type: tosca.nodes.Compute + ''' + err1 = self.assertRaises( + exception.TypeMismatchError, + lambda: self._single_node_template_content_test(tpl_snippet1)) + self.assertEqual(expectedmessage, err1.__str__()) + + # requirements provided as string + tpl_snippet2 = ''' + node_templates: + my_webserver: + type: tosca.nodes.WebServer + requirements: server + server: + type: tosca.nodes.Compute + ''' + err2 = self.assertRaises( + exception.TypeMismatchError, + lambda: self._single_node_template_content_test(tpl_snippet2)) + self.assertEqual(expectedmessage, err2.__str__()) + + # requirements provided as list + tpl_snippet3 = ''' + node_templates: + my_webserver: + type: tosca.nodes.WebServer + requirements: + - host: server + server: + type: tosca.nodes.Compute + ''' + self.assertIsNone( + self._single_node_template_content_test(tpl_snippet3)) + + def test_properties_override_with_flavor_and_image(self): + tpl_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "data/test_normative_type_properties_override.yaml") + self.assertIsNotNone(ToscaTemplate(tpl_path)) diff --git a/tosca2heat/tosca-parser/toscaparser/topology_template.py b/tosca2heat/tosca-parser/toscaparser/topology_template.py index d7fd443..4571fe7 100644 --- a/tosca2heat/tosca-parser/toscaparser/topology_template.py +++ b/tosca2heat/tosca-parser/toscaparser/topology_template.py @@ -118,6 +118,7 @@ class TopologyTemplate(object): def _substitution_mappings(self): tpl_substitution_mapping = self._tpl_substitution_mappings() + # if tpl_substitution_mapping and self.sub_mapped_node_template: if tpl_substitution_mapping: return SubstitutionMappings(tpl_substitution_mapping, self.nodetemplates, @@ -131,17 +132,17 @@ class TopologyTemplate(object): for policy in self._tpl_policies(): for policy_name, policy_tpl in policy.items(): target_list = policy_tpl.get('targets') + target_objects = [] + targets_type = "groups" if target_list and len(target_list) >= 1: - target_objects = [] - targets_type = "groups" target_objects = self._get_policy_groups(target_list) if not target_objects: targets_type = "node_templates" target_objects = self._get_group_members(target_list) - policyObj = Policy(policy_name, policy_tpl, - target_objects, targets_type, - self.custom_defs) - policies.append(policyObj) + policyObj = Policy(policy_name, policy_tpl, + target_objects, targets_type, + self.custom_defs) + policies.append(policyObj) return policies def _groups(self): @@ -152,7 +153,7 @@ class TopologyTemplate(object): if member_names is not None: DataEntity.validate_datatype('list', member_names) if len(member_names) < 1 or \ - len(member_names) != len(set(member_names)): + len(member_names) != len(set(member_names)): exception.ExceptionCollector.appendException( exception.InvalidGroupTargetException( message=_('Member nodes "%s" should be >= 1 ' @@ -196,16 +197,16 @@ class TopologyTemplate(object): # topology template can act like node template # it is exposed by substitution_mappings. def nodetype(self): - return (self.substitution_mappings.node_type - if self.substitution_mappings else None) + return self.substitution_mappings.node_type \ + if self.substitution_mappings else None def capabilities(self): - return (self.substitution_mappings.capabilities - if self.substitution_mappings else None) + return self.substitution_mappings.capabilities \ + if self.substitution_mappings else None def requirements(self): - return (self.substitution_mappings.requirements - if self.substitution_mappings else None) + return self.substitution_mappings.requirements \ + if self.substitution_mappings else None def _tpl_description(self): description = self.tpl.get(DESCRIPTION) @@ -258,7 +259,8 @@ class TopologyTemplate(object): self, node_template, value) - if node_template.requirements: + if node_template.requirements and \ + isinstance(node_template.requirements, list): for req in node_template.requirements: rel = req for req_name, req_item in req.items(): @@ -291,7 +293,7 @@ class TopologyTemplate(object): for interface in rel_tpl.interfaces: if interface.inputs: for name, value in \ - interface.inputs.items(): + interface.inputs.items(): interface.inputs[name] = \ functions.get_function(self, rel_tpl, diff --git a/tosca2heat/tosca-parser/toscaparser/tosca_template.py b/tosca2heat/tosca-parser/toscaparser/tosca_template.py index 84d953c..f48078f 100644 --- a/tosca2heat/tosca-parser/toscaparser/tosca_template.py +++ b/tosca2heat/tosca-parser/toscaparser/tosca_template.py @@ -36,14 +36,14 @@ SECTIONS = (DEFINITION_VERSION, DEFAULT_NAMESPACE, TEMPLATE_NAME, TOPOLOGY_TEMPLATE, TEMPLATE_AUTHOR, TEMPLATE_VERSION, DESCRIPTION, IMPORTS, DSL_DEFINITIONS, NODE_TYPES, RELATIONSHIP_TYPES, RELATIONSHIP_TEMPLATES, - CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES, + CAPABILITY_TYPES, ARTIFACT_TYPES, DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES, REPOSITORIES) = \ ('tosca_definitions_version', 'tosca_default_namespace', 'template_name', 'topology_template', 'template_author', 'template_version', 'description', 'imports', 'dsl_definitions', 'node_types', 'relationship_types', 'relationship_templates', 'capability_types', 'artifact_types', 'data_types', - 'policy_types', 'group_types', 'repositories') + 'interface_types', 'policy_types', 'group_types', 'repositories') # Sections that are specific to individual template definitions SPECIAL_SECTIONS = (METADATA) = ('metadata') @@ -106,6 +106,7 @@ class ToscaTemplate(object): self.relationship_templates = self._relationship_templates() self.nodetemplates = self._nodetemplates() self.outputs = self._outputs() + self.policies = self._policies() self._handle_nested_tosca_templates_with_topology() self.graph = ToscaGraph(self.nodetemplates) @@ -162,9 +163,12 @@ class ToscaTemplate(object): def _tpl_topology_template(self): return self.tpl.get(TOPOLOGY_TEMPLATE) + def _policies(self): + return self.topology_template.policies + def _get_all_custom_defs(self, imports=None): types = [IMPORTS, NODE_TYPES, CAPABILITY_TYPES, RELATIONSHIP_TYPES, - DATA_TYPES, POLICY_TYPES, GROUP_TYPES] + DATA_TYPES, INTERFACE_TYPES, POLICY_TYPES, GROUP_TYPES] custom_defs_final = {} custom_defs = self._get_custom_types(types, imports) if custom_defs: @@ -196,9 +200,9 @@ class ToscaTemplate(object): imports = self._tpl_imports() if imports: - custom_service = \ - toscaparser.imports.ImportsLoader(imports, self.path, - type_defs, self.tpl) + custom_service = toscaparser.imports.\ + ImportsLoader(imports, self.path, + type_defs, self.tpl) nested_tosca_tpls = custom_service.get_nested_tosca_tpls() self._update_nested_tosca_tpls_with_topology(nested_tosca_tpls) diff --git a/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py b/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py index 0d2f1d6..a0c11f0 100644 --- a/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py +++ b/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py @@ -20,6 +20,18 @@ log = logging.getLogger('tosca') class UnsupportedType(object): + """Note: TOSCA spec version related + + The tosca.nodes.Storage.ObjectStorage and tosca.nodes.Storage.BlockStorage + used here as un_supported_types are part of the name changes in TOSCA spec + version 1.1. The original name as specified in version 1.0 are, + tosca.nodes.BlockStorage and tosca.nodes.ObjectStorage which are supported + by the tosca-parser. Since there are little overlapping in version support + currently in the tosca-parser, the names tosca.nodes.Storage.ObjectStorage + and tosca.nodes.Storage.BlockStorage are used here to demonstrate the usage + of un_supported_types. As tosca-parser move to provide support for version + 1.1 and higher, they will be removed. + """ un_supported_types = ['tosca.test.invalidtype', 'tosca.nodes.Storage.ObjectStorage', 'tosca.nodes.Storage.BlockStorage'] diff --git a/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py b/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py index f5562e2..d631ac8 100644 --- a/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py +++ b/tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py @@ -19,4 +19,5 @@ _t = gettext.translation('tosca-parser', localedir=_localedir, def _(msg): + # type: (object) -> object return _t.gettext(msg) diff --git a/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py b/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py index 43e14d6..b280576 100644 --- a/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py +++ b/tosca2heat/tosca-parser/toscaparser/utils/validateutils.py @@ -198,7 +198,7 @@ class TOSCAVersionProperty(object): """ if self.minor_version is None and self.build_version is None and \ - value != '0': + value != '0': log.warning(_('Minor version assumed "0".')) self.version = '.'.join([value, '0']) return value |