Sync upstream code 85/29385/2
authorshangxdy <shang.xiaodong@zte.com.cn>
Sat, 25 Feb 2017 16:49:42 +0000 (00:49 +0800)
committershangxdy <shang.xiaodong@zte.com.cn>
Sat, 25 Feb 2017 16:58:41 +0000 (00:58 +0800)
Sync upstream project of tosca-parser

Change-Id: Ic707844203ea05007b3c02e9dcadb52389eb3149
JIRA:PARSER-118
Signed-off-by: shangxdy <shang.xiaodong@zte.com.cn>
76 files changed:
tosca2heat/tosca-parser/README.rst
tosca2heat/tosca-parser/doc/source/conf.py
tosca2heat/tosca-parser/doc/source/installation.rst
tosca2heat/tosca-parser/requirements.txt
tosca2heat/tosca-parser/setup.cfg
tosca2heat/tosca-parser/test-requirements.txt
tosca2heat/tosca-parser/tools/tox_install.sh [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/__init__.py
tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml
tosca2heat/tosca-parser/toscaparser/elements/capabilitytype.py
tosca2heat/tosca-parser/toscaparser/elements/constraints.py
tosca2heat/tosca-parser/toscaparser/elements/entity_type.py
tosca2heat/tosca-parser/toscaparser/elements/grouptype.py
tosca2heat/tosca-parser/toscaparser/elements/interfaces.py
tosca2heat/tosca-parser/toscaparser/elements/nodetype.py
tosca2heat/tosca-parser/toscaparser/elements/policytype.py
tosca2heat/tosca-parser/toscaparser/elements/portspectype.py
tosca2heat/tosca-parser/toscaparser/elements/relationshiptype.py
tosca2heat/tosca-parser/toscaparser/elements/statefulentitytype.py
tosca2heat/tosca-parser/toscaparser/entity_template.py
tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0_0.yaml [moved from tosca2heat/tosca-parser/toscaparser/extensions/nfv/TOSCA_nfv_definition_1_0.yaml with 100% similarity]
tosca2heat/tosca-parser/toscaparser/extensions/nfv/tosca_simple_profile_for_nfv_1_0_0.py [moved from tosca2heat/tosca-parser/toscaparser/extensions/nfv/nfv.py with 93% similarity]
tosca2heat/tosca-parser/toscaparser/functions.py
tosca2heat/tosca-parser/toscaparser/imports.py
tosca2heat/tosca-parser/toscaparser/nodetemplate.py
tosca2heat/tosca-parser/toscaparser/parameters.py
tosca2heat/tosca-parser/toscaparser/policy.py
tosca2heat/tosca-parser/toscaparser/shell.py
tosca2heat/tosca-parser/toscaparser/tests/base.py
tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar
tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip
tosca2heat/tosca-parser/toscaparser/tests/data/containers/test_container_docker_mysql.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/compute_with_nested_atributes.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/custom_interface.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/custom_types/imported_sample.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/dsl_definitions/test_nested_dsl_def.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_attribute_unknown_node_template_name.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_implicit_attribute.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/functions/test_get_property_with_host.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_in_template.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/interfaces/test_custom_interface_invalid_operation.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/load_balancer/tosca_load_balancer.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/node_filter/test_node_filter.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_defs.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/policies/tacker_nfv_defs.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/policies/test_tosca_nfv_multiple_policies.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/policies/tosca_policy_template.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/relationship/test_custom_relationship.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/repositories/test_repositories_definition.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/repositories/tosca_repositories_test_definition.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/requirements/test_requirements.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/test_endpoint_on_compute.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/test_multiple_validation_errors.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/test_normative_type_properties_override.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/definitions.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_example_app_substitution_mappings.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_invalid_output.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/topology_template/validate/test_substitution_mappings_valid_output.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/data/tosca_imports_validation.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_local_abspath_import.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/tosca_single_instance_wordpress_with_url_import.yaml
tosca2heat/tosca-parser/toscaparser/tests/data/tosca_test_get_operation_output.yaml [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/tests/test_custom_relationships.py
tosca2heat/tosca-parser/toscaparser/tests/test_functions.py
tosca2heat/tosca-parser/toscaparser/tests/test_scalarunit.py
tosca2heat/tosca-parser/toscaparser/tests/test_shell.py
tosca2heat/tosca-parser/toscaparser/tests/test_topology_template.py
tosca2heat/tosca-parser/toscaparser/tests/test_toscadef.py
tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py
tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py
tosca2heat/tosca-parser/toscaparser/topology_template.py
tosca2heat/tosca-parser/toscaparser/tosca_template.py
tosca2heat/tosca-parser/toscaparser/unsupportedtype.py
tosca2heat/tosca-parser/toscaparser/utils/gettextutils.py
tosca2heat/tosca-parser/toscaparser/utils/validateutils.py

index d80d75b..0f94072 100644 (file)
@@ -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
 ===============
index e461246..d5d9189 100644 (file)
@@ -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
index f3805a5..5476d41 100644 (file)
@@ -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
index b30cc51..45a19f0 100644 (file)
@@ -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
index c109228..77e1b2e 100644 (file)
@@ -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
index 1bb6623..d4b59c3 100644 (file)
@@ -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 (file)
index 0000000..e61b63a
--- /dev/null
@@ -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 $?
index d6fa60c..d9745ed 100644 (file)
@@ -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
index 6f3b331..9f3369e 100644 (file)
@@ -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
index 865690e..54cd9fe 100644 (file)
@@ -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
 
index 8594b85..70863bc 100644 (file)
@@ -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 = (
@@ -85,6 +85,10 @@ class Schema(collections.Mapping):
     def default(self):
         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:
index d7fcb18..9fd6c4d 100644 (file)
@@ -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 = {}
index 02c285a..4e58d64 100644 (file)
@@ -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"'
index 88fb8ab..47ec90a 100644 (file)
@@ -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():
index f5e4eb0..7d68c0b 100644 (file)
@@ -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> }
index 8fbb0f0..a922d26 100644 (file)
@@ -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,
index d32e97e..0218305 100644 (file)
@@ -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))
index 25440ca..8eefbea 100644 (file)
 #    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))
index be9933e..2f221b3 100644 (file)
@@ -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()):
index 7ce8cec..cc3d620 100644 (file)
@@ -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) \
index 1b64416..d498229 100644 (file)
@@ -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
index 451c952..b69bf4d 100644 (file)
@@ -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):
index 10eae33..ca855ad 100644 (file)
@@ -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():
index ca8e697..787db00 100644 (file)
@@ -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)
index 61c09ec..fedbeb4 100644 (file)
@@ -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
index b41c024..1d98f1a 100644 (file)
@@ -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:
index f6ff8d1..2619889 100644 (file)
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 # Copyright 2010-2011 OpenStack Foundation
 # Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
 #
index 5fae801..a514dc6 100644 (file)
Binary files a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar and b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.csar differ
index 5fae801..0d860d4 100644 (file)
Binary files a/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip and b/tosca2heat/tosca-parser/toscaparser/tests/data/CSAR/csar_elk.zip differ
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 (file)
index 0000000..3fd4466
--- /dev/null
@@ -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
+
index f23a8a1..909a297 100644 (file)
@@ -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 (file)
index 0000000..2d9bec4
--- /dev/null
@@ -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:
+
index 70d0b0f..c8e4532 100644 (file)
@@ -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 (file)
index 0000000..6155595
--- /dev/null
@@ -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
index 923305c..34c1c33 100644 (file)
@@ -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 (file)
index 0000000..a269005
--- /dev/null
@@ -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
index 1e5f5e6..1ca69ca 100644 (file)
@@ -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 (file)
index 0000000..c23917c
--- /dev/null
@@ -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 (file)
index 0000000..d56ad9c
--- /dev/null
@@ -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 (file)
index 0000000..2fcdb48
--- /dev/null
@@ -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 (file)
index 0000000..3dd8e26
--- /dev/null
@@ -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 (file)
index 0000000..96b0d45
--- /dev/null
@@ -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 (file)
index 0000000..1387509
--- /dev/null
@@ -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 (file)
index 0000000..452dbb5
--- /dev/null
@@ -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
index 92bebe5..47f7870 100644 (file)
@@ -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 (file)
index 0000000..81b92b4
--- /dev/null
@@ -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 (file)
index 0000000..c2856c8
--- /dev/null
@@ -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 (file)
index 0000000..0001d06
--- /dev/null
@@ -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 (file)
index 0000000..bb67577
--- /dev/null
@@ -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 (file)
index 0000000..cf2ec94
--- /dev/null
@@ -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
index ccae4eb..479a1ec 100644 (file)
@@ -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 (file)
index 0000000..3c3e272
--- /dev/null
@@ -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
index 77829c6..ba5eac1 100644 (file)
@@ -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 (file)
index 0000000..718022a
--- /dev/null
@@ -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 (file)
index 0000000..ef21811
--- /dev/null
@@ -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 (file)
index 0000000..766ca87
--- /dev/null
@@ -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
index 9c3fef4..257beb8 100644 (file)
@@ -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
index f605b05..9e686ab 100644 (file)
@@ -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.
index 9a57eb0..6caac11 100644 (file)
@@ -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.
index 5d41749..e5f1580 100644 (file)
@@ -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 (file)
index 0000000..f47f33c
--- /dev/null
@@ -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]}
index 71de0c2..9ae85d5 100644 (file)
@@ -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):
index 81de909..fa60140 100644 (file)
@@ -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):
 
index fcd1c83..09a24b6 100644 (file)
@@ -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__())
 
index e0b5a4e..bb163ff 100644 (file)
@@ -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(
index 0c26b67..3aabc9b 100644 (file)
@@ -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(
index 358bf28..2e97b0e 100644 (file)
@@ -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)
index e87b672..77232df 100644 (file)
@@ -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]))
index 5a8f37a..911867f 100644 (file)
@@ -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))
index d7fd443..4571fe7 100644 (file)
@@ -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,
index 84d953c..f48078f 100644 (file)
@@ -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)
index 0d2f1d6..a0c11f0 100644 (file)
@@ -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']
index f5562e2..d631ac8 100644 (file)
@@ -19,4 +19,5 @@ _t = gettext.translation('tosca-parser', localedir=_localedir,
 
 
 def _(msg):
+    # type: (object) -> object
     return _t.gettext(msg)
index 43e14d6..b280576 100644 (file)
@@ -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