Update the upstream of tosco-parser and heat-translator to stable 97/21097/1
authorshangxdy <shang.xiaodong@zte.com.cn>
Wed, 14 Sep 2016 06:36:33 +0000 (14:36 +0800)
committershangxdy <shang.xiaodong@zte.com.cn>
Wed, 14 Sep 2016 08:00:06 +0000 (16:00 +0800)
release 0.6/0.5

Currently the parser is based on dev branch of upstream projects,
include tosco-parser and heat-translator,  for the colorado release of
parser, it should be based on a stable version, so it's necessary to
update the upstream version to 0.6/tosca-parser and 0.5/heat-translator.

JIRA:PARSER-106

Change-Id: I8fb043068d25188c47e5648e1b66184446ac82d6
Signed-off-by: shangxdy <shang.xiaodong@zte.com.cn>
29 files changed:
tosca2heat/heat-translator/test-requirements.txt
tosca2heat/heat-translator/tox.ini
tosca2heat/heat-translator/translator/common/utils.py
tosca2heat/heat-translator/translator/hot/syntax/hot_output.py
tosca2heat/heat-translator/translator/hot/syntax/hot_resource.py
tosca2heat/heat-translator/translator/hot/syntax/hot_template.py
tosca2heat/heat-translator/translator/hot/tosca/tests/test_tosca_compute.py
tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage.py
tosca2heat/heat-translator/translator/hot/tosca/tosca_block_storage_attachment.py
tosca2heat/heat-translator/translator/hot/tosca/tosca_compute.py
tosca2heat/heat-translator/translator/hot/translate_node_templates.py
tosca2heat/heat-translator/translator/hot/translate_outputs.py
tosca2heat/heat-translator/translator/tests/test_tosca_hot_translation.py
tosca2heat/tosca-parser/setup.cfg
tosca2heat/tosca-parser/test-requirements.txt
tosca2heat/tosca-parser/toscaparser/common/exception.py
tosca2heat/tosca-parser/toscaparser/elements/TOSCA_definition_1_0.yaml
tosca2heat/tosca-parser/toscaparser/elements/artifacttype.py
tosca2heat/tosca-parser/toscaparser/elements/entity_type.py
tosca2heat/tosca-parser/toscaparser/elements/grouptype.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.yaml
tosca2heat/tosca-parser/toscaparser/tests/test_toscatpl.py
tosca2heat/tosca-parser/toscaparser/tests/test_toscatplvalidation.py
tosca2heat/tosca-parser/toscaparser/tests/test_utils.py
tosca2heat/tosca-parser/toscaparser/topology_template.py
tosca2heat/tosca-parser/toscaparser/unsupportedtype.py [new file with mode: 0644]
tosca2heat/tosca-parser/toscaparser/utils/urlutils.py

index 70a261b..17a507c 100644 (file)
@@ -4,11 +4,11 @@
 hacking<0.11,>=0.10.0
 coverage>=3.6 # Apache-2.0
 discover # BSD
-fixtures>=3.0.0 # Apache-2.0/BSD
+fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
 oslotest>=1.10.0 # Apache-2.0
 oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
 python-subunit>=0.0.18 # Apache-2.0/BSD
-sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
+sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
 testrepository>=0.0.18 # Apache-2.0/BSD
 testscenarios>=0.4 # Apache-2.0/BSD
 testtools>=1.4.0 # MIT
index 9ee67a0..be57d3e 100644 (file)
@@ -27,11 +27,6 @@ commands = python setup.py build_sphinx
 [testenv:debug]
 commands = oslo_debug_helper -t translator/tests {posargs}
 
-[testenv:py27-tosca-parser-master]
-commands =
-    ./run_py27-tosca-parser-master.sh
-    python setup.py test --slowest --testr-args='{posargs}'
-
 [flake8]
 # H803 skipped on purpose per list discussion.
 # E123, E125 skipped as they are invalid PEP-8.
index 8e4b690..459b5ee 100644 (file)
@@ -18,7 +18,6 @@ import numbers
 import os
 import re
 import requests
-import six
 from six.moves.urllib.parse import urlparse
 import yaml
 
@@ -263,17 +262,12 @@ class UrlUtils(object):
 
 def str_to_num(value):
     """Convert a string representation of a number into a numeric type."""
-    if isinstance(value, numbers.Number) \
-            or isinstance(value, six.integer_types) \
-            or isinstance(value, float):
+    if isinstance(value, numbers.Number):
         return value
     try:
         return int(value)
     except ValueError:
-        try:
-            return float(value)
-        except ValueError:
-            return None
+        return float(value)
 
 
 def check_for_env_variables():
index a41208a..ad77fb3 100644 (file)
@@ -21,8 +21,5 @@ class HotOutput(object):
         self.description = description
 
     def get_dict_output(self):
-        if self.description:
-            return {self.name: {'value': self.value,
-                                'description': self.description}}
-        else:
-            return {self.name: {'value': self.value}}
+        return {self.name: {'value': self.value,
+                            'description': self.description}}
index 7b83906..54e0d96 100644 (file)
@@ -103,7 +103,7 @@ class HotResource(object):
         # scenarios and cannot be fixed or hard coded here
         operations_deploy_sequence = ['create', 'configure', 'start']
 
-        operations = HotResource.get_all_operations(self.nodetemplate)
+        operations = HotResource._get_all_operations(self.nodetemplate)
 
         # create HotResource for each operation used for deployment:
         # create, start, configure
@@ -140,15 +140,7 @@ class HotResource(object):
                 # hosting_server is None if requirements is None
                 hosting_on_server = (hosting_server.name if
                                      hosting_server else None)
-                base_type = HotResource.get_base_type(
-                    self.nodetemplate.type_definition).type
-                # handle interfaces directly defined on a compute
-                if hosting_on_server is None \
-                    and base_type == 'tosca.nodes.Compute':
-                    hosting_on_server = self.name
-
-                if operation.name == reserve_current and \
-                    base_type != 'tosca.nodes.Compute':
+                if operation.name == reserve_current:
                     deploy_resource = self
                     self.name = deploy_name
                     self.type = 'OS::Heat::SoftwareDeployment'
@@ -156,7 +148,7 @@ class HotResource(object):
                                        'server': {'get_resource':
                                                   hosting_on_server},
                                        'signal_transport': 'HEAT_SIGNAL'}
-                    deploy_lookup[operation] = self
+                    deploy_lookup[operation.name] = self
                 else:
                     sd_config = {'config': {'get_resource': config_name},
                                  'server': {'get_resource':
@@ -168,7 +160,7 @@ class HotResource(object):
                                     'OS::Heat::SoftwareDeployment',
                                     sd_config)
                     hot_resources.append(deploy_resource)
-                    deploy_lookup[operation] = deploy_resource
+                    deploy_lookup[operation.name] = deploy_resource
                 lifecycle_inputs = self._get_lifecycle_inputs(operation)
                 if lifecycle_inputs:
                     deploy_resource.properties['input_values'] = \
@@ -178,34 +170,24 @@ class HotResource(object):
         # in operations_deploy_sequence
         # TODO(anyone): find some better way to encode this implicit sequence
         group = {}
-        op_index_max = -1
         for op, hot in deploy_lookup.items():
             # position to determine potential preceding nodes
-            op_index = operations_deploy_sequence.index(op.name)
-            if op_index > op_index_max:
-                op_index_max = op_index
-            for preceding_op_name in \
+            op_index = operations_deploy_sequence.index(op)
+            for preceding_op in \
                     reversed(operations_deploy_sequence[:op_index]):
-                preceding_hot = deploy_lookup.get(
-                    operations.get(preceding_op_name))
+                preceding_hot = deploy_lookup.get(preceding_op)
                 if preceding_hot:
                     hot.depends_on.append(preceding_hot)
                     hot.depends_on_nodes.append(preceding_hot)
                     group[preceding_hot] = hot
                     break
 
-        if op_index_max >= 0:
-            last_deploy = deploy_lookup.get(operations.get(
-                operations_deploy_sequence[op_index_max]))
-        else:
-            last_deploy = None
-
         # save this dependency chain in the set of HOT resources
         self.group_dependencies.update(group)
         for hot in hot_resources:
             hot.group_dependencies.update(group)
 
-        return hot_resources, deploy_lookup, last_deploy
+        return hot_resources
 
     def handle_connectsto(self, tosca_source, tosca_target, hot_source,
                           hot_target, config_location, operation):
@@ -353,7 +335,7 @@ class HotResource(object):
         return tosca_props
 
     @staticmethod
-    def get_all_operations(node):
+    def _get_all_operations(node):
         operations = {}
         for operation in node.interfaces:
             operations[operation.name] = operation
index 0403562..4263c4d 100644 (file)
@@ -77,7 +77,6 @@ class HotTemplate(object):
         dict_output.update({self.OUTPUTS: all_outputs})
 
         yaml.add_representer(OrderedDict, self.represent_ordereddict)
-        yaml.add_representer(dict, self.represent_ordereddict)
         yaml_string = yaml.dump(dict_output, default_flow_style=False)
         # get rid of the '' from yaml.dump around numbers
         yaml_string = yaml_string.replace('\'', '')
index 743074b..408ee8b 100644 (file)
@@ -16,6 +16,7 @@ from mock import patch
 
 from toscaparser.nodetemplate import NodeTemplate
 from toscaparser.tests.base import TestCase
+from toscaparser.utils.gettextutils import _
 import toscaparser.utils.yamlparser
 from translator.hot.tosca.tosca_compute import ToscaCompute
 
@@ -26,12 +27,22 @@ class ToscaComputeTest(TestCase):
         nodetemplates = (toscaparser.utils.yamlparser.
                          simple_parse(tpl_snippet)['node_templates'])
         name = list(nodetemplates.keys())[0]
-        nodetemplate = NodeTemplate(name, nodetemplates)
-        nodetemplate.validate()
-        toscacompute = ToscaCompute(nodetemplate)
-        toscacompute.handle_properties()
+        try:
+            nodetemplate = NodeTemplate(name, nodetemplates)
+            nodetemplate.validate()
+            toscacompute = ToscaCompute(nodetemplate)
+            toscacompute.handle_properties()
+            if not self._compare_properties(toscacompute.properties,
+                                            expectedprops):
+                raise Exception(_("Hot Properties are not"
+                                  " same as expected properties"))
+        except Exception:
+            # for time being rethrowing. Will be handled future based
+            # on new development in Glance and Graffiti
+            raise
 
-        self.assertDictEqual(expectedprops, toscacompute.properties)
+    def _compare_properties(self, hotprops, expectedprops):
+        return all(item in hotprops.items() for item in expectedprops.items())
 
     def test_node_compute_with_host_and_os_capabilities(self):
         tpl_snippet = '''
index 924ff9d..d4b2f44 100644 (file)
@@ -67,5 +67,5 @@ class ToscaBlockStorage(HotResource):
         # attribute for the matching resource.  Unless there is additional
         # runtime support, this should be a one to one mapping.
         if attribute == 'volume_id':
-            attr['get_resource'] = self.name
+            attr['get_resource'] = args[0]
         return attr
index 2242c2d..71b9822 100644 (file)
@@ -50,4 +50,4 @@ class ToscaBlockStorageAttachment(HotResource):
             self.properties.pop('device')
 
     def handle_life_cycle(self):
-        return None, None, None
+        pass
index 16d0518..8a959d1 100644 (file)
@@ -84,14 +84,6 @@ class ToscaCompute(HotResource):
                       ('architecture', 'distribution', 'type', 'version')
     toscatype = 'tosca.nodes.Compute'
 
-    ALLOWED_NOVA_SERVER_PROPS = \
-        ('admin_pass', 'availability_zone', 'block_device_mapping',
-         'block_device_mapping_v2', 'config_drive', 'diskConfig', 'flavor',
-         'flavor_update_policy', 'image', 'image_update_policy', 'key_name',
-         'metadata', 'name', 'networks', 'personality', 'reservation_id',
-         'scheduler_hints', 'security_groups', 'software_config_transport',
-         'user_data', 'user_data_format', 'user_data_update_policy')
-
     def __init__(self, nodetemplate):
         super(ToscaCompute, self).__init__(nodetemplate,
                                            type='OS::Nova::Server')
@@ -107,8 +99,7 @@ class ToscaCompute(HotResource):
         self.properties['software_config_transport'] = 'POLL_SERVER_HEAT'
         tosca_props = self.get_tosca_props()
         for key, value in tosca_props.items():
-            if key in self.ALLOWED_NOVA_SERVER_PROPS:
-                self.properties[key] = value
+            self.properties[key] = value
 
     # To be reorganized later based on new development in Glance and Graffiti
     def translate_compute_flavor_and_image(self,
@@ -264,7 +255,7 @@ class ToscaCompute(HotResource):
         images = IMAGES
         if translator.common.utils.check_for_env_variables():
             resp = self._populate_image_dict()
-            if resp and len(resp.keys()) > 0:
+            if len(resp.keys()) > 0:
                 images = resp
         match_all = images.keys()
         architecture = properties.get(self.ARCHITECTURE)
index 4dd9556..0aefd48 100644 (file)
@@ -16,8 +16,6 @@ import logging
 import os
 import six
 
-from collections import OrderedDict
-from toscaparser.functions import Concat
 from toscaparser.functions import GetAttribute
 from toscaparser.functions import GetInput
 from toscaparser.functions import GetProperty
@@ -27,7 +25,6 @@ from toscaparser.utils.gettextutils import _
 from translator.common.exception import ToscaClassAttributeError
 from translator.common.exception import ToscaClassImportError
 from translator.common.exception import ToscaModImportError
-from translator.common import utils
 from translator.conf.config import ConfigProvider as translatorConfig
 from translator.hot.syntax.hot_resource import HotResource
 from translator.hot.tosca.tosca_block_storage_attachment import (
@@ -135,8 +132,6 @@ log = logging.getLogger('heat-translator')
 
 TOSCA_TO_HOT_TYPE = _generate_type_map()
 
-BASE_TYPES = six.string_types + six.integer_types + (dict, OrderedDict)
-
 
 class TranslateNodeTemplates(object):
     '''Translate TOSCA NodeTemplates to Heat Resources.'''
@@ -151,9 +146,6 @@ class TranslateNodeTemplates(object):
         log.debug(_('Mapping between TOSCA nodetemplate and HOT resource.'))
         self.hot_lookup = {}
         self.policies = self.tosca.topology_template.policies
-        # stores the last deploy of generated behavior for a resource
-        # useful to satisfy underlying dependencies between interfaces
-        self.last_deploy_map = {}
 
     def translate(self):
         return self._translate_nodetemplates()
@@ -231,14 +223,9 @@ class TranslateNodeTemplates(object):
         # into multiple HOT resources and may change their name
         lifecycle_resources = []
         for resource in self.hot_resources:
-            expanded_resources, deploy_lookup, last_deploy = resource.\
-                handle_life_cycle()
-            if expanded_resources:
-                lifecycle_resources += expanded_resources
-            if deploy_lookup:
-                self.hot_lookup.update(deploy_lookup)
-            if last_deploy:
-                self.last_deploy_map[resource] = last_deploy
+            expanded = resource.handle_life_cycle()
+            if expanded:
+                lifecycle_resources += expanded
         self.hot_resources += lifecycle_resources
 
         # Handle configuration from ConnectsTo relationship in the TOSCA node:
@@ -270,9 +257,7 @@ class TranslateNodeTemplates(object):
                 # if the source of dependency is a server and the
                 # relationship type is 'tosca.relationships.HostedOn',
                 # add dependency as properties.server
-                base_type = HotResource.get_base_type(
-                    node_depend.type_definition)
-                if base_type.type == 'tosca.nodes.Compute' and \
+                if node_depend.type == 'tosca.nodes.Compute' and \
                    node.related[node_depend].type == \
                    node.type_definition.HOSTEDON:
                     self.hot_lookup[node].properties['server'] = \
@@ -285,13 +270,6 @@ class TranslateNodeTemplates(object):
                 self.hot_lookup[node].depends_on_nodes.append(
                     self.hot_lookup[node_depend].top_of_chain())
 
-                last_deploy = self.last_deploy_map.get(
-                    self.hot_lookup[node_depend])
-                if last_deploy and \
-                    last_deploy not in self.hot_lookup[node].depends_on:
-                    self.hot_lookup[node].depends_on.append(last_deploy)
-                    self.hot_lookup[node].depends_on_nodes.append(last_deploy)
-
         # handle hosting relationship
         for resource in self.hot_resources:
             resource.handle_hosting()
@@ -321,202 +299,53 @@ class TranslateNodeTemplates(object):
             inputs = resource.properties.get('input_values')
             if inputs:
                 for name, value in six.iteritems(inputs):
-                    inputs[name] = self.translate_param_value(value, resource)
-
-        # remove resources without type defined
-        # for example a SoftwareComponent without interfaces
-        # would fall in this case
-        to_remove = []
-        for resource in self.hot_resources:
-            if resource.type is None:
-                to_remove.append(resource)
-
-        for resource in to_remove:
-            self.hot_resources.remove(resource)
+                    inputs[name] = self._translate_input(value, resource)
 
         return self.hot_resources
 
-    def translate_param_value(self, param_value, resource):
-        tosca_template = None
-        if resource:
-            tosca_template = resource.nodetemplate
-
+    def _translate_input(self, input_value, resource):
         get_property_args = None
-        if isinstance(param_value, GetProperty):
-            get_property_args = param_value.args
+        if isinstance(input_value, GetProperty):
+            get_property_args = input_value.args
         # to remove when the parser is fixed to return GetProperty
-        elif isinstance(param_value, dict) and 'get_property' in param_value:
-            get_property_args = param_value['get_property']
+        if isinstance(input_value, dict) and 'get_property' in input_value:
+            get_property_args = input_value['get_property']
         if get_property_args is not None:
-            tosca_target, prop_name, prop_arg = \
-                self.decipher_get_operation(get_property_args,
-                                            tosca_template)
-            if tosca_target:
-                prop_value = tosca_target.get_property_value(prop_name)
-                if prop_value:
-                    prop_value = self.translate_param_value(
-                        prop_value, resource)
-                    return self._unfold_value(prop_value, prop_arg)
-        get_attr_args = None
-        if isinstance(param_value, GetAttribute):
-            get_attr_args = param_value.result().args
-        # to remove when the parser is fixed to return GetAttribute
-        elif isinstance(param_value, dict) and 'get_attribute' in param_value:
-            get_attr_args = param_value['get_attribute']
-        if get_attr_args is not None:
+            hot_target = self._find_hot_resource_for_tosca(
+                get_property_args[0], resource)
+            if hot_target:
+                props = hot_target.get_tosca_props()
+                prop_name = get_property_args[1]
+                if prop_name in props:
+                    return props[prop_name]
+        elif isinstance(input_value, GetAttribute):
             # for the attribute
             # get the proper target type to perform the translation
-            tosca_target, attr_name, attr_arg = \
-                self.decipher_get_operation(get_attr_args, tosca_template)
-            attr_args = []
-            if attr_arg:
-                attr_args += attr_arg
-            if tosca_target:
-                if tosca_target in self.hot_lookup:
-                    attr_value = self.hot_lookup[tosca_target].\
-                        get_hot_attribute(attr_name, attr_args)
-                    attr_value = self.translate_param_value(
-                        attr_value, resource)
-                    return self._unfold_value(attr_value, attr_arg)
-        elif isinstance(param_value, dict) and 'get_artifact' in param_value:
-            get_artifact_args = param_value['get_artifact']
-            tosca_target, artifact_name, _ = \
-                self.decipher_get_operation(get_artifact_args,
-                                            tosca_template)
-
-            if tosca_target:
-                artifacts = self.get_all_artifacts(tosca_target)
-                if artifact_name in artifacts:
-                    artifact = artifacts[artifact_name]
-                    if artifact.get('type', None) == 'tosca.artifacts.File':
-                        return {'get_file': artifact.get('file')}
-        get_input_args = None
-        if isinstance(param_value, GetInput):
-            get_input_args = param_value.args
-        elif isinstance(param_value, dict) and 'get_input' in param_value:
-            get_input_args = param_value['get_input']
-        if get_input_args is not None:
-            if isinstance(get_input_args, list) \
-                    and len(get_input_args) == 1:
-                return {'get_param': self.translate_param_value(
-                    get_input_args[0], resource)}
-            else:
-                return {'get_param': self.translate_param_value(
-                    get_input_args, resource)}
-        elif isinstance(param_value, dict) \
-                and 'get_operation_output' in param_value:
-            res = self._translate_get_operation_output_function(
-                param_value['get_operation_output'], tosca_template)
-            if res:
-                return res
-        concat_list = None
-        if isinstance(param_value, Concat):
-            concat_list = param_value.args
-        elif isinstance(param_value, dict) and 'concat' in param_value:
-            concat_list = param_value['concat']
-        if concat_list is not None:
-            res = self._translate_concat_function(concat_list, resource)
-            if res:
-                return res
-
-        if isinstance(param_value, list):
-            translated_list = []
-            for elem in param_value:
-                translated_elem = self.translate_param_value(elem, resource)
-                if translated_elem:
-                    translated_list.append(translated_elem)
-            return translated_list
-
-        if isinstance(param_value, BASE_TYPES):
-            return param_value
-
-        return None
-
-    def _translate_concat_function(self, concat_list, resource):
-        str_replace_template = ''
-        str_replace_params = {}
-        index = 0
-        for elem in concat_list:
-            str_replace_template += '$s' + str(index)
-            str_replace_params['$s' + str(index)] = \
-                self.translate_param_value(elem, resource)
-            index += 1
-
-        return {'str_replace': {
-            'template': str_replace_template,
-            'params': str_replace_params
-        }}
-
-    def _translate_get_operation_output_function(self, args, tosca_template):
-        tosca_target = self._find_tosca_node(args[0],
-                                             tosca_template)
-        if tosca_target and len(args) >= 4:
-            operations = HotResource.get_all_operations(tosca_target)
-            # ignore Standard interface name,
-            # it is the only one supported in the translator anyway
-            op_name = args[2]
-            output_name = args[3]
-            if op_name in operations:
-                operation = operations[op_name]
-                if operation in self.hot_lookup:
-                    matching_deploy = self.hot_lookup[operation]
-                    matching_config_name = matching_deploy.\
-                        properties['config']['get_resource']
-                    matching_config = self.find_hot_resource(
-                        matching_config_name)
-                    if matching_config:
-                        outputs = matching_config.properties.get('outputs')
-                        if outputs is None:
-                            outputs = []
-                        outputs.append({'name': output_name})
-                        matching_config.properties['outputs'] = outputs
-                    return {'get_attr': [
-                        matching_deploy.name,
-                        output_name
-                    ]}
-
-    @staticmethod
-    def _unfold_value(value, value_arg):
-        if value_arg is not None:
-            if isinstance(value, dict):
-                val = value.get(value_arg)
-                if val is not None:
-                    return val
-
-            index = utils.str_to_num(value_arg)
-            if isinstance(value, list) and index is not None:
-                return value[index]
-        return value
-
-    def decipher_get_operation(self, args, current_tosca_node):
-        tosca_target = self._find_tosca_node(args[0],
-                                             current_tosca_node)
-        new_target = None
-        if tosca_target and len(args) > 2:
-            cap_or_req_name = args[1]
-            cap = tosca_target.get_capability(cap_or_req_name)
-            if cap:
-                new_target = cap
+            args = input_value.result().args
+            hot_target = self._find_hot_resource_for_tosca(args[0], resource)
+
+            return hot_target.get_hot_attribute(args[1], args)
+        # most of artifacts logic should move to the parser
+        elif isinstance(input_value, dict) and 'get_artifact' in input_value:
+            get_artifact_args = input_value['get_artifact']
+
+            hot_target = self._find_hot_resource_for_tosca(
+                get_artifact_args[0], resource)
+            artifacts = TranslateNodeTemplates.get_all_artifacts(
+                hot_target.nodetemplate)
+
+            if get_artifact_args[1] in artifacts:
+                artifact = artifacts[get_artifact_args[1]]
+                if artifact.get('type', None) == 'tosca.artifacts.File':
+                    return {'get_file': artifact.get('file')}
+        elif isinstance(input_value, GetInput):
+            if isinstance(input_value.args, list) \
+                    and len(input_value.args) == 1:
+                return {'get_param': input_value.args[0]}
             else:
-                for req in tosca_target.requirements:
-                    if cap_or_req_name in req:
-                        new_target = self._find_tosca_node(
-                            req[cap_or_req_name])
-                        cap = new_target.get_capability(cap_or_req_name)
-                        if cap:
-                            new_target = cap
-                        break
-
-        if new_target:
-            tosca_target = new_target
-
-            prop_name = args[2]
-            prop_arg = args[3] if len(args) >= 4 else None
-        else:
-            prop_name = args[1]
-            prop_arg = args[2] if len(args) >= 3 else None
+                return {'get_param': input_value.args}
 
-        return tosca_target, prop_name, prop_arg
+        return input_value
 
     @staticmethod
     def get_all_artifacts(nodetemplate):
@@ -591,29 +420,23 @@ class TranslateNodeTemplates(object):
             if resource.name == name:
                 return resource
 
-    def _find_tosca_node(self, tosca_name, current_tosca_template=None):
-        tosca_node = None
-        if tosca_name == 'SELF':
-            tosca_node = current_tosca_template
-        if tosca_name == 'HOST' and current_tosca_template:
-            for req in current_tosca_template.requirements:
-                if 'host' in req:
-                    tosca_node = self._find_tosca_node(req['host'])
-
-        if tosca_node is None:
-            for node in self.nodetemplates:
-                if node.name == tosca_name:
-                    tosca_node = node
-                    break
-        return tosca_node
+    def _find_tosca_node(self, tosca_name):
+        for node in self.nodetemplates:
+            if node.name == tosca_name:
+                return node
 
     def _find_hot_resource_for_tosca(self, tosca_name,
                                      current_hot_resource=None):
-        current_tosca_resource = current_hot_resource.nodetemplate \
-            if current_hot_resource else None
-        tosca_node = self._find_tosca_node(tosca_name, current_tosca_resource)
-        if tosca_node:
-            return self.hot_lookup[tosca_node]
+        if tosca_name == 'SELF':
+            return current_hot_resource
+        if tosca_name == 'HOST' and current_hot_resource is not None:
+            for req in current_hot_resource.nodetemplate.requirements:
+                if 'host' in req:
+                    return self._find_hot_resource_for_tosca(req['host'])
+
+        for node in self.nodetemplates:
+            if node.name == tosca_name:
+                return self.hot_lookup[node]
 
         return None
 
index 87ec02a..4197cdd 100644 (file)
@@ -33,8 +33,16 @@ class TranslateOutputs(object):
     def _translate_outputs(self):
         hot_outputs = []
         for output in self.outputs:
-            hot_value = self.nodes.translate_param_value(output.value, None)
-            if hot_value is not None:
-                hot_outputs.append(HotOutput(output.name, hot_value,
+            if output.value.name == 'get_attribute':
+                get_parameters = output.value.args
+                hot_target = self.nodes.find_hot_resource(get_parameters[0])
+                hot_value = hot_target.get_hot_attribute(get_parameters[1],
+                                                         get_parameters)
+                hot_outputs.append(HotOutput(output.name,
+                                             hot_value,
+                                             output.description))
+            else:
+                hot_outputs.append(HotOutput(output.name,
+                                             output.value,
                                              output.description))
         return hot_outputs
index 3e69d7a..bd98904 100644 (file)
@@ -23,48 +23,35 @@ from translator.tests.base import TestCase
 
 class ToscaHotTranslationTest(TestCase):
 
-    def _test_successful_translation(self, tosca_file, hot_file, params=None):
-        if not params:
-            params = {}
+    def test_hot_translate_single_server(self):
+        tosca_file = '../tests/data/tosca_single_server.yaml'
+        hot_file = '../tests/data/hot_output/hot_single_server.yaml'
+        params = {'cpus': 1}
         diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
                                                                    hot_file,
                                                                    params)
         self.assertEqual({}, diff, '<difference> : ' +
                          json.dumps(diff, indent=4, separators=(', ', ': ')))
 
-    def _test_failed_translation(self, tosca_file, hot_file, params, msg,
-                                 msg_path, error_raise, error_collect):
-        if msg_path:
-            path = os.path.normpath(os.path.join(
-                os.path.dirname(os.path.realpath(__file__)), tosca_file))
-            msg = msg % path
-        self.assertRaises(
-            error_raise,
-            TranslationUtils.compare_tosca_translation_with_hot,
-            tosca_file, hot_file, params)
-        ExceptionCollector.assertExceptionMessage(error_collect, msg)
-
-    def test_hot_translate_single_server(self):
-        tosca_file = '../tests/data/tosca_single_server.yaml'
-        hot_file = '../tests/data/hot_output/hot_single_server.yaml'
-        params = {'cpus': 1}
-        self._test_successful_translation(tosca_file, hot_file, params)
-
     def test_hot_translate_single_server_with_defaults(self):
         tosca_file = \
             '../tests/data/tosca_single_server_with_defaults.yaml'
-
         hot_file_with_input = '../tests/data/hot_output/' \
             'hot_single_server_with_defaults_with_input.yaml'
-        params1 = {'cpus': '1'}
-        self._test_successful_translation(tosca_file, hot_file_with_input,
-                                          params1)
-
         hot_file_without_input = '../tests/data/hot_output/' \
             'hot_single_server_with_defaults_without_input.yaml'
+
+        params1 = {'cpus': '1'}
+        diff1 = TranslationUtils.compare_tosca_translation_with_hot(
+            tosca_file, hot_file_with_input, params1)
+        self.assertEqual({}, diff1, '<difference> : ' +
+                         json.dumps(diff1, indent=4, separators=(', ', ': ')))
+
         params2 = {}
-        self._test_successful_translation(tosca_file, hot_file_without_input,
-                                          params2)
+        diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+            tosca_file, hot_file_without_input, params2)
+        self.assertEqual({}, diff2, '<difference> : ' +
+                         json.dumps(diff2, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_wordpress_single_instance(self):
         tosca_file = '../tests/data/tosca_single_instance_wordpress.yaml'
@@ -76,17 +63,29 @@ class ToscaHotTranslationTest(TestCase):
                   'db_root_pwd': 'passw0rd',
                   'db_port': 3366,
                   'cpus': 8}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_helloworld(self):
         tosca_file = '../tests/data/tosca_helloworld.yaml'
         hot_file = '../tests/data/hot_output/hot_hello_world.yaml'
-        self._test_successful_translation(tosca_file, hot_file)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   {})
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_host_assignment(self):
         tosca_file = '../tests/data/test_host_assignment.yaml'
         hot_file = '../tests/data/hot_output/hot_host_assignment.yaml'
-        self._test_successful_translation(tosca_file, hot_file)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   {})
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_elk(self):
         tosca_file = '../tests/data/tosca_elk.yaml'
@@ -94,7 +93,11 @@ class ToscaHotTranslationTest(TestCase):
         params = {'github_url':
                   'http://github.com/paypal/rest-api-sample-app-nodejs.git',
                   'my_cpus': 4}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_nodejs_mongodb_two_instances(self):
         tosca_file = '../tests/data/tosca_nodejs_mongodb_two_instances.yaml'
@@ -103,7 +106,11 @@ class ToscaHotTranslationTest(TestCase):
         params = {'github_url':
                   'http://github.com/paypal/rest-api-sample-app-nodejs.git',
                   'my_cpus': 4}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_blockstorage_with_attachment(self):
         tosca_file = '../tests/data/storage/' \
@@ -114,7 +121,11 @@ class ToscaHotTranslationTest(TestCase):
                   'storage_location': '/dev/vdc',
                   'storage_size': '2000 MB',
                   'storage_snapshot_id': 'ssid'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_blockstorage_with_custom_relationship_type(self):
         tosca_file = '../tests/data/storage/' \
@@ -125,7 +136,11 @@ class ToscaHotTranslationTest(TestCase):
                   'storage_location': '/dev/vdc',
                   'storage_size': '1 GB',
                   'storage_snapshot_id': 'ssid'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_blockstorage_with_relationship_template(self):
         tosca_file = '../tests/data/storage/' \
@@ -135,7 +150,11 @@ class ToscaHotTranslationTest(TestCase):
         params = {'cpus': 1,
                   'storage_location': '/dev/vdc',
                   'storage_size': '1 GB'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_blockstorage_with_attachment_notation1(self):
         tosca_file = '../tests/data/storage/' \
@@ -148,11 +167,19 @@ class ToscaHotTranslationTest(TestCase):
                   'storage_location': 'some_folder',
                   'storage_size': '1 GB',
                   'storage_snapshot_id': 'ssid'}
-
+        diff1 = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                    hot_file1,
+                                                                    params)
         try:
-            self._test_successful_translation(tosca_file, hot_file1, params)
+            self.assertEqual({}, diff1, '<difference> : ' +
+                             json.dumps(diff1, indent=4,
+                                        separators=(', ', ': ')))
         except Exception:
-            self._test_successful_translation(tosca_file, hot_file2, params)
+            diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+                tosca_file, hot_file2, params)
+            self.assertEqual({}, diff2, '<difference> : ' +
+                             json.dumps(diff2, indent=4,
+                                        separators=(', ', ': ')))
 
     def test_hot_translate_blockstorage_with_attachment_notation2(self):
         tosca_file = '../tests/data/storage/' \
@@ -165,10 +192,19 @@ class ToscaHotTranslationTest(TestCase):
                   'storage_location': '/dev/vdc',
                   'storage_size': '1 GB',
                   'storage_snapshot_id': 'ssid'}
+        diff1 = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                    hot_file1,
+                                                                    params)
         try:
-            self._test_successful_translation(tosca_file, hot_file1, params)
+            self.assertEqual({}, diff1, '<difference> : ' +
+                             json.dumps(diff1, indent=4,
+                                        separators=(', ', ': ')))
         except Exception:
-            self._test_successful_translation(tosca_file, hot_file2, params)
+            diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+                tosca_file, hot_file2, params)
+            self.assertEqual({}, diff2, '<difference> : ' +
+                             json.dumps(diff2, indent=4,
+                                        separators=(', ', ': ')))
 
     def test_hot_translate_multiple_blockstorage_with_attachment(self):
         tosca_file = '../tests/data/storage/' \
@@ -181,23 +217,40 @@ class ToscaHotTranslationTest(TestCase):
                   'storage_location': '/dev/vdc',
                   'storage_size': '1 GB',
                   'storage_snapshot_id': 'ssid'}
+        diff1 = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                    hot_file1,
+                                                                    params)
         try:
-            self._test_successful_translation(tosca_file, hot_file1, params)
+            self.assertEqual({}, diff1, '<difference> : ' +
+                             json.dumps(diff1, indent=4,
+                                        separators=(', ', ': ')))
         except Exception:
-            self._test_successful_translation(tosca_file, hot_file2, params)
+            diff2 = TranslationUtils.compare_tosca_translation_with_hot(
+                tosca_file, hot_file2, params)
+            self.assertEqual({}, diff2, '<difference> : ' +
+                             json.dumps(diff2, indent=4,
+                                        separators=(', ', ': ')))
 
     def test_hot_translate_single_object_store(self):
         tosca_file = '../tests/data/storage/tosca_single_object_store.yaml'
         hot_file = '../tests/data/hot_output/hot_single_object_store.yaml'
         params = {'objectstore_name': 'myobjstore'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_one_server_one_network(self):
         tosca_file = '../tests/data/network/tosca_one_server_one_network.yaml'
         hot_file = '../tests/data/hot_output/network/' \
                    'hot_one_server_one_network.yaml'
         params = {'network_name': 'private_net'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_server_on_existing_network(self):
         tosca_file = '../tests/data/network/' \
@@ -205,7 +258,11 @@ class ToscaHotTranslationTest(TestCase):
         hot_file = '../tests/data/hot_output/network/' \
                    'hot_server_on_existing_network.yaml'
         params = {'network_name': 'private_net'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_two_servers_one_network(self):
         tosca_file = '../tests/data/network/tosca_two_servers_one_network.yaml'
@@ -215,7 +272,11 @@ class ToscaHotTranslationTest(TestCase):
                   'network_cidr': '10.0.0.0/24',
                   'network_start_ip': '10.0.0.100',
                   'network_end_ip': '10.0.0.150'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_one_server_three_networks(self):
         tosca_file = '../tests/data/network/' \
@@ -223,20 +284,32 @@ class ToscaHotTranslationTest(TestCase):
         hot_file = '../tests/data/hot_output/network/' \
                    'hot_one_server_three_networks.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_software_component(self):
         tosca_file = '../tests/data/tosca_software_component.yaml'
         hot_file = '../tests/data/hot_output/hot_software_component.yaml'
         params = {'cpus': '1',
                   'download_url': 'http://www.software.com/download'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_web_application(self):
         tosca_file = '../tests/data/tosca_web_application.yaml'
         hot_file = '../tests/data/hot_output/hot_web_application.yaml'
         params = {'cpus': '2', 'context_root': 'my_web_app'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_template_with_url_import(self):
         tosca_file = '../tests/data/' \
@@ -249,7 +322,11 @@ class ToscaHotTranslationTest(TestCase):
                   'db_root_pwd': 'passw0rd',
                   'db_port': 3366,
                   'cpus': 8}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_template_by_url_with_local_import(self):
         tosca_file = 'https://raw.githubusercontent.com/openstack/' \
@@ -263,7 +340,11 @@ class ToscaHotTranslationTest(TestCase):
                   'db_root_pwd': 'passw0rd',
                   'db_port': 3366,
                   'cpus': 8}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_template_by_url_with_local_abspath_import(self):
         tosca_file = 'https://raw.githubusercontent.com/openstack/' \
@@ -278,15 +359,17 @@ class ToscaHotTranslationTest(TestCase):
                   'db_root_pwd': 'passw0rd',
                   'db_port': 3366,
                   'cpus': 8}
+
+        self.assertRaises(
+            ValidationError,
+            TranslationUtils.compare_tosca_translation_with_hot,
+            tosca_file, hot_file, params)
         expected_msg = _('Absolute file name "/tmp/wordpress.yaml" cannot be '
                          'used in a URL-based input template "https://raw.'
                          'githubusercontent.com/openstack/heat-translator/'
                          'master/translator/tests/data/tosca_single_instance_'
                          'wordpress_with_local_abspath_import.yaml".')
-        msg_path = False
-        self._test_failed_translation(tosca_file, hot_file, params,
-                                      expected_msg, msg_path, ValidationError,
-                                      ImportError)
+        ExceptionCollector.assertExceptionMessage(ImportError, expected_msg)
 
     def test_hot_translate_template_by_url_with_url_import(self):
         tosca_url = 'https://raw.githubusercontent.com/openstack/' \
@@ -300,12 +383,20 @@ class ToscaHotTranslationTest(TestCase):
                   'db_root_pwd': 'passw0rd',
                   'db_port': 3366,
                   'cpus': 8}
-        self._test_successful_translation(tosca_url, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_url,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_translate_hello_world_csar(self):
         tosca_file = '../tests/data/csar_hello_world.zip'
         hot_file = '../tests/data/hot_output/hot_hello_world.yaml'
-        self._test_successful_translation(tosca_file, hot_file)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   {})
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_translate_single_instance_wordpress_csar(self):
         tosca_file = '../tests/data/csar_single_instance_wordpress.zip'
@@ -317,7 +408,11 @@ class ToscaHotTranslationTest(TestCase):
                   'db_root_pwd': 'passw0rd',
                   'db_port': 3366,
                   'cpus': 8}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_translate_elk_csar_from_url(self):
         tosca_file = 'https://github.com/openstack/heat-translator/raw/' \
@@ -326,103 +421,150 @@ class ToscaHotTranslationTest(TestCase):
         params = {'github_url':
                   'http://github.com/paypal/rest-api-sample-app-nodejs.git',
                   'my_cpus': 4}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_translate_csar_not_zip(self):
         tosca_file = '../tests/data/csar_not_zip.zip'
         hot_file = ''
         params = {}
-        expected_msg = _('"%s" is not a valid zip file.')
-        msg_path = True
-        self._test_failed_translation(tosca_file, hot_file, params,
-                                      expected_msg, msg_path, ValidationError,
-                                      ValidationError)
+
+        self.assertRaises(
+            ValidationError,
+            TranslationUtils.compare_tosca_translation_with_hot,
+            tosca_file, hot_file, params)
+        path = os.path.normpath(os.path.join(
+            os.path.dirname(os.path.realpath(__file__)), tosca_file))
+        expected_msg = _('"%s" is not a valid zip file.') % path
+        ExceptionCollector.assertExceptionMessage(ValidationError,
+                                                  expected_msg)
 
     def test_translate_csar_metadata_not_yaml(self):
         tosca_file = '../tests/data/csar_metadata_not_yaml.zip'
         hot_file = ''
         params = {}
+
+        self.assertRaises(
+            ValidationError,
+            TranslationUtils.compare_tosca_translation_with_hot,
+            tosca_file, hot_file, params)
+        path = os.path.normpath(os.path.join(
+            os.path.dirname(os.path.realpath(__file__)), tosca_file))
         expected_msg = _('The file "TOSCA-Metadata/TOSCA.meta" in the CSAR '
-                         '"%s" does not contain valid YAML content.')
-        msg_path = True
-        self._test_failed_translation(tosca_file, hot_file, params,
-                                      expected_msg, msg_path, ValidationError,
-                                      ValidationError)
+                         '"%s" does not contain valid YAML content.') % path
+        ExceptionCollector.assertExceptionMessage(ValidationError,
+                                                  expected_msg)
 
     def test_translate_csar_wrong_metadata_file(self):
         tosca_file = '../tests/data/csar_wrong_metadata_file.zip'
         hot_file = ''
         params = {}
+
+        self.assertRaises(
+            ValidationError,
+            TranslationUtils.compare_tosca_translation_with_hot,
+            tosca_file, hot_file, params)
+        path = os.path.normpath(os.path.join(
+            os.path.dirname(os.path.realpath(__file__)), tosca_file))
         expected_msg = _('"%s" is not a valid CSAR as it does not contain the '
                          'required file "TOSCA.meta" in the folder '
-                         '"TOSCA-Metadata".')
-        msg_path = True
-        self._test_failed_translation(tosca_file, hot_file, params,
-                                      expected_msg, msg_path, ValidationError,
-                                      ValidationError)
+                         '"TOSCA-Metadata".') % path
+        ExceptionCollector.assertExceptionMessage(ValidationError,
+                                                  expected_msg)
 
     def test_translate_csar_wordpress_invalid_import_path(self):
         tosca_file = '../tests/data/csar_wordpress_invalid_import_path.zip'
         hot_file = ''
         params = {}
+
+        self.assertRaises(
+            ValidationError,
+            TranslationUtils.compare_tosca_translation_with_hot,
+            tosca_file, hot_file, params)
         expected_msg = _('Import '
                          '"Invalid_import_path/wordpress.yaml" is not valid.')
-        msg_path = False
-        self._test_failed_translation(tosca_file, hot_file, params,
-                                      expected_msg, msg_path, ValidationError,
-                                      ImportError)
+        ExceptionCollector.assertExceptionMessage(ImportError, expected_msg)
 
     def test_translate_csar_wordpress_invalid_script_url(self):
         tosca_file = '../tests/data/csar_wordpress_invalid_script_url.zip'
         hot_file = ''
         params = {}
+
+        self.assertRaises(
+            ValidationError,
+            TranslationUtils.compare_tosca_translation_with_hot,
+            tosca_file, hot_file, params)
         expected_msg = _('The resource at '
                          '"https://raw.githubusercontent.com/openstack/'
                          'heat-translator/master/translator/tests/data/'
                          'custom_types/wordpress1.yaml" cannot be accessed.')
-        msg_path = False
-        self._test_failed_translation(tosca_file, hot_file, params,
-                                      expected_msg, msg_path, ValidationError,
-                                      URLException)
+        ExceptionCollector.assertExceptionMessage(URLException, expected_msg)
 
     def test_hot_translate_flavor_image(self):
         tosca_file = '../tests/data/test_tosca_flavor_and_image.yaml'
         hot_file = '../tests/data/hot_output/hot_flavor_and_image.yaml'
-        self._test_successful_translation(tosca_file, hot_file)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   {})
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_flavor_image_params(self):
         tosca_file = '../tests/data/test_tosca_flavor_and_image.yaml'
         hot_file = '../tests/data/hot_output/hot_flavor_and_image_params.yaml'
         params = {'key_name': 'paramkey'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_custom_type(self):
         tosca_file = '../tests/data/test_tosca_custom_type.yaml'
         hot_file = '../tests/data/hot_output/' \
             'hot_custom_type.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_custom_type_with_override(self):
         tosca_file = '../tests/data/test_tosca_custom_type_with_override.yaml'
         hot_file = '../tests/data/hot_output/' \
             'hot_custom_type_with_override.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_custom_type_with_param_override(self):
         tosca_file = '../tests/data/test_tosca_custom_type_with_override.yaml'
         hot_file = '../tests/data/hot_output/' \
             'hot_custom_type_with_param_override.yaml'
         params = {'install_path': '/home/custom/from/cli'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_artifact(self):
         tosca_file = '../tests/data/test_tosca_artifact.yaml'
         hot_file = '../tests/data/hot_output/' \
             'hot_artifact.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_without_tosca_os_version(self):
         tosca_file = '../tests/data/' \
@@ -430,13 +572,21 @@ class ToscaHotTranslationTest(TestCase):
         hot_file = '../tests/data/hot_output/' \
             'hot_single_server_without_tosca_os_version.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_helloworld_with_userkey(self):
         tosca_file = '../tests/data/tosca_helloworld.yaml'
         hot_file = '../tests/data/hot_output/hot_hello_world_userkey.yaml'
         params = {'key_name': 'userkey'}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_custom_networks_nodes_inline(self):
         tosca_file = '../tests/data/network/' \
@@ -444,7 +594,11 @@ class ToscaHotTranslationTest(TestCase):
         hot_file = '../tests/data/hot_output/network/' \
                    'hot_custom_network_nodes.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_custom_networks_nodes_imports(self):
         tosca_file = '../tests/data/network/' \
@@ -452,46 +606,38 @@ class ToscaHotTranslationTest(TestCase):
         hot_file = '../tests/data/hot_output/network/' \
                    'hot_custom_network_nodes.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_nfv_sample(self):
         tosca_file = '../tests/data/test_tosca_nfv_sample.yaml'
         hot_file = '../tests/data/hot_output/hot_nfv_sample.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
-
-    def test_hot_translate_nfv_vRNC(self):
-        tosca_file = "../tests/data/vRNC/Definitions/vRNC.yaml"
-        hot_file = '../tests/data/hot_output/hot_vRNC.yaml'
-        params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_translate_policy(self):
         tosca_file = '../tests/data/tosca_policies.yaml'
         hot_file = '../tests/data/hot_output/hot_policies.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
 
     def test_hot_script_types(self):
         tosca_file = '../tests/data/test_tosca_script_types.yaml'
         hot_file = '../tests/data/hot_output/hot_script_types.yaml'
         params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
-
-    def test_hot_interface_on_compute(self):
-        tosca_file = '../tests/data/test_tosca_interface_on_compute.yaml'
-        hot_file = '../tests/data/hot_output/hot_interface_on_compute.yaml'
-        params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
-
-    def test_hot_get_functions_semantic(self):
-        tosca_file = '../tests/data/test_tosca_get_functions_semantic.yaml'
-        hot_file = '../tests/data/hot_output/hot_get_functions_semantic.yaml'
-        params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
-
-    def test_hot_exchange_public_ssh_key(self):
-        tosca_file = '../tests/data/tosca_exchange_public_ssh_key.yaml'
-        hot_file = '../tests/data/hot_output/hot_exchange_public_ssh_key.yaml'
-        params = {}
-        self._test_successful_translation(tosca_file, hot_file, params)
+        diff = TranslationUtils.compare_tosca_translation_with_hot(tosca_file,
+                                                                   hot_file,
+                                                                   params)
+        self.assertEqual({}, diff, '<difference> : ' +
+                         json.dumps(diff, indent=4, separators=(', ', ': ')))
index 747d88c..c109228 100644 (file)
@@ -17,6 +17,7 @@ classifier =
     Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3.4
+    Programming Language :: Python :: 3.5
 
 [files]
 packages =
index 70a261b..1bb6623 100644 (file)
@@ -3,7 +3,6 @@
 # process, which may cause wedges in the gate later.
 hacking<0.11,>=0.10.0
 coverage>=3.6 # Apache-2.0
-discover # BSD
 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
index 34abe77..f67a277 100644 (file)
@@ -67,6 +67,11 @@ class TOSCAException(Exception):
             TOSCAException._FATAL_EXCEPTION_FORMAT_ERRORS = flag
 
 
+class UnsupportedTypeError(TOSCAException):
+    msg_fmt = _('Type "%(what)s" is valid TOSCA type'
+                ' but not supported at this time.')
+
+
 class MissingRequiredFieldError(TOSCAException):
     msg_fmt = _('%(what)s is missing required field "%(required)s".')
 
index ede5fa5..6f3b331 100644 (file)
@@ -22,685 +22,688 @@ tosca_definitions_version: tosca_simple_yaml_1_0
 # A Node Type is a reusable entity that defines the type of one or more
 # Node Templates.
 ##########################################################################
-tosca.nodes.Root:
-  description: >
-    The TOSCA root node all other TOSCA base node types derive from.
-  attributes:
-    tosca_id:
-      type: string
-    tosca_name:
-      type: string
-    state:
-      type: string
-  capabilities:
-    feature:
-      type: tosca.capabilities.Node
-  requirements:
-    - dependency:
-        capability: tosca.capabilities.Node
-        node: tosca.nodes.Root
-        relationship: tosca.relationships.DependsOn
-        occurrences: [ 0, UNBOUNDED ]
-  interfaces:
-    Standard:
-      type: tosca.interfaces.node.lifecycle.Standard
-
-tosca.nodes.Compute:
-  derived_from: tosca.nodes.Root
-  attributes:
-    private_address:
-      type: string
-    public_address:
-      type: string
-    networks:
-      type: map
-      entry_schema:
-        type: tosca.datatypes.network.NetworkInfo
-    ports:
-      type: map
-      entry_schema:
-        type: tosca.datatypes.network.PortInfo
-  capabilities:
+node_types:
+  tosca.nodes.Root:
+    description: >
+      The TOSCA root node all other TOSCA base node types derive from.
+    attributes:
+      tosca_id:
+        type: string
+      tosca_name:
+        type: string
+      state:
+        type: string
+    capabilities:
+      feature:
+        type: tosca.capabilities.Node
+    requirements:
+      - dependency:
+          capability: tosca.capabilities.Node
+          node: tosca.nodes.Root
+          relationship: tosca.relationships.DependsOn
+          occurrences: [ 0, UNBOUNDED ]
+    interfaces:
+      Standard:
+        type: tosca.interfaces.node.lifecycle.Standard
+
+  tosca.nodes.Compute:
+    derived_from: tosca.nodes.Root
+    attributes:
+      private_address:
+        type: string
+      public_address:
+        type: string
+      networks:
+        type: map
+        entry_schema:
+          type: tosca.datatypes.network.NetworkInfo
+      ports:
+        type: map
+        entry_schema:
+          type: tosca.datatypes.network.PortInfo
+    capabilities:
+        host:
+           type: tosca.capabilities.Container
+        binding:
+           type: tosca.capabilities.network.Bindable
+        os:
+           type: tosca.capabilities.OperatingSystem
+        scalable:
+           type: tosca.capabilities.Scalable
+    requirements:
+      - local_storage:
+          capability: tosca.capabilities.Attachment
+          node: tosca.nodes.BlockStorage
+          relationship: tosca.relationships.AttachesTo
+          occurrences: [0, UNBOUNDED]
+
+  tosca.nodes.SoftwareComponent:
+    derived_from: tosca.nodes.Root
+    properties:
+      # domain-specific software component version
+      component_version:
+        type: version
+        required: false
+        description: >
+          Software component version.
+      admin_credential:
+        type: tosca.datatypes.Credential
+        required: false
+    requirements:
+      - host:
+          capability: tosca.capabilities.Container
+          node: tosca.nodes.Compute
+          relationship: tosca.relationships.HostedOn
+
+  tosca.nodes.DBMS:
+    derived_from: tosca.nodes.SoftwareComponent
+    properties:
+      port:
+        required: false
+        type: integer
+        description: >
+          The port the DBMS service will listen to for data and requests.
+      root_password:
+        required: false
+        type: string
+        description: >
+          The root password for the DBMS service.
+    capabilities:
       host:
-         type: tosca.capabilities.Container
-      binding:
-         type: tosca.capabilities.network.Bindable
-      os:
-         type: tosca.capabilities.OperatingSystem
-      scalable:
-         type: tosca.capabilities.Scalable
-  requirements:
-    - local_storage:
-        capability: tosca.capabilities.Attachment
-        node: tosca.nodes.BlockStorage
-        relationship: tosca.relationships.AttachesTo
-        occurrences: [0, UNBOUNDED]
+        type: tosca.capabilities.Container
+        valid_source_types: [tosca.nodes.Database]
+
+  tosca.nodes.Database:
+    derived_from: tosca.nodes.Root
+    properties:
+      user:
+        required: false
+        type: string
+        description: >
+          User account name for DB administration
+      port:
+        required: false
+        type: integer
+        description:  >
+          The port the database service will use to listen for incoming data and
+          requests.
+      name:
+        required: false
+        type: string
+        description: >
+          The name of the database.
+      password:
+        required: false
+        type: string
+        description: >
+          The password for the DB user account
+    requirements:
+      - host:
+          capability: tosca.capabilities.Container
+          node: tosca.nodes.DBMS
+          relationship: tosca.relationships.HostedOn
+    capabilities:
+      database_endpoint:
+        type: tosca.capabilities.Endpoint.Database
+
+  tosca.nodes.WebServer:
+    derived_from: tosca.nodes.SoftwareComponent
+    capabilities:
+      data_endpoint:
+        type: tosca.capabilities.Endpoint
+      admin_endpoint:
+        type: tosca.capabilities.Endpoint.Admin
+      host:
+        type: tosca.capabilities.Container
+        valid_source_types: [tosca.nodes.WebApplication]
 
-tosca.nodes.SoftwareComponent:
-  derived_from: tosca.nodes.Root
-  properties:
-    # domain-specific software component version
-    component_version:
-      type: version
-      required: false
-      description: >
-        Software component version.
-    admin_credential:
-      type: tosca.datatypes.Credential
-      required: false
-  requirements:
-    - host:
-        capability: tosca.capabilities.Container
-        node: tosca.nodes.Compute
-        relationship: tosca.relationships.HostedOn
-
-tosca.nodes.DBMS:
-  derived_from: tosca.nodes.SoftwareComponent
-  properties:
-    port:
-      required: false
-      type: integer
-      description: >
-        The port the DBMS service will listen to for data and requests.
-    root_password:
-      required: false
-      type: string
-      description: >
-        The root password for the DBMS service.
-  capabilities:
-    host:
-      type: tosca.capabilities.Container
-      valid_source_types: [tosca.nodes.Database]
-
-tosca.nodes.Database:
-  derived_from: tosca.nodes.Root
-  properties:
-    user:
-      required: false
-      type: string
-      description: >
-        User account name for DB administration
-    port:
-      required: false
-      type: integer
-      description:  >
-        The port the database service will use to listen for incoming data and
-        requests.
-    name:
-      required: false
-      type: string
-      description: >
-        The name of the database.
-    password:
-      required: false
-      type: string
-      description: >
-        The password for the DB user account
-  requirements:
-    - host:
-        capability: tosca.capabilities.Container
-        node: tosca.nodes.DBMS
-        relationship: tosca.relationships.HostedOn
-  capabilities:
-    database_endpoint:
-      type: tosca.capabilities.Endpoint.Database
-
-tosca.nodes.WebServer:
-  derived_from: tosca.nodes.SoftwareComponent
-  capabilities:
-    data_endpoint:
-      type: tosca.capabilities.Endpoint
-    admin_endpoint:
-      type: tosca.capabilities.Endpoint.Admin
-    host:
-      type: tosca.capabilities.Container
-      valid_source_types: [tosca.nodes.WebApplication]
-
-tosca.nodes.WebApplication:
-  derived_from: tosca.nodes.Root
-  properties:
-    context_root:
-      type: string
-      required: false
-  requirements:
-    - host:
-        capability: tosca.capabilities.Container
-        node: tosca.nodes.WebServer
-        relationship: tosca.relationships.HostedOn
-  capabilities:
-    app_endpoint:
-      type: tosca.capabilities.Endpoint
-
-tosca.nodes.BlockStorage:
-  derived_from: tosca.nodes.Root
-  properties:
-    size:
-      type: scalar-unit.size
-      constraints:
-        - greater_or_equal: 1 MB
-    volume_id:
-      type: string
-      required: false
-    snapshot_id:
-      type: string
-      required: false
-  attributes:
-    volume_id:
-      type: string
-  capabilities:
-    attachment:
-      type: tosca.capabilities.Attachment
-
-tosca.nodes.network.Network:
-  derived_from: tosca.nodes.Root
-  description: >
-    The TOSCA Network node represents a simple, logical network service.
-  properties:
-    ip_version:
-      type: integer
-      required: false
-      default: 4
-      constraints:
-        - valid_values: [ 4, 6 ]
-      description: >
-        The IP version of the requested network. Valid values are 4 for ipv4
-        or 6 for ipv6.
-    cidr:
-      type: string
-      required: false
-      description: >
-        The cidr block of the requested network.
-    start_ip:
-      type: string
-      required: false
-      description: >
-         The IP address to be used as the start of a pool of addresses within
-         the full IP range derived from the cidr block.
-    end_ip:
-      type: string
-      required: false
-      description: >
-          The IP address to be used as the end of a pool of addresses within
-          the full IP range derived from the cidr block.
-    gateway_ip:
-      type: string
-      required: false
-      description: >
-         The gateway IP address.
-    network_name:
-      type: string
-      required: false
-      description: >
-         An identifier that represents an existing Network instance in the
-         underlying cloud infrastructure or can be used as the name of the
-         newly created network. If network_name is provided and no other
-         properties are provided (with exception of network_id), then an
-         existing network instance will be used. If network_name is provided
-         alongside with more properties then a new network with this name will
-         be created.
-    network_id:
-      type: string
-      required: false
-      description: >
-         An identifier that represents an existing Network instance in the
-         underlying cloud infrastructure. This property is mutually exclusive
-         with all other properties except network_name. This can be used alone
-         or together with network_name to identify an existing network.
-    segmentation_id:
-      type: string
-      required: false
-      description: >
-         A segmentation identifier in the underlying cloud infrastructure.
-         E.g. VLAN ID, GRE tunnel ID, etc..
-    network_type:
-      type: string
-      required: false
-      description: >
-         It specifies the nature of the physical network in the underlying
-         cloud infrastructure. Examples are flat, vlan, gre or vxlan.
-         For flat and vlan types, physical_network should be provided too.
-    physical_network:
-      type: string
-      required: false
-      description: >
-         It identifies the physical network on top of which the network is
-         implemented, e.g. physnet1. This property is required if network_type
-         is flat or vlan.
-    dhcp_enabled:
-      type: boolean
-      required: false
-      default: true
-      description: >
-        Indicates should DHCP service be enabled on the network or not.
-  capabilities:
-    link:
-      type: tosca.capabilities.network.Linkable
-
-tosca.nodes.network.Port:
-  derived_from: tosca.nodes.Root
-  description: >
-    The TOSCA Port node represents a logical entity that associates between
-    Compute and Network normative types. The Port node type effectively
-    represents a single virtual NIC on the Compute node instance.
-  properties:
-    ip_address:
-      type: string
-      required: false
-      description: >
-        Allow the user to set a static IP.
-    order:
-      type: integer
-      required: false
-      default: 0
-      constraints:
-        - greater_or_equal: 0
-      description: >
-        The order of the NIC on the compute instance (e.g. eth2).
-    is_default:
-      type: boolean
-      required: false
-      default: false
-      description: >
-        If is_default=true this port will be used for the default gateway
-        route. Only one port that is associated to single compute node can
-        set as is_default=true.
-    ip_range_start:
-      type: string
-      required: false
-      description: >
-        Defines the starting IP of a range to be allocated for the compute
-        instances that are associated with this Port.
-    ip_range_end:
-      type: string
-      required: false
-      description: >
-        Defines the ending IP of a range to be allocated for the compute
-        instances that are associated with this Port.
-  attributes:
-    ip_address:
-      type: string
-  requirements:
-    - binding:
-        description: >
-          Binding requirement expresses the relationship between Port and
-          Compute nodes. Effectively it indicates that the Port will be
-          attached to specific Compute node instance
-        capability: tosca.capabilities.network.Bindable
-        relationship: tosca.relationships.network.BindsTo
-        node: tosca.nodes.Compute
-    - link:
-        description: >
-          Link requirement expresses the relationship between Port and Network
-          nodes. It indicates which network this port will connect to.
-        capability: tosca.capabilities.network.Linkable
-        relationship: tosca.relationships.network.LinksTo
-        node: tosca.nodes.network.Network
-
-tosca.nodes.ObjectStorage:
-  derived_from: tosca.nodes.Root
-  description: >
-    The TOSCA ObjectStorage node represents storage that provides the ability
-    to store data as objects (or BLOBs of data) without consideration for the
-    underlying filesystem or devices
-  properties:
-    name:
-      type: string
-      required: true
-      description: >
-        The logical name of the object store (or container).
-    size:
-      type: scalar-unit.size
-      required: false
-      constraints:
-        - greater_or_equal: 0 GB
-      description: >
-        The requested initial storage size.
-    maxsize:
-      type: scalar-unit.size
-      required: false
-      constraints:
-        - greater_or_equal: 0 GB
-      description: >
-        The requested maximum storage size.
-  capabilities:
-    storage_endpoint:
-      type: tosca.capabilities.Endpoint
-
-tosca.nodes.LoadBalancer:
-  derived_from: tosca.nodes.Root
-  properties:
-    algorithm:
-      type: string
-      required: false
-      status: experimental
-  capabilities:
-    client:
-      type: tosca.capabilities.Endpoint.Public
-      occurrences: [0, UNBOUNDED]
-      description: the Floating (IP) client’s on the public network can connect to
-  requirements:
-    - application:
-        capability: tosca.capabilities.Endpoint
-        relationship: tosca.relationships.RoutesTo
+  tosca.nodes.WebApplication:
+    derived_from: tosca.nodes.Root
+    properties:
+      context_root:
+        type: string
+        required: false
+    requirements:
+      - host:
+          capability: tosca.capabilities.Container
+          node: tosca.nodes.WebServer
+          relationship: tosca.relationships.HostedOn
+    capabilities:
+      app_endpoint:
+        type: tosca.capabilities.Endpoint
+
+  tosca.nodes.BlockStorage:
+    derived_from: tosca.nodes.Root
+    properties:
+      size:
+        type: scalar-unit.size
+        constraints:
+          - greater_or_equal: 1 MB
+      volume_id:
+        type: string
+        required: false
+      snapshot_id:
+        type: string
+        required: false
+    attributes:
+      volume_id:
+        type: string
+    capabilities:
+      attachment:
+        type: tosca.capabilities.Attachment
+
+  tosca.nodes.network.Network:
+    derived_from: tosca.nodes.Root
+    description: >
+      The TOSCA Network node represents a simple, logical network service.
+    properties:
+      ip_version:
+        type: integer
+        required: false
+        default: 4
+        constraints:
+          - valid_values: [ 4, 6 ]
+        description: >
+          The IP version of the requested network. Valid values are 4 for ipv4
+          or 6 for ipv6.
+      cidr:
+        type: string
+        required: false
+        description: >
+          The cidr block of the requested network.
+      start_ip:
+        type: string
+        required: false
+        description: >
+           The IP address to be used as the start of a pool of addresses within
+           the full IP range derived from the cidr block.
+      end_ip:
+        type: string
+        required: false
+        description: >
+            The IP address to be used as the end of a pool of addresses within
+            the full IP range derived from the cidr block.
+      gateway_ip:
+        type: string
+        required: false
+        description: >
+           The gateway IP address.
+      network_name:
+        type: string
+        required: false
+        description: >
+           An identifier that represents an existing Network instance in the
+           underlying cloud infrastructure or can be used as the name of the
+           newly created network. If network_name is provided and no other
+           properties are provided (with exception of network_id), then an
+           existing network instance will be used. If network_name is provided
+           alongside with more properties then a new network with this name will
+           be created.
+      network_id:
+        type: string
+        required: false
+        description: >
+           An identifier that represents an existing Network instance in the
+           underlying cloud infrastructure. This property is mutually exclusive
+           with all other properties except network_name. This can be used alone
+           or together with network_name to identify an existing network.
+      segmentation_id:
+        type: string
+        required: false
+        description: >
+           A segmentation identifier in the underlying cloud infrastructure.
+           E.g. VLAN ID, GRE tunnel ID, etc..
+      network_type:
+        type: string
+        required: false
+        description: >
+           It specifies the nature of the physical network in the underlying
+           cloud infrastructure. Examples are flat, vlan, gre or vxlan.
+           For flat and vlan types, physical_network should be provided too.
+      physical_network:
+        type: string
+        required: false
+        description: >
+           It identifies the physical network on top of which the network is
+           implemented, e.g. physnet1. This property is required if network_type
+           is flat or vlan.
+      dhcp_enabled:
+        type: boolean
+        required: false
+        default: true
+        description: >
+          Indicates should DHCP service be enabled on the network or not.
+    capabilities:
+      link:
+        type: tosca.capabilities.network.Linkable
+
+  tosca.nodes.network.Port:
+    derived_from: tosca.nodes.Root
+    description: >
+      The TOSCA Port node represents a logical entity that associates between
+      Compute and Network normative types. The Port node type effectively
+      represents a single virtual NIC on the Compute node instance.
+    properties:
+      ip_address:
+        type: string
+        required: false
+        description: >
+          Allow the user to set a static IP.
+      order:
+        type: integer
+        required: false
+        default: 0
+        constraints:
+          - greater_or_equal: 0
+        description: >
+          The order of the NIC on the compute instance (e.g. eth2).
+      is_default:
+        type: boolean
+        required: false
+        default: false
+        description: >
+          If is_default=true this port will be used for the default gateway
+          route. Only one port that is associated to single compute node can
+          set as is_default=true.
+      ip_range_start:
+        type: string
+        required: false
+        description: >
+          Defines the starting IP of a range to be allocated for the compute
+          instances that are associated with this Port.
+      ip_range_end:
+        type: string
+        required: false
+        description: >
+          Defines the ending IP of a range to be allocated for the compute
+          instances that are associated with this Port.
+    attributes:
+      ip_address:
+        type: string
+    requirements:
+      - binding:
+          description: >
+            Binding requirement expresses the relationship between Port and
+            Compute nodes. Effectively it indicates that the Port will be
+            attached to specific Compute node instance
+          capability: tosca.capabilities.network.Bindable
+          relationship: tosca.relationships.network.BindsTo
+          node: tosca.nodes.Compute
+      - link:
+          description: >
+            Link requirement expresses the relationship between Port and Network
+            nodes. It indicates which network this port will connect to.
+          capability: tosca.capabilities.network.Linkable
+          relationship: tosca.relationships.network.LinksTo
+          node: tosca.nodes.network.Network
+
+  tosca.nodes.ObjectStorage:
+    derived_from: tosca.nodes.Root
+    description: >
+      The TOSCA ObjectStorage node represents storage that provides the ability
+      to store data as objects (or BLOBs of data) without consideration for the
+      underlying filesystem or devices
+    properties:
+      name:
+        type: string
+        required: true
+        description: >
+          The logical name of the object store (or container).
+      size:
+        type: scalar-unit.size
+        required: false
+        constraints:
+          - greater_or_equal: 0 GB
+        description: >
+          The requested initial storage size.
+      maxsize:
+        type: scalar-unit.size
+        required: false
+        constraints:
+          - greater_or_equal: 0 GB
+        description: >
+          The requested maximum storage size.
+    capabilities:
+      storage_endpoint:
+        type: tosca.capabilities.Endpoint
+
+  tosca.nodes.LoadBalancer:
+    derived_from: tosca.nodes.Root
+    properties:
+      algorithm:
+        type: string
+        required: false
+        status: experimental
+    capabilities:
+      client:
+        type: tosca.capabilities.Endpoint.Public
         occurrences: [0, UNBOUNDED]
-        description: Connection to one or more load balanced applications
-
-tosca.nodes.Container.Application:
-  derived_from: tosca.nodes.Root
-  requirements:
-    - host:
-        capability: tosca.capabilities.Container
-        node: tosca.nodes.Container.Runtime
-        relationship: tosca.relationships.HostedOn
-
-tosca.nodes.Container.Runtime:
-  derived_from: tosca.nodes.SoftwareComponent
-  capabilities:
-    host:
-      type: tosca.capabilities.Container
-    scalable:
-      type: tosca.capabilities.Scalable
-
-tosca.nodes.Container.Application.Docker:
-  derived_from: tosca.nodes.Container.Application
-  requirements:
-    - host:
-        capability: tosca.capabilities.Container.Docker
+        description: the Floating (IP) client’s on the public network can connect to
+    requirements:
+      - application:
+          capability: tosca.capabilities.Endpoint
+          relationship: tosca.relationships.RoutesTo
+          occurrences: [0, UNBOUNDED]
+          description: Connection to one or more load balanced applications
+
+  tosca.nodes.Container.Application:
+    derived_from: tosca.nodes.Root
+    requirements:
+      - host:
+          capability: tosca.capabilities.Container
+          node: tosca.nodes.Container.Runtime
+          relationship: tosca.relationships.HostedOn
+
+  tosca.nodes.Container.Runtime:
+    derived_from: tosca.nodes.SoftwareComponent
+    capabilities:
+      host:
+        type: tosca.capabilities.Container
+      scalable:
+        type: tosca.capabilities.Scalable
+
+  tosca.nodes.Container.Application.Docker:
+    derived_from: tosca.nodes.Container.Application
+    requirements:
+      - host:
+          capability: tosca.capabilities.Container.Docker
 
 ##########################################################################
 # Relationship Type.
 # A Relationship Type is a reusable entity that defines the type of one
 # or more relationships between Node Types or Node Templates.
 ##########################################################################
-tosca.relationships.Root:
-  description: >
-    The TOSCA root Relationship Type all other TOSCA base Relationship Types
-    derive from.
-  attributes:
-    tosca_id:
-      type: string
-    tosca_name:
-      type: string
-  interfaces:
-    Configure:
-      type: tosca.interfaces.relationship.Configure
-
-tosca.relationships.DependsOn:
-  derived_from: tosca.relationships.Root
-
-tosca.relationships.HostedOn:
-  derived_from: tosca.relationships.Root
-  valid_target_types: [ tosca.capabilities.Container ]
-
-tosca.relationships.ConnectsTo:
-  derived_from: tosca.relationships.Root
-  valid_target_types: [ tosca.capabilities.Endpoint ]
-  credential:
-    type: tosca.datatypes.Credential
-    required: false
-
-tosca.relationships.AttachesTo:
-  derived_from: tosca.relationships.Root
-  valid_target_types: [ tosca.capabilities.Attachment ]
-  properties:
-    location:
-      required: true
-      type: string
-      constraints:
-        - min_length: 1
-    device:
+relationship_types:
+  tosca.relationships.Root:
+    description: >
+      The TOSCA root Relationship Type all other TOSCA base Relationship Types
+      derive from.
+    attributes:
+      tosca_id:
+        type: string
+      tosca_name:
+        type: string
+    interfaces:
+      Configure:
+        type: tosca.interfaces.relationship.Configure
+
+  tosca.relationships.DependsOn:
+    derived_from: tosca.relationships.Root
+
+  tosca.relationships.HostedOn:
+    derived_from: tosca.relationships.Root
+    valid_target_types: [ tosca.capabilities.Container ]
+
+  tosca.relationships.ConnectsTo:
+    derived_from: tosca.relationships.Root
+    valid_target_types: [ tosca.capabilities.Endpoint ]
+    credential:
+      type: tosca.datatypes.Credential
       required: false
-      type: string
 
-tosca.relationships.RoutesTo:
-  derived_from: tosca.relationships.ConnectsTo
-  valid_target_types: [ tosca.capabilities.Endpoint ]
+  tosca.relationships.AttachesTo:
+    derived_from: tosca.relationships.Root
+    valid_target_types: [ tosca.capabilities.Attachment ]
+    properties:
+      location:
+        required: true
+        type: string
+        constraints:
+          - min_length: 1
+      device:
+        required: false
+        type: string
 
-tosca.relationships.network.LinksTo:
-  derived_from: tosca.relationships.DependsOn
-  valid_target_types: [ tosca.capabilities.network.Linkable ]
+  tosca.relationships.RoutesTo:
+    derived_from: tosca.relationships.ConnectsTo
+    valid_target_types: [ tosca.capabilities.Endpoint ]
 
-tosca.relationships.network.BindsTo:
-  derived_from: tosca.relationships.DependsOn
-  valid_target_types: [ tosca.capabilities.network.Bindable ]
+  tosca.relationships.network.LinksTo:
+    derived_from: tosca.relationships.DependsOn
+    valid_target_types: [ tosca.capabilities.network.Linkable ]
+
+  tosca.relationships.network.BindsTo:
+    derived_from: tosca.relationships.DependsOn
+    valid_target_types: [ tosca.capabilities.network.Bindable ]
 
 ##########################################################################
 # Capability Type.
 # A Capability Type is a reusable entity that describes a kind of
 # capability that a Node Type can declare to expose.
 ##########################################################################
-tosca.capabilities.Root:
-  description: >
-    The TOSCA root Capability Type all other TOSCA base Capability Types
-    derive from.
-
-tosca.capabilities.Node:
-  derived_from: tosca.capabilities.Root
-
-tosca.capabilities.Container:
-  derived_from: tosca.capabilities.Root
-  properties:
-    num_cpus:
-      required: false
-      type: integer
-      constraints:
-        - greater_or_equal: 1
-    cpu_frequency:
-      required: false
-      type: scalar-unit.frequency
-      constraints:
-        - greater_or_equal: 0.1 GHz
-    disk_size:
-      required: false
-      type: scalar-unit.size
-      constraints:
-        - greater_or_equal: 0 MB
-    mem_size:
-      required: false
-      type: scalar-unit.size
-      constraints:
-        - greater_or_equal: 0 MB
-
-tosca.capabilities.Endpoint:
-  derived_from: tosca.capabilities.Root
-  properties:
-    protocol:
-      type: string
-      required: true
-      default: tcp
-    port:
-      type: tosca.datatypes.network.PortDef
-      required: false
-    secure:
-      type: boolean
-      required: false
-      default: false
-    url_path:
-      type: string
-      required: false
-    port_name:
-      type: string
-      required: false
-    network_name:
-      type: string
-      required: false
-    initiator:
-      type: string
-      required: false
-      default: source
-      constraints:
-        - valid_values: [source, target, peer]
-    ports:
-      type: map
-      required: false
-      constraints:
-        - min_length: 1
-      entry_schema:
-        type: tosca.datatypes.network.PortSpec
-  attributes:
-    ip_address:
-      type: string
-
-tosca.capabilities.Endpoint.Admin:
-  derived_from: tosca.capabilities.Endpoint
-  properties:
-    secure:
-      type: boolean
-      default: true
-      constraints:
-        - equal: true
-
-tosca.capabilities.Endpoint.Public:
-  derived_from: tosca.capabilities.Endpoint
-  properties:
-    # Change the default network_name to use the first public network found
-    network_name:
-      type: string
-      default: PUBLIC
-      constraints:
-        - equal: PUBLIC
-    floating:
-      description: >
-        Indicates that the public address should be allocated from a pool of
-        floating IPs that are associated with the network.
-      type: boolean
-      default: false
-      status: experimental
-    dns_name:
-      description: The optional name to register with DNS
-      type: string
-      required: false
-      status: experimental
-
-tosca.capabilities.Scalable:
-  derived_from: tosca.capabilities.Root
-  properties:
-    min_instances:
-      type: integer
-      required: true
-      default: 1
-      description: >
-        This property is used to indicate the minimum number of instances
-        that should be created for the associated TOSCA Node Template by
-        a TOSCA orchestrator.
-    max_instances:
-      type: integer
-      required: true
-      default: 1
-      description: >
-        This property is used to indicate the maximum number of instances
-        that should be created for the associated TOSCA Node Template by
-        a TOSCA orchestrator.
-    default_instances:
-      type: integer
-      required: false
-      description: >
-        An optional property that indicates the requested default number
-        of instances that should be the starting number of instances a
-        TOSCA orchestrator should attempt to allocate.
-        The value for this property MUST be in the range between the values
-        set for min_instances and max_instances properties.
-
-tosca.capabilities.Endpoint.Database:
-  derived_from: tosca.capabilities.Endpoint
-
-tosca.capabilities.Attachment:
-  derived_from: tosca.capabilities.Root
-
-tosca.capabilities.network.Linkable:
-  derived_from: tosca.capabilities.Root
-  description: >
-    A node type that includes the Linkable capability indicates that it can
-    be pointed by tosca.relationships.network.LinksTo relationship type, which
-    represents an association relationship between Port and Network node types.
-
-tosca.capabilities.network.Bindable:
-  derived_from: tosca.capabilities.Root
-  description: >
-    A node type that includes the Bindable capability indicates that it can
-    be pointed by tosca.relationships.network.BindsTo relationship type, which
-    represents a network association relationship between Port and Compute node
-    types.
-
-tosca.capabilities.OperatingSystem:
-  derived_from: tosca.capabilities.Root
-  properties:
-    architecture:
-      required: false
-      type: string
-      description: >
-        The host Operating System (OS) architecture.
-    type:
-      required: false
-      type: string
-      description: >
-        The host Operating System (OS) type.
-    distribution:
-      required: false
-      type: string
-      description: >
-        The host Operating System (OS) distribution. Examples of valid values
-        for an “type” of “Linux” would include:
-        debian, fedora, rhel and ubuntu.
-    version:
-      required: false
-      type: version
-      description: >
-        The host Operating System version.
-
-tosca.capabilities.Container.Docker:
-  derived_from: tosca.capabilities.Container
-  properties:
-    version:
-      type: list
-      required: false
-      entry_schema:
+capability_types:
+  tosca.capabilities.Root:
+    description: >
+      The TOSCA root Capability Type all other TOSCA base Capability Types
+      derive from.
+
+  tosca.capabilities.Node:
+    derived_from: tosca.capabilities.Root
+
+  tosca.capabilities.Container:
+    derived_from: tosca.capabilities.Root
+    properties:
+      num_cpus:
+        required: false
+        type: integer
+        constraints:
+          - greater_or_equal: 1
+      cpu_frequency:
+        required: false
+        type: scalar-unit.frequency
+        constraints:
+          - greater_or_equal: 0.1 GHz
+      disk_size:
+        required: false
+        type: scalar-unit.size
+        constraints:
+          - greater_or_equal: 0 MB
+      mem_size:
+        required: false
+        type: scalar-unit.size
+        constraints:
+          - greater_or_equal: 0 MB
+
+  tosca.capabilities.Endpoint:
+    derived_from: tosca.capabilities.Root
+    properties:
+      protocol:
+        type: string
+        required: true
+        default: tcp
+      port:
+        type: tosca.datatypes.network.PortDef
+        required: false
+      secure:
+        type: boolean
+        required: false
+        default: false
+      url_path:
+        type: string
+        required: false
+      port_name:
+        type: string
+        required: false
+      network_name:
+        type: string
+        required: false
+      initiator:
+        type: string
+        required: false
+        default: source
+        constraints:
+          - valid_values: [source, target, peer]
+      ports:
+        type: map
+        required: false
+        constraints:
+          - min_length: 1
+        entry_schema:
+          type: tosca.datatypes.network.PortSpec
+    attributes:
+      ip_address:
+        type: string
+
+  tosca.capabilities.Endpoint.Admin:
+    derived_from: tosca.capabilities.Endpoint
+    properties:
+      secure:
+        type: boolean
+        default: true
+        constraints:
+          - equal: true
+
+  tosca.capabilities.Endpoint.Public:
+    derived_from: tosca.capabilities.Endpoint
+    properties:
+      # Change the default network_name to use the first public network found
+      network_name:
+        type: string
+        default: PUBLIC
+        constraints:
+          - equal: PUBLIC
+      floating:
+        description: >
+          Indicates that the public address should be allocated from a pool of
+          floating IPs that are associated with the network.
+        type: boolean
+        default: false
+        status: experimental
+      dns_name:
+        description: The optional name to register with DNS
+        type: string
+        required: false
+        status: experimental
+
+  tosca.capabilities.Scalable:
+    derived_from: tosca.capabilities.Root
+    properties:
+      min_instances:
+        type: integer
+        required: true
+        default: 1
+        description: >
+          This property is used to indicate the minimum number of instances
+          that should be created for the associated TOSCA Node Template by
+          a TOSCA orchestrator.
+      max_instances:
+        type: integer
+        required: true
+        default: 1
+        description: >
+          This property is used to indicate the maximum number of instances
+          that should be created for the associated TOSCA Node Template by
+          a TOSCA orchestrator.
+      default_instances:
+        type: integer
+        required: false
+        description: >
+          An optional property that indicates the requested default number
+          of instances that should be the starting number of instances a
+          TOSCA orchestrator should attempt to allocate.
+          The value for this property MUST be in the range between the values
+          set for min_instances and max_instances properties.
+
+  tosca.capabilities.Endpoint.Database:
+    derived_from: tosca.capabilities.Endpoint
+
+  tosca.capabilities.Attachment:
+    derived_from: tosca.capabilities.Root
+
+  tosca.capabilities.network.Linkable:
+    derived_from: tosca.capabilities.Root
+    description: >
+      A node type that includes the Linkable capability indicates that it can
+      be pointed by tosca.relationships.network.LinksTo relationship type, which
+      represents an association relationship between Port and Network node types.
+
+  tosca.capabilities.network.Bindable:
+    derived_from: tosca.capabilities.Root
+    description: >
+      A node type that includes the Bindable capability indicates that it can
+      be pointed by tosca.relationships.network.BindsTo relationship type, which
+      represents a network association relationship between Port and Compute node
+      types.
+
+  tosca.capabilities.OperatingSystem:
+    derived_from: tosca.capabilities.Root
+    properties:
+      architecture:
+        required: false
+        type: string
+        description: >
+          The host Operating System (OS) architecture.
+      type:
+        required: false
+        type: string
+        description: >
+          The host Operating System (OS) type.
+      distribution:
+        required: false
+        type: string
+        description: >
+          The host Operating System (OS) distribution. Examples of valid values
+          for an “type” of “Linux” would include:
+          debian, fedora, rhel and ubuntu.
+      version:
+        required: false
         type: version
-      description: >
-        The Docker version capability.
-    publish_all:
-      type: boolean
-      default: false
-      required: false
-      description: >
-        Indicates that all ports (ranges) listed in the dockerfile
-        using the EXPOSE keyword be published.
-    publish_ports:
-      type: list
-      entry_schema:
-        type: PortSpec
-      required: false
-      description: >
-        List of ports mappings from source (Docker container)
-        to target (host) ports to publish.
-    expose_ports:
-      type: list
-      entry_schema:
-        type: PortSpec
-      required: false
-      description: >
-        List of ports mappings from source (Docker container) to expose
-        to other Docker containers (not accessible outside host).
-    volumes:
-      type: list
-      entry_schema:
+        description: >
+          The host Operating System version.
+
+  tosca.capabilities.Container.Docker:
+    derived_from: tosca.capabilities.Container
+    properties:
+      version:
+        type: list
+        required: false
+        entry_schema:
+          type: version
+        description: >
+          The Docker version capability.
+      publish_all:
+        type: boolean
+        default: false
+        required: false
+        description: >
+          Indicates that all ports (ranges) listed in the dockerfile
+          using the EXPOSE keyword be published.
+      publish_ports:
+        type: list
+        entry_schema:
+          type: PortSpec
+        required: false
+        description: >
+          List of ports mappings from source (Docker container)
+          to target (host) ports to publish.
+      expose_ports:
+        type: list
+        entry_schema:
+          type: PortSpec
+        required: false
+        description: >
+          List of ports mappings from source (Docker container) to expose
+          to other Docker containers (not accessible outside host).
+      volumes:
+        type: list
+        entry_schema:
+          type: string
+        required: false
+        description: >
+          The dockerfile VOLUME command which is used to enable access
+          from the Docker container to a directory on the host machine.
+      host_id:
         type: string
-      required: false
-      description: >
-        The dockerfile VOLUME command which is used to enable access
-        from the Docker container to a directory on the host machine.
-    host_id:
-      type: string
-      required: false
-      description: >
-          The optional identifier of an existing host resource
-          that should be used to run this container on.
-    volume_id:
-      type: string
-      required: false
-      description: >
-        The optional identifier of an existing storage volume (resource)
-        that should be used to create the container's mount point(s) on.
+        required: false
+        description: >
+            The optional identifier of an existing host resource
+            that should be used to run this container on.
+      volume_id:
+        type: string
+        required: false
+        description: >
+          The optional identifier of an existing storage volume (resource)
+          that should be used to create the container's mount point(s) on.
 
 ##########################################################################
  # Interfaces Type.
@@ -708,129 +711,131 @@ tosca.capabilities.Container.Docker:
  # definitions for a modelable entity (e.g., a Node or Relationship Type)
  # as defined within the TOSCA Simple Profile specification.
 ##########################################################################
-tosca.interfaces.node.lifecycle.Standard:
-  create:
-    description: Standard lifecycle create operation.
-  configure:
-    description: Standard lifecycle configure operation.
-  start:
-    description: Standard lifecycle start operation.
-  stop:
-    description: Standard lifecycle stop operation.
-  delete:
-    description: Standard lifecycle delete operation.
-
-tosca.interfaces.relationship.Configure:
-  pre_configure_source:
-    description: Operation to pre-configure the source endpoint.
-  pre_configure_target:
-    description: Operation to pre-configure the target endpoint.
-  post_configure_source:
-    description: Operation to post-configure the source endpoint.
-  post_configure_target:
-    description: Operation to post-configure the target endpoint.
-  add_target:
-    description: Operation to add a target node.
-  remove_target:
-    description: Operation to remove a target node.
-  add_source: >
-    description: Operation to notify the target node of a source node which
-    is now available via a relationship.
-    description:
-  target_changed: >
-    description: Operation to notify source some property or attribute of the
-    target changed
+interface_types:
+  tosca.interfaces.node.lifecycle.Standard:
+    create:
+      description: Standard lifecycle create operation.
+    configure:
+      description: Standard lifecycle configure operation.
+    start:
+      description: Standard lifecycle start operation.
+    stop:
+      description: Standard lifecycle stop operation.
+    delete:
+      description: Standard lifecycle delete operation.
+
+  tosca.interfaces.relationship.Configure:
+    pre_configure_source:
+      description: Operation to pre-configure the source endpoint.
+    pre_configure_target:
+      description: Operation to pre-configure the target endpoint.
+    post_configure_source:
+      description: Operation to post-configure the source endpoint.
+    post_configure_target:
+      description: Operation to post-configure the target endpoint.
+    add_target:
+      description: Operation to add a target node.
+    remove_target:
+      description: Operation to remove a target node.
+    add_source: >
+      description: Operation to notify the target node of a source node which
+      is now available via a relationship.
+      description:
+    target_changed: >
+      description: Operation to notify source some property or attribute of the
+      target changed
 
 ##########################################################################
  # Data Type.
  # A Datatype is a complex data type declaration which contains other
  # complex or simple data types.
 ##########################################################################
-tosca.datatypes.Root:
-  description: >
-    The TOSCA root Data Type all other TOSCA base Data Types derive from
-
-tosca.datatypes.network.NetworkInfo:
-  derived_from: tosca.datatypes.Root
-  properties:
-    network_name:
-      type: string
-    network_id:
-      type: string
-    addresses:
-      type: list
-      entry_schema:
-        type: string
-
-tosca.datatypes.network.PortInfo:
-  derived_from: tosca.datatypes.Root
-  properties:
-    port_name:
-      type: string
-    port_id:
-      type: string
-    network_id:
-      type: string
-    mac_address:
-      type: string
-    addresses:
-      type: list
-      entry_schema:
-        type: string
-
-tosca.datatypes.network.PortDef:
-  derived_from: tosca.datatypes.Root
-  type: integer
-  constraints:
-    - in_range: [ 1, 65535 ]
-
-tosca.datatypes.network.PortSpec:
-  derived_from: tosca.datatypes.Root
-  properties:
-    protocol:
-      type: string
-      required: true
-      default: tcp
-      constraints:
-        - valid_values: [ udp, tcp, igmp ]
-    target:
-      type: PortDef
-      required: false
-    target_range:
-      type: range
-      required: false
-      constraints:
-        - in_range: [ 1, 65535 ]
-    source:
-      type: PortDef
-      required: false
-    source_range:
-      type: range
-      required: false
-      constraints:
-        - in_range: [ 1, 65535 ]
-
-tosca.datatypes.Credential:
-  derived_from: tosca.datatypes.Root
-  properties:
-    protocol:
-      type: string
-      required: false
-    token_type:
-      type: string
-      default: password
-      required: true
-    token:
-      type: string
-      required: true
-    keys:
-      type: map
-      entry_schema:
+data_types:
+  tosca.datatypes.Root:
+    description: >
+      The TOSCA root Data Type all other TOSCA base Data Types derive from
+
+  tosca.datatypes.network.NetworkInfo:
+    derived_from: tosca.datatypes.Root
+    properties:
+      network_name:
         type: string
-      required: false
-    user:
-      type: string
-      required: false
+      network_id:
+        type: string
+      addresses:
+        type: list
+        entry_schema:
+          type: string
+
+  tosca.datatypes.network.PortInfo:
+    derived_from: tosca.datatypes.Root
+    properties:
+      port_name:
+        type: string
+      port_id:
+        type: string
+      network_id:
+        type: string
+      mac_address:
+        type: string
+      addresses:
+        type: list
+        entry_schema:
+          type: string
+
+  tosca.datatypes.network.PortDef:
+    derived_from: tosca.datatypes.Root
+    type: integer
+    constraints:
+      - in_range: [ 1, 65535 ]
+
+  tosca.datatypes.network.PortSpec:
+    derived_from: tosca.datatypes.Root
+    properties:
+      protocol:
+        type: string
+        required: true
+        default: tcp
+        constraints:
+          - valid_values: [ udp, tcp, igmp ]
+      target:
+        type: PortDef
+        required: false
+      target_range:
+        type: range
+        required: false
+        constraints:
+          - in_range: [ 1, 65535 ]
+      source:
+        type: PortDef
+        required: false
+      source_range:
+        type: range
+        required: false
+        constraints:
+          - in_range: [ 1, 65535 ]
+
+  tosca.datatypes.Credential:
+    derived_from: tosca.datatypes.Root
+    properties:
+      protocol:
+        type: string
+        required: false
+      token_type:
+        type: string
+        default: password
+        required: true
+      token:
+        type: string
+        required: true
+      keys:
+        type: map
+        entry_schema:
+          type: string
+        required: false
+      user:
+        type: string
+        required: false
 
 ##########################################################################
  # Artifact Type.
@@ -838,56 +843,57 @@ tosca.datatypes.Credential:
  # files which Node Types or Node Templates can have dependent relationships
  # and used during operations such as during installation or deployment.
 ##########################################################################
-tosca.artifacts.Root:
-  description: >
-    The TOSCA Artifact Type all other TOSCA Artifact Types derive from
-  properties:
-    version: version
-
-tosca.artifacts.File:
-  derived_from: tosca.artifacts.Root
-
-tosca.artifacts.Deployment:
-  derived_from: tosca.artifacts.Root
-  description: TOSCA base type for deployment artifacts
-
-tosca.artifacts.Deployment.Image:
-  derived_from: tosca.artifacts.Deployment
-
-tosca.artifacts.Deployment.Image.VM:
-  derived_from: tosca.artifacts.Deployment.Image
-
-tosca.artifacts.Implementation:
-  derived_from: tosca.artifacts.Root
-  description: TOSCA base type for implementation artifacts
-
-tosca.artifacts.Implementation.Bash:
-  derived_from: tosca.artifacts.Implementation
-  description: Script artifact for the Unix Bash shell
-  mime_type: application/x-sh
-  file_ext: [ sh ]
-
-tosca.artifacts.Implementation.Python:
-  derived_from: tosca.artifacts.Implementation
-  description: Artifact for the interpreted Python language
-  mime_type: application/x-python
-  file_ext: [ py ]
-
-tosca.artifacts.Deployment.Image.Container.Docker:
-  derived_from: tosca.artifacts.Deployment.Image
-  description: Docker container image
-
-tosca.artifacts.Deployment.Image.VM.ISO:
-  derived_from: tosca.artifacts.Deployment.Image
-  description: Virtual Machine (VM) image in ISO disk format
-  mime_type: application/octet-stream
-  file_ext: [ iso ]
-
-tosca.artifacts.Deployment.Image.VM.QCOW2:
-  derived_from: tosca.artifacts.Deployment.Image
-  description: Virtual Machine (VM) image in QCOW v2 standard disk format
-  mime_type: application/octet-stream
-  file_ext: [ qcow2 ]
+artifact_types:
+  tosca.artifacts.Root:
+    description: >
+      The TOSCA Artifact Type all other TOSCA Artifact Types derive from
+    properties:
+      version: version
+
+  tosca.artifacts.File:
+    derived_from: tosca.artifacts.Root
+
+  tosca.artifacts.Deployment:
+    derived_from: tosca.artifacts.Root
+    description: TOSCA base type for deployment artifacts
+
+  tosca.artifacts.Deployment.Image:
+    derived_from: tosca.artifacts.Deployment
+
+  tosca.artifacts.Deployment.Image.VM:
+    derived_from: tosca.artifacts.Deployment.Image
+
+  tosca.artifacts.Implementation:
+    derived_from: tosca.artifacts.Root
+    description: TOSCA base type for implementation artifacts
+
+  tosca.artifacts.Implementation.Bash:
+    derived_from: tosca.artifacts.Implementation
+    description: Script artifact for the Unix Bash shell
+    mime_type: application/x-sh
+    file_ext: [ sh ]
+
+  tosca.artifacts.Implementation.Python:
+    derived_from: tosca.artifacts.Implementation
+    description: Artifact for the interpreted Python language
+    mime_type: application/x-python
+    file_ext: [ py ]
+
+  tosca.artifacts.Deployment.Image.Container.Docker:
+    derived_from: tosca.artifacts.Deployment.Image
+    description: Docker container image
+
+  tosca.artifacts.Deployment.Image.VM.ISO:
+    derived_from: tosca.artifacts.Deployment.Image
+    description: Virtual Machine (VM) image in ISO disk format
+    mime_type: application/octet-stream
+    file_ext: [ iso ]
+
+  tosca.artifacts.Deployment.Image.VM.QCOW2:
+    derived_from: tosca.artifacts.Deployment.Image
+    description: Virtual Machine (VM) image in QCOW v2 standard disk format
+    mime_type: application/octet-stream
+    file_ext: [ qcow2 ]
 
 ##########################################################################
  # Policy Type.
@@ -895,38 +901,39 @@ tosca.artifacts.Deployment.Image.VM.QCOW2:
  # an implied relationship and need to be orchestrated or managed together
  # to achieve some result.
 ##########################################################################
-tosca.policies.Root:
-  description: The TOSCA Policy Type all other TOSCA Policy Types derive from.
-
-tosca.policies.Placement:
-  derived_from: tosca.policies.Root
-  description: The TOSCA Policy Type definition that is used to govern
-    placement of TOSCA nodes or groups of nodes.
-
-tosca.policies.Placement.Colocate:
-  derived_from: tosca.policies.Placement
-  description: The TOSCA Policy Type definition that is used to govern
-    colocate placement of TOSCA nodes or groups of nodes.
-
-tosca.policies.Placement.Antilocate:
-  derived_from: tosca.policies.Placement
-  description: The TOSCA Policy Type definition that is used to govern
-    anti-locate placement of TOSCA nodes or groups of nodes.
-
-tosca.policies.Scaling:
-  derived_from: tosca.policies.Root
-  description: The TOSCA Policy Type definition that is used to govern
-    scaling of TOSCA nodes or groups of nodes.
-
-tosca.policies.Update:
-  derived_from: tosca.policies.Root
-  description: The TOSCA Policy Type definition that is used to govern
-    update of TOSCA nodes or groups of nodes.
-
-tosca.policies.Performance:
-  derived_from: tosca.policies.Root
-  description: The TOSCA Policy Type definition that is used to declare
-    performance requirements for TOSCA nodes or groups of nodes.
+policy_types:
+  tosca.policies.Root:
+    description: The TOSCA Policy Type all other TOSCA Policy Types derive from.
+
+  tosca.policies.Placement:
+    derived_from: tosca.policies.Root
+    description: The TOSCA Policy Type definition that is used to govern
+      placement of TOSCA nodes or groups of nodes.
+
+  tosca.policies.Placement.Colocate:
+    derived_from: tosca.policies.Placement
+    description: The TOSCA Policy Type definition that is used to govern
+      colocate placement of TOSCA nodes or groups of nodes.
+
+  tosca.policies.Placement.Antilocate:
+    derived_from: tosca.policies.Placement
+    description: The TOSCA Policy Type definition that is used to govern
+      anti-locate placement of TOSCA nodes or groups of nodes.
+
+  tosca.policies.Scaling:
+    derived_from: tosca.policies.Root
+    description: The TOSCA Policy Type definition that is used to govern
+      scaling of TOSCA nodes or groups of nodes.
+
+  tosca.policies.Update:
+    derived_from: tosca.policies.Root
+    description: The TOSCA Policy Type definition that is used to govern
+      update of TOSCA nodes or groups of nodes.
+
+  tosca.policies.Performance:
+    derived_from: tosca.policies.Root
+    description: The TOSCA Policy Type definition that is used to declare
+      performance requirements for TOSCA nodes or groups of nodes.
 
 ##########################################################################
  # Group Type.
@@ -934,8 +941,9 @@ tosca.policies.Performance:
  # implied membership relationship and may need to be orchestrated or
  # managed together to achieve some result.
 ##########################################################################
-tosca.groups.Root:
-  description: The TOSCA Group Type all other TOSCA Group Types derive from
-  interfaces:
-    Standard:
-      type: tosca.interfaces.node.lifecycle.Standard
+group_types:
+  tosca.groups.Root:
+    description: The TOSCA Group Type all other TOSCA Group Types derive from
+    interfaces:
+      Standard:
+        type: tosca.interfaces.node.lifecycle.Standard
index 887e99a..bf379fc 100644 (file)
@@ -31,7 +31,6 @@ class ArtifactTypeDef(StatefulEntityType):
         parent_artif = self.parent_type.type if self.parent_type else None
         if parent_artif:
             while parent_artif != 'tosca.artifacts.Root':
-                # only support normative artifact, shall be modified future
                 artifacts[parent_artif] = self.TOSCA_DEF[parent_artif]
                 parent_artif = artifacts[parent_artif]['derived_from']
         return artifacts
@@ -44,8 +43,6 @@ class ArtifactTypeDef(StatefulEntityType):
         partifact_entity = self.derived_from(self.defs)
         if partifact_entity:
             return ArtifactTypeDef(partifact_entity, self.custom_def)
-        else:
-            return None
 
     def get_artifact(self, name):
         '''Return the definition of an artifact field by name.'''
index 9b9787b..d7fcb18 100644 (file)
@@ -29,6 +29,11 @@ class EntityType(object):
                ('derived_from', 'properties', 'attributes', 'requirements',
                 'interfaces', 'capabilities', 'type', 'artifacts')
 
+    TOSCA_DEF_SECTIONS = ['node_types', 'data_types', 'artifact_types',
+                          'group_types', 'relationship_types',
+                          'capability_types', 'interface_types',
+                          'policy_types']
+
     '''TOSCA definition file.'''
     TOSCA_DEF_FILE = os.path.join(
         os.path.dirname(os.path.abspath(__file__)),
@@ -36,7 +41,15 @@ class EntityType(object):
 
     loader = toscaparser.utils.yamlparser.load_yaml
 
-    TOSCA_DEF = loader(TOSCA_DEF_FILE)
+    TOSCA_DEF_LOAD_AS_IS = loader(TOSCA_DEF_FILE)
+
+    # Map of definition with pre-loaded values of TOSCA_DEF_FILE_SECTIONS
+    TOSCA_DEF = {}
+    for section in TOSCA_DEF_SECTIONS:
+        if section in TOSCA_DEF_LOAD_AS_IS.keys():
+            value = TOSCA_DEF_LOAD_AS_IS[section]
+            for key in value.keys():
+                TOSCA_DEF[key] = value[key]
 
     RELATIONSHIP_TYPE = (DEPENDSON, HOSTEDON, CONNECTSTO, ATTACHESTO,
                          LINKSTO, BINDSTO) = \
@@ -148,5 +161,11 @@ def update_definitions(version):
     extension_defs_file = exttools.get_defs_file(version)
 
     loader = toscaparser.utils.yamlparser.load_yaml
-
-    EntityType.TOSCA_DEF.update(loader(extension_defs_file))
+    nfv_def_file = loader(extension_defs_file)
+    nfv_def = {}
+    for section in EntityType.TOSCA_DEF_SECTIONS:
+        if section in nfv_def_file.keys():
+            value = nfv_def_file[section]
+            for key in value.keys():
+                nfv_def[key] = value[key]
+    EntityType.TOSCA_DEF.update(nfv_def)
index 5587f05..02c285a 100644 (file)
@@ -59,8 +59,6 @@ class GroupType(StatefulEntityType):
         pgroup_entity = self.derived_from(self.defs)
         if pgroup_entity:
             return GroupType(pgroup_entity, self.custom_def)
-        else:
-            return None
 
     @property
     def description(self):
index 47496f7..be9933e 100644 (file)
@@ -15,6 +15,7 @@ from toscaparser.common.exception import InvalidTypeError
 from toscaparser.elements.attribute_definition import AttributeDef
 from toscaparser.elements.entity_type import EntityType
 from toscaparser.elements.property_definition import PropertyDef
+from toscaparser.unsupportedtype import UnsupportedType
 
 
 class StatefulEntityType(EntityType):
@@ -31,17 +32,20 @@ class StatefulEntityType(EntityType):
 
     def __init__(self, entitytype, prefix, custom_def=None):
         entire_entitytype = entitytype
-        if not entitytype.startswith(self.TOSCA):
-            entire_entitytype = prefix + entitytype
-        if entire_entitytype in list(self.TOSCA_DEF.keys()):
-            self.defs = self.TOSCA_DEF[entire_entitytype]
-            entitytype = entire_entitytype
-        elif custom_def and entitytype in list(custom_def.keys()):
-            self.defs = custom_def[entitytype]
-        else:
+        if UnsupportedType.validate_type(entire_entitytype):
             self.defs = None
-            ExceptionCollector.appendException(
-                InvalidTypeError(what=entitytype))
+        else:
+            if not entitytype.startswith(self.TOSCA):
+                entire_entitytype = prefix + entitytype
+            if entire_entitytype in list(self.TOSCA_DEF.keys()):
+                self.defs = self.TOSCA_DEF[entire_entitytype]
+                entitytype = entire_entitytype
+            elif custom_def and entitytype in list(custom_def.keys()):
+                self.defs = custom_def[entitytype]
+            else:
+                self.defs = None
+                ExceptionCollector.appendException(
+                    InvalidTypeError(what=entitytype))
         self.type = entitytype
 
     def get_properties_def_objects(self):
index 7488c33..7ce8cec 100644 (file)
@@ -21,6 +21,7 @@ from toscaparser.elements.nodetype import NodeType
 from toscaparser.elements.policytype import PolicyType
 from toscaparser.elements.relationshiptype import RelationshipType
 from toscaparser.properties import Property
+from toscaparser.unsupportedtype import UnsupportedType
 from toscaparser.utils.gettextutils import _
 
 
@@ -44,8 +45,9 @@ class EntityTemplate(object):
         self.entity_tpl = template
         self.custom_def = custom_def
         self._validate_field(self.entity_tpl)
+        type = self.entity_tpl.get('type')
+        UnsupportedType.validate_type(type)
         if entity_name == 'node_type':
-            type = self.entity_tpl.get('type')
             self.type_definition = NodeType(type, custom_def) \
                 if type is not None else None
         if entity_name == 'relationship_type':
@@ -57,10 +59,10 @@ class EntityTemplate(object):
                 type = self.entity_tpl['relationship']
             else:
                 type = self.entity_tpl['type']
+            UnsupportedType.validate_type(type)
             self.type_definition = RelationshipType(type,
                                                     None, custom_def)
         if entity_name == 'policy_type':
-            type = self.entity_tpl.get('type')
             if not type:
                 msg = (_('Policy definition of "%(pname)s" must have'
                        ' a "type" ''attribute.') % dict(pname=name))
@@ -69,7 +71,6 @@ class EntityTemplate(object):
 
             self.type_definition = PolicyType(type, custom_def)
         if entity_name == 'group_type':
-            type = self.entity_tpl.get('type')
             self.type_definition = GroupType(type, custom_def) \
                 if type is not None else None
         self._properties = None
index dc986e5..365d70e 100644 (file)
@@ -22,94 +22,94 @@ tosca_definitions_version: tosca_simple_profile_for_nfv_1_0_0
 # A Node Type is a reusable entity that defines the type of one or more
 # Node Templates.
 ##########################################################################
+node_types:
+  tosca.nodes.nfv.VNF:
+    derived_from: tosca.nodes.Root   # Or should this be its own top - level type?
+    properties:
+      id:
+        type: string
+        description: ID of this VNF
+      vendor:
+        type: string
+        description: name of the vendor who generate this VNF
+      version:
+        type: version
+        description: version of the software for this VNF
+    requirements:
+      - virtualLink:
+          capability: tosca.capabilities.nfv.VirtualLinkable
+          relationship: tosca.relationships.nfv.VirtualLinksTo
+          node: tosca.nodes.nfv.VL
+
+  tosca.nodes.nfv.VDU:
+    derived_from: tosca.nodes.Compute
+    capabilities:
+      high_availability:
+        type: tosca.capabilities.nfv.HA
+      virtualbinding:
+        type: tosca.capabilities.nfv.VirtualBindable
+      monitoring_parameter:
+        type: tosca.capabilities.nfv.Metric
+    requirements:
+      - high_availability:
+          capability: tosca.capabilities.nfv.HA
+          relationship: tosca.relationships.nfv.HA
+          node: tosca.nodes.nfv.VDU
+          occurrences: [ 0, 1 ]
+
+  tosca.nodes.nfv.CP:
+    derived_from: tosca.nodes.network.Port
+    properties:
+      type:
+        type: string
+        required: false
+    requirements:
+      - virtualLink:
+          capability: tosca.capabilities.nfv.VirtualLinkable
+          relationship: tosca.relationships.nfv.VirtualLinksTo
+          node: tosca.nodes.nfv.VL
+      - virtualBinding:
+          capability: tosca.capabilities.nfv.VirtualBindable
+          relationship: tosca.relationships.nfv.VirtualBindsTo
+          node: tosca.nodes.nfv.VDU
+    attributes:
+      address:
+        type: string
 
-tosca.nodes.nfv.VNF:
-  derived_from: tosca.nodes.Root   # Or should this be its own top - level type?
-  properties:
-    id:
-      type: string
-      description: ID of this VNF
-    vendor:
-      type: string
-      description: name of the vendor who generate this VNF
-    version:
-      type: version
-      description: version of the software for this VNF
-  requirements:
-    - virtualLink:
-        capability: tosca.capabilities.nfv.VirtualLinkable
-        relationship: tosca.relationships.nfv.VirtualLinksTo
-        node: tosca.nodes.nfv.VL
-
-tosca.nodes.nfv.VDU:
-  derived_from: tosca.nodes.Compute
-  capabilities:
-    high_availability:
-      type: tosca.capabilities.nfv.HA
-    virtualbinding:
-      type: tosca.capabilities.nfv.VirtualBindable
-    monitoring_parameter:
-      type: tosca.capabilities.nfv.Metric
-  requirements:
-    - high_availability:
-        capability: tosca.capabilities.nfv.HA
-        relationship: tosca.relationships.nfv.HA
-        node: tosca.nodes.nfv.VDU
-        occurrences: [ 0, 1 ]
-
-tosca.nodes.nfv.CP:
-  derived_from: tosca.nodes.network.Port
-  properties:
-    type:
-      type: string
-      required: false
-  requirements:
-    - virtualLink:
-        capability: tosca.capabilities.nfv.VirtualLinkable
-        relationship: tosca.relationships.nfv.VirtualLinksTo
-        node: tosca.nodes.nfv.VL
-    - virtualBinding:
-        capability: tosca.capabilities.nfv.VirtualBindable
-        relationship: tosca.relationships.nfv.VirtualBindsTo
-        node: tosca.nodes.nfv.VDU
-  attributes:
-    address:
-      type: string
-
-tosca.nodes.nfv.VL:
-  derived_from: tosca.nodes.network.Network
-  properties:
-    vendor:
-      type: string
-      required: true
-      description: name of the vendor who generate this VL
-  capabilities:
-    virtual_linkable:
-      type: tosca.capabilities.nfv.VirtualLinkable
-
-tosca.nodes.nfv.VL.ELine:
-  derived_from: tosca.nodes.nfv.VL
-  capabilities:
-    virtual_linkable:
-      occurrences: 2
-
-tosca.nodes.nfv.VL.ELAN:
-  derived_from: tosca.nodes.nfv.VL
-
-tosca.nodes.nfv.VL.ETree:
-  derived_from: tosca.nodes.nfv.VL
-
-tosca.nodes.nfv.FP:
-  derived_from: tosca.nodes.Root
-  properties:
-    policy:
-      type: string
-      required: false
-      description: name of the vendor who generate this VL
-  requirements:
-    - forwarder:
-        capability: tosca.capabilities.nfv.Forwarder
-        relationship: tosca.relationships.nfv.ForwardsTo
+  tosca.nodes.nfv.VL:
+    derived_from: tosca.nodes.network.Network
+    properties:
+      vendor:
+        type: string
+        required: true
+        description: name of the vendor who generate this VL
+    capabilities:
+      virtual_linkable:
+        type: tosca.capabilities.nfv.VirtualLinkable
+
+  tosca.nodes.nfv.VL.ELine:
+    derived_from: tosca.nodes.nfv.VL
+    capabilities:
+      virtual_linkable:
+        occurrences: 2
+
+  tosca.nodes.nfv.VL.ELAN:
+    derived_from: tosca.nodes.nfv.VL
+
+  tosca.nodes.nfv.VL.ETree:
+    derived_from: tosca.nodes.nfv.VL
+
+  tosca.nodes.nfv.FP:
+    derived_from: tosca.nodes.Root
+    properties:
+      policy:
+        type: string
+        required: false
+        description: name of the vendor who generate this VL
+    requirements:
+      - forwarder:
+          capability: tosca.capabilities.nfv.Forwarder
+          relationship: tosca.relationships.nfv.ForwardsTo
 
 ##########################################################################
 # Relationship Type.
@@ -117,25 +117,26 @@ tosca.nodes.nfv.FP:
 # or more relationships between Node Types or Node Templates.
 ##########################################################################
 
-tosca.relationships.nfv.VirtualLinksTo:
-  derived_from: tosca.relationships.network.LinksTo
-  valid_target_types: [ tosca.capabilities.nfv.VirtualLinkable ]
+relationship_types:
+  tosca.relationships.nfv.VirtualLinksTo:
+    derived_from: tosca.relationships.network.LinksTo
+    valid_target_types: [ tosca.capabilities.nfv.VirtualLinkable ]
 
-tosca.relationships.nfv.VirtualBindsTo:
-  derived_from: tosca.relationships.network.BindsTo
-  valid_target_types: [ tosca.capabilities.nfv.VirtualBindable ]
+  tosca.relationships.nfv.VirtualBindsTo:
+    derived_from: tosca.relationships.network.BindsTo
+    valid_target_types: [ tosca.capabilities.nfv.VirtualBindable ]
 
-tosca.relationships.nfv.HA:
-  derived_from: tosca.relationships.Root
-  valid_target_types: [ tosca.capabilities.nfv.HA ]
+  tosca.relationships.nfv.HA:
+    derived_from: tosca.relationships.Root
+    valid_target_types: [ tosca.capabilities.nfv.HA ]
 
-tosca.relationships.nfv.Monitor:
-  derived_from: tosca.relationships.ConnectsTo
-  valid_target_types: [ tosca.capabilities.nfv.Metric ]
+  tosca.relationships.nfv.Monitor:
+    derived_from: tosca.relationships.ConnectsTo
+    valid_target_types: [ tosca.capabilities.nfv.Metric ]
 
-tosca.relationships.nfv.ForwardsTo:
-  derived_from: tosca.relationships.root
-  valid_target_types: [ tosca.capabilities.nfv.Forwarder]
+  tosca.relationships.nfv.ForwardsTo:
+    derived_from: tosca.relationships.root
+    valid_target_types: [ tosca.capabilities.nfv.Forwarder]
 
 ##########################################################################
 # Capability Type.
@@ -143,27 +144,28 @@ tosca.relationships.nfv.ForwardsTo:
 # capability that a Node Type can declare to expose.
 ##########################################################################
 
-tosca.capabilities.nfv.VirtualLinkable:
-  derived_from: tosca.capabilities.network.Linkable
+capability_types:
+  tosca.capabilities.nfv.VirtualLinkable:
+    derived_from: tosca.capabilities.network.Linkable
 
-tosca.capabilities.nfv.VirtualBindable:
-  derived_from: tosca.capabilities.network.Bindable
+  tosca.capabilities.nfv.VirtualBindable:
+    derived_from: tosca.capabilities.network.Bindable
 
-tosca.capabilities.nfv.HA:
-  derived_from: tosca.capabilities.Root
-  valid_source_types: [ tosca.nodes.nfv.VDU ]
+  tosca.capabilities.nfv.HA:
+    derived_from: tosca.capabilities.Root
+    valid_source_types: [ tosca.nodes.nfv.VDU ]
 
-tosca.capabilities.nfv.HA.ActiveActive:
-  derived_from: tosca.capabilities.nfv.HA
+  tosca.capabilities.nfv.HA.ActiveActive:
+    derived_from: tosca.capabilities.nfv.HA
 
-tosca.capabilities.nfv.HA.ActivePassive:
-  derived_from: tosca.capabilities.nfv.HA
+  tosca.capabilities.nfv.HA.ActivePassive:
+    derived_from: tosca.capabilities.nfv.HA
 
-tosca.capabilities.nfv.Metric:
-  derived_from: tosca.capabilities.Root
+  tosca.capabilities.nfv.Metric:
+    derived_from: tosca.capabilities.Root
 
-tosca.capabilities.nfv.Forwarder:
-  derived_from: tosca.capabilities.Root
+  tosca.capabilities.nfv.Forwarder:
+    derived_from: tosca.capabilities.Root
 
 ##########################################################################
  # Interfaces Type.
@@ -196,42 +198,43 @@ tosca.capabilities.nfv.Forwarder:
  # Group Type
  #
 ##########################################################################
-tosca.groups.nfv.VNFFG:
-  derived_from: tosca.groups.Root
-
-  properties:
-    vendor:
-      type: string
-      required: true
-      description: name of the vendor who generate this VNFFG
-
-    version:
-      type: string
-      required: true
-      description: version of this VNFFG
-
-    number_of_endpoints:
-      type: integer
-      required: true
-      description: count of the external endpoints included in this VNFFG
-
-    dependent_virtual_link:
-      type: list
-      entry_schema:
-        type: string
-      required: true
-      description: Reference to a VLD  used in this Forwarding Graph
+group_types:
+  tosca.groups.nfv.VNFFG:
+    derived_from: tosca.groups.Root
 
-    connection_point:
-      type: list
-      entry_schema:
+    properties:
+      vendor:
         type: string
-      required: true
-      description: Reference to Connection Points forming the VNFFG
+        required: true
+        description: name of the vendor who generate this VNFFG
 
-    constituent_vnfs:
-      type: list
-      entry_schema:
+      version:
         type: string
-      required: true
-      description: Reference to a list of  VNFD used in this VNF Forwarding Graph
+        required: true
+        description: version of this VNFFG
+
+      number_of_endpoints:
+        type: integer
+        required: true
+        description: count of the external endpoints included in this VNFFG
+
+      dependent_virtual_link:
+        type: list
+        entry_schema:
+          type: string
+        required: true
+        description: Reference to a VLD  used in this Forwarding Graph
+
+      connection_point:
+        type: list
+        entry_schema:
+          type: string
+        required: true
+        description: Reference to Connection Points forming the VNFFG
+
+      constituent_vnfs:
+        type: list
+        entry_schema:
+          type: string
+        required: true
+        description: Reference to a list of  VNFD used in this VNF Forwarding Graph
index e229d2f..e87b672 100644 (file)
@@ -706,6 +706,8 @@ class ToscaTemplateTest(TestCase):
         tosca = ToscaTemplate(tosca_tpl)
 
         for policy in tosca.topology_template.policies:
+            self.assertTrue(
+                policy.is_derived_from("tosca.policies.Root"))
             if policy.name == 'my_compute_placement_policy':
                 self.assertEqual('tosca.policies.Placement', policy.type)
                 self.assertEqual(['my_server_1', 'my_server_2'],
@@ -726,6 +728,8 @@ class ToscaTemplateTest(TestCase):
         tosca = ToscaTemplate(tosca_tpl)
 
         for policy in tosca.topology_template.policies:
+            self.assertTrue(
+                policy.is_derived_from("tosca.policies.Root"))
             if policy.name == 'my_groups_placement':
                 self.assertEqual('mycompany.mytypes.myScalingPolicy',
                                  policy.type)
index 57daf7e..5a8f37a 100644 (file)
@@ -98,6 +98,22 @@ class ToscaTemplateValidationTest(TestCase):
               'field "derived1_from". Refer to the definition to '
               'verify valid values.'))
 
+    def test_unsupported_type(self):
+        tpl_snippet = '''
+        node_templates:
+          invalid_type:
+            type: tosca.test.invalidtype
+            properties:
+              size: { get_input: storage_size }
+              snapshot_id: { get_input: storage_snapshot_id }
+        '''
+        tpl = (toscaparser.utils.yamlparser.simple_parse(tpl_snippet))
+        err = self.assertRaises(exception.UnsupportedTypeError,
+                                TopologyTemplate, tpl, None)
+        expectedmessage = _('Type "tosca.test.invalidtype" is valid'
+                            ' TOSCA type but not supported at this time.')
+        self.assertEqual(expectedmessage, err.__str__())
+
     def test_inputs(self):
         tpl_snippet1 = '''
         inputs:
index 215fa0a..fca024d 100644 (file)
@@ -29,6 +29,7 @@ class UrlUtilsTest(TestCase):
         self.assertFalse(self.url_utils.validate_url("github.com"))
         self.assertFalse(self.url_utils.validate_url("123"))
         self.assertFalse(self.url_utils.validate_url("a/b/c"))
+        self.assertTrue(self.url_utils.validate_url("file:///dir/file.ext"))
 
     def test_urlutils_join_url(self):
         self.assertEqual(
index 100a06b..d7fd443 100644 (file)
@@ -26,6 +26,7 @@ from toscaparser.substitution_mappings import SubstitutionMappings
 from toscaparser.tpl_relationship_graph import ToscaGraph
 from toscaparser.utils.gettextutils import _
 
+
 # Topology template key names
 SECTIONS = (DESCRIPTION, INPUTS, NODE_TEMPLATES,
             RELATIONSHIP_TEMPLATES, OUTPUTS, GROUPS,
diff --git a/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py b/tosca2heat/tosca-parser/toscaparser/unsupportedtype.py
new file mode 100644 (file)
index 0000000..0d2f1d6
--- /dev/null
@@ -0,0 +1,38 @@
+#    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
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+import logging
+
+from toscaparser.common.exception import ExceptionCollector
+from toscaparser.common.exception import UnsupportedTypeError
+from toscaparser.utils.gettextutils import _
+
+log = logging.getLogger('tosca')
+
+
+class UnsupportedType(object):
+
+    un_supported_types = ['tosca.test.invalidtype',
+                          'tosca.nodes.Storage.ObjectStorage',
+                          'tosca.nodes.Storage.BlockStorage']
+
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def validate_type(entitytype):
+        if entitytype in UnsupportedType.un_supported_types:
+            ExceptionCollector.appendException(UnsupportedTypeError(
+                                               what=_('%s')
+                                               % entitytype))
+            return True
+        else:
+            return False
index 34b6032..546acca 100644 (file)
@@ -35,7 +35,11 @@ class UrlUtils(object):
         URL.
         """
         parsed = urlparse(path)
-        return bool(parsed.scheme) and bool(parsed.netloc)
+        if parsed.scheme == 'file':
+            # If the url uses the file scheme netloc will be ""
+            return True
+        else:
+            return bool(parsed.scheme) and bool(parsed.netloc)
 
     @staticmethod
     def join_url(url, relative_path):