You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by av...@apache.org on 2017/06/04 12:55:45 UTC

[1/2] incubator-ariatosca git commit: ARIA-180 Separate Parameter models and change relationships

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/master 9174f9469 -> b6d3c43ba


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/cli/test_service_templates.py
----------------------------------------------------------------------
diff --git a/tests/cli/test_service_templates.py b/tests/cli/test_service_templates.py
index 7e86896..cc0150e 100644
--- a/tests/cli/test_service_templates.py
+++ b/tests/cli/test_service_templates.py
@@ -215,7 +215,7 @@ class TestServiceTemplatesInputs(TestCliBase):
 
     def test_inputs_existing_inputs(self, monkeypatch, mock_storage):
         monkeypatch.setattr(_Environment, 'model_storage', mock_storage)
-        input = mock_models.create_parameter(name='input1', value='value1')
+        input = mock_models.create_input(name='input1', value='value1')
         st = mock_models.create_service_template(inputs={'input1': input})
         monkeypatch.setattr(mock_storage.service_template, 'get_by_name',
                             mock.MagicMock(return_value=st))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 50aa340..56a6e3e 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -94,7 +94,7 @@ def create_service_with_dependencies(include_execution=False,
         service.executions = [execution]
         execution.id = '1'
     if include_input:
-        input = create_parameter(name='input1', value='value1')
+        input = create_input(name='input1', value='value1')
         service.inputs = {'input1': input}
     if include_node:
         node_template = create_node_template(service_template=service_template)
@@ -110,7 +110,7 @@ def create_node_template_with_dependencies(include_node=False, include_property=
         service = create_service(service_template=service_template)
         create_node(dependency_node_template=node_template, service=service)
     if include_property:
-        node_template.properties = {'prop1': create_parameter(name='prop1', value='value1')}
+        node_template.properties = {'prop1': create_property(name='prop1', value='value1')}
     return node_template
 
 
@@ -120,7 +120,7 @@ def create_node_with_dependencies(include_attribute=False):
     node_template.service_template.services[0] = create_service(node_template.service_template)
     node = create_node(node_template, node_template.service_template.services[0])
     if include_attribute:
-        node.attributes['attribute1'] = models.Parameter.wrap('attribute1', 'value1')               # pylint: disable=unsubscriptable-object
+        node.attributes['attribute1'] = models.Attribute.wrap('attribute1', 'value1')               # pylint: disable=unsubscriptable-object
     return node
 
 
@@ -227,7 +227,7 @@ def create_interface(service, interface_name, operation_name, operation_kwargs=N
 
     if operation_kwargs and operation_kwargs.get('arguments'):
         operation_kwargs['arguments'] = dict(
-            (argument_name, models.Parameter.wrap(argument_name, argument_value))
+            (argument_name, models.Argument.wrap(argument_name, argument_value))
             for argument_name, argument_value in operation_kwargs['arguments'].iteritems()
             if argument_value is not None)
 
@@ -278,9 +278,16 @@ def create_plugin_specification(name='test_plugin', version='0.1'):
     )
 
 
-def create_parameter(name, value):
-    p = models.Parameter()
-    return p.wrap(name, value)
+def _create_parameter(name, value, model_cls):
+    return model_cls.wrap(name, value)
+
+
+def create_property(name, value):
+    return _create_parameter(name, value, model_cls=models.Property)
+
+
+def create_input(name, value):
+    return _create_parameter(name, value, model_cls=models.Input)
 
 
 def _dictify(item):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/mock/topology.py
----------------------------------------------------------------------
diff --git a/tests/mock/topology.py b/tests/mock/topology.py
index ab08dbd..9f0521f 100644
--- a/tests/mock/topology.py
+++ b/tests/mock/topology.py
@@ -28,8 +28,8 @@ def create_simple_topology_single_node(model_storage, create_operation):
         'Standard', 'create',
         operation_kwargs=dict(
             function=create_operation,
-            arguments={'key': aria_models.Parameter.wrap('key', 'create'),
-                       'value': aria_models.Parameter.wrap('value', True)})
+            arguments={'key': aria_models.Argument.wrap('key', 'create'),
+                       'value': aria_models.Argument.wrap('value', True)})
     )
     node_template.interface_templates[interface_template.name] = interface_template                 # pylint: disable=unsubscriptable-object
 
@@ -39,8 +39,8 @@ def create_simple_topology_single_node(model_storage, create_operation):
         'Standard', 'create',
         operation_kwargs=dict(
             function=create_operation,
-            arguments={'key': aria_models.Parameter.wrap('key', 'create'),
-                       'value': aria_models.Parameter.wrap('value', True)})
+            arguments={'key': aria_models.Argument.wrap('key', 'create'),
+                       'value': aria_models.Argument.wrap('value', True)})
     )
     node.interfaces[interface.name] = interface                                                     # pylint: disable=unsubscriptable-object
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/modeling/test_models.py
----------------------------------------------------------------------
diff --git a/tests/modeling/test_models.py b/tests/modeling/test_models.py
index df3aebd..464f432 100644
--- a/tests/modeling/test_models.py
+++ b/tests/modeling/test_models.py
@@ -36,7 +36,12 @@ from aria.modeling.models import (
     Relationship,
     NodeTemplate,
     Node,
-    Parameter,
+    Input,
+    Output,
+    Property,
+    Attribute,
+    Configuration,
+    Argument,
     Type
 )
 
@@ -622,7 +627,7 @@ class TestNodeHostAddress(object):
             service_template=storage.service_template.list()[0]
         )
         if host_address:
-            kwargs['properties'] = {'host_address': Parameter.wrap('host_address', host_address)}
+            kwargs['properties'] = {'host_address': Property.wrap('host_address', host_address)}
         node = NodeTemplate(**kwargs)
         storage.node_template.put(node)
         return node
@@ -640,7 +645,7 @@ class TestNodeHostAddress(object):
             if host_address is not None:
                 host_address = host_address.value
         if host_address:
-            kwargs.setdefault('attributes', {})['ip'] = Parameter.wrap('ip', host_address)
+            kwargs.setdefault('attributes', {})['ip'] = Attribute.wrap('ip', host_address)
         if is_host:
             kwargs['host_fk'] = 1
         elif host_fk:
@@ -839,3 +844,41 @@ class TestType(object):
 
         assert super_type.hierarchy == [super_type, additional_type]
         assert sub_type.hierarchy == [sub_type, super_type, additional_type]
+
+
+class TestParameter(object):
+
+    MODELS_DERIVED_FROM_PARAMETER = (Input, Output, Property, Attribute, Configuration, Argument)
+
+    @pytest.mark.parametrize(
+        'is_valid, name, type_name, description',
+        [
+            (False, 'name', 'int', []),
+            (False, 'name', [], 'desc'),
+            (False, [], 'type_name', 'desc'),
+            (True, 'name', 'type_name', 'desc'),
+        ]
+    )
+    def test_derived_from_parameter_model_creation(self, empty_storage, is_valid, name, type_name,
+                                                   description):
+
+        for model_cls in self.MODELS_DERIVED_FROM_PARAMETER:
+            _test_model(is_valid=is_valid,
+                        storage=empty_storage,
+                        model_cls=model_cls,
+                        model_kwargs=dict(
+                            name=name,
+                            type_name=type_name,
+                            description=description,
+                            _value={})
+                       )
+
+    def test_as_argument(self):
+
+        for model_cls in self.MODELS_DERIVED_FROM_PARAMETER:
+            model = model_cls(name='name',
+                              type_name='type_name',
+                              description='description',
+                              _value={})
+            argument = model.as_argument()
+            assert isinstance(argument, Argument)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/orchestrator/context/test_collection_instrumentation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_collection_instrumentation.py b/tests/orchestrator/context/test_collection_instrumentation.py
index 3ee5a44..1e6214a 100644
--- a/tests/orchestrator/context/test_collection_instrumentation.py
+++ b/tests/orchestrator/context/test_collection_instrumentation.py
@@ -15,7 +15,7 @@
 
 import pytest
 
-from aria.modeling.models import Parameter
+from aria.modeling.models import Attribute
 from aria.orchestrator.context import collection_instrumentation
 
 
@@ -28,7 +28,7 @@ class MockActor(object):
 class MockModel(object):
 
     def __init__(self):
-        self.parameter = type('MockModel', (object, ), {'model_cls': Parameter,
+        self.attribute = type('MockModel', (object, ), {'model_cls': Attribute,
                                                         'put': lambda *args, **kwargs: None,
                                                         'update': lambda *args, **kwargs: None})()
 
@@ -57,16 +57,16 @@ class TestDict(CollectionInstrumentation):
     def test_keys(self, actor, dict_):
         dict_.update(
             {
-                'key1': Parameter.wrap('key1', 'value1'),
-                'key2': Parameter.wrap('key2', 'value2')
+                'key1': Attribute.wrap('key1', 'value1'),
+                'key2': Attribute.wrap('key2', 'value2')
             }
         )
         assert sorted(dict_.keys()) == sorted(['key1', 'key2']) == sorted(actor.dict_.keys())
 
     def test_values(self, actor, dict_):
         dict_.update({
-            'key1': Parameter.wrap('key1', 'value1'),
-            'key2': Parameter.wrap('key1', 'value2')
+            'key1': Attribute.wrap('key1', 'value1'),
+            'key2': Attribute.wrap('key1', 'value2')
         })
         assert (sorted(dict_.values()) ==
                 sorted(['value1', 'value2']) ==
@@ -74,34 +74,34 @@ class TestDict(CollectionInstrumentation):
 
     def test_items(self, dict_):
         dict_.update({
-            'key1': Parameter.wrap('key1', 'value1'),
-            'key2': Parameter.wrap('key1', 'value2')
+            'key1': Attribute.wrap('key1', 'value1'),
+            'key2': Attribute.wrap('key1', 'value2')
         })
         assert sorted(dict_.items()) == sorted([('key1', 'value1'), ('key2', 'value2')])
 
     def test_iter(self, actor, dict_):
         dict_.update({
-            'key1': Parameter.wrap('key1', 'value1'),
-            'key2': Parameter.wrap('key1', 'value2')
+            'key1': Attribute.wrap('key1', 'value1'),
+            'key2': Attribute.wrap('key1', 'value2')
         })
         assert sorted(list(dict_)) == sorted(['key1', 'key2']) == sorted(actor.dict_.keys())
 
     def test_bool(self, dict_):
         assert not dict_
         dict_.update({
-            'key1': Parameter.wrap('key1', 'value1'),
-            'key2': Parameter.wrap('key1', 'value2')
+            'key1': Attribute.wrap('key1', 'value1'),
+            'key2': Attribute.wrap('key1', 'value2')
         })
         assert dict_
 
     def test_set_item(self, actor, dict_):
-        dict_['key1'] = Parameter.wrap('key1', 'value1')
+        dict_['key1'] = Attribute.wrap('key1', 'value1')
         assert dict_['key1'] == 'value1' == actor.dict_['key1'].value
-        assert isinstance(actor.dict_['key1'], Parameter)
+        assert isinstance(actor.dict_['key1'], Attribute)
 
     def test_nested(self, actor, dict_):
         dict_['key'] = {}
-        assert isinstance(actor.dict_['key'], Parameter)
+        assert isinstance(actor.dict_['key'], Attribute)
         assert dict_['key'] == actor.dict_['key'].value == {}
 
         dict_['key']['inner_key'] = 'value'
@@ -112,7 +112,7 @@ class TestDict(CollectionInstrumentation):
         assert dict_['key'].keys() == ['inner_key']
         assert dict_['key'].values() == ['value']
         assert dict_['key'].items() == [('inner_key', 'value')]
-        assert isinstance(actor.dict_['key'], Parameter)
+        assert isinstance(actor.dict_['key'], Attribute)
         assert isinstance(dict_['key'], collection_instrumentation._InstrumentedDict)
 
         dict_['key'].update({'updated_key': 'updated_value'})
@@ -123,7 +123,7 @@ class TestDict(CollectionInstrumentation):
         assert sorted(dict_['key'].values()) == sorted(['value', 'updated_value'])
         assert sorted(dict_['key'].items()) == sorted([('inner_key', 'value'),
                                                        ('updated_key', 'updated_value')])
-        assert isinstance(actor.dict_['key'], Parameter)
+        assert isinstance(actor.dict_['key'], Attribute)
         assert isinstance(dict_['key'], collection_instrumentation._InstrumentedDict)
 
         dict_.update({'key': 'override_value'})
@@ -131,12 +131,12 @@ class TestDict(CollectionInstrumentation):
         assert 'key' in dict_
         assert dict_['key'] == 'override_value'
         assert len(actor.dict_) == 1
-        assert isinstance(actor.dict_['key'], Parameter)
+        assert isinstance(actor.dict_['key'], Attribute)
         assert actor.dict_['key'].value == 'override_value'
 
     def test_get_item(self, actor, dict_):
-        dict_['key1'] = Parameter.wrap('key1', 'value1')
-        assert isinstance(actor.dict_['key1'], Parameter)
+        dict_['key1'] = Attribute.wrap('key1', 'value1')
+        assert isinstance(actor.dict_['key1'], Attribute)
 
     def test_update(self, actor, dict_):
         dict_['key1'] = 'value1'
@@ -145,7 +145,7 @@ class TestDict(CollectionInstrumentation):
         dict_.update(new_dict)
         assert len(dict_) == 2
         assert dict_['key2'] == 'value2'
-        assert isinstance(actor.dict_['key2'], Parameter)
+        assert isinstance(actor.dict_['key2'], Attribute)
 
         new_dict = {}
         new_dict.update(dict_)
@@ -172,20 +172,20 @@ class TestDict(CollectionInstrumentation):
 class TestList(CollectionInstrumentation):
 
     def test_append(self, actor, list_):
-        list_.append(Parameter.wrap('name', 'value1'))
+        list_.append(Attribute.wrap('name', 'value1'))
         list_.append('value2')
         assert len(actor.list_) == 2
         assert len(list_) == 2
-        assert isinstance(actor.list_[0], Parameter)
+        assert isinstance(actor.list_[0], Attribute)
         assert list_[0] == 'value1'
 
-        assert isinstance(actor.list_[1], Parameter)
+        assert isinstance(actor.list_[1], Attribute)
         assert list_[1] == 'value2'
 
         list_[0] = 'new_value1'
         list_[1] = 'new_value2'
-        assert isinstance(actor.list_[1], Parameter)
-        assert isinstance(actor.list_[1], Parameter)
+        assert isinstance(actor.list_[1], Attribute)
+        assert isinstance(actor.list_[1], Attribute)
         assert list_[0] == 'new_value1'
         assert list_[1] == 'new_value2'
 
@@ -214,12 +214,12 @@ class TestList(CollectionInstrumentation):
         list_.append([])
 
         list_[0].append('inner_item')
-        assert isinstance(actor.list_[0], Parameter)
+        assert isinstance(actor.list_[0], Attribute)
         assert len(list_) == 1
         assert list_[0][0] == 'inner_item'
 
         list_[0].append('new_item')
-        assert isinstance(actor.list_[0], Parameter)
+        assert isinstance(actor.list_[0], Attribute)
         assert len(list_) == 1
         assert list_[0][1] == 'new_item'
 
@@ -231,23 +231,23 @@ class TestDictList(CollectionInstrumentation):
     def test_dict_in_list(self, actor, list_):
         list_.append({})
         assert len(list_) == 1
-        assert isinstance(actor.list_[0], Parameter)
+        assert isinstance(actor.list_[0], Attribute)
         assert actor.list_[0].value == {}
 
         list_[0]['key'] = 'value'
         assert list_[0]['key'] == 'value'
         assert len(actor.list_) == 1
-        assert isinstance(actor.list_[0], Parameter)
+        assert isinstance(actor.list_[0], Attribute)
         assert actor.list_[0].value['key'] == 'value'
 
     def test_list_in_dict(self, actor, dict_):
         dict_['key'] = []
         assert len(dict_) == 1
-        assert isinstance(actor.dict_['key'], Parameter)
+        assert isinstance(actor.dict_['key'], Attribute)
         assert actor.dict_['key'].value == []
 
         dict_['key'].append('value')
         assert dict_['key'][0] == 'value'
         assert len(actor.dict_) == 1
-        assert isinstance(actor.dict_['key'], Parameter)
+        assert isinstance(actor.dict_['key'], Attribute)
         assert actor.dict_['key'].value[0] == 'value'

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/orchestrator/context/test_toolbelt.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_toolbelt.py b/tests/orchestrator/context/test_toolbelt.py
index 326ce83..4de9e55 100644
--- a/tests/orchestrator/context/test_toolbelt.py
+++ b/tests/orchestrator/context/test_toolbelt.py
@@ -94,7 +94,7 @@ def test_host_ip(workflow_context, executor, dataholder):
         operation_kwargs=dict(function=op_path(host_ip, module_path=__name__), arguments=arguments)
     )
     dependency_node.interfaces[interface.name] = interface
-    dependency_node.attributes['ip'] = models.Parameter.wrap('ip', '1.1.1.1')
+    dependency_node.attributes['ip'] = models.Attribute.wrap('ip', '1.1.1.1')
 
     workflow_context.model.node.update(dependency_node)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/orchestrator/test_workflow_runner.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/test_workflow_runner.py b/tests/orchestrator/test_workflow_runner.py
index 3646339..c5a62ae 100644
--- a/tests/orchestrator/test_workflow_runner.py
+++ b/tests/orchestrator/test_workflow_runner.py
@@ -170,7 +170,7 @@ def test_execution_inputs_override_workflow_inputs(request):
     wf_inputs = {'input1': 'value1', 'input2': 'value2', 'input3': 5}
     mock_workflow = _setup_mock_workflow_in_service(
         request,
-        inputs=dict((name, models.Parameter.wrap(name, val)) for name, val
+        inputs=dict((name, models.Input.wrap(name, val)) for name, val
                     in wf_inputs.iteritems()))
 
     with mock.patch('aria.orchestrator.workflow_runner.Engine'):
@@ -195,7 +195,7 @@ def test_execution_inputs_undeclared_inputs(request):
 
 def test_execution_inputs_missing_required_inputs(request):
     mock_workflow = _setup_mock_workflow_in_service(
-        request, inputs={'required_input': models.Parameter.wrap('required_input', value=None)})
+        request, inputs={'required_input': models.Input.wrap('required_input', value=None)})
 
     with pytest.raises(modeling_exceptions.MissingRequiredParametersException):
         _create_workflow_runner(request, mock_workflow, inputs={})
@@ -203,7 +203,7 @@ def test_execution_inputs_missing_required_inputs(request):
 
 def test_execution_inputs_wrong_type_inputs(request):
     mock_workflow = _setup_mock_workflow_in_service(
-        request, inputs={'input': models.Parameter.wrap('input', 'value')})
+        request, inputs={'input': models.Input.wrap('input', 'value')})
 
     with pytest.raises(modeling_exceptions.ParametersOfWrongTypeException):
         _create_workflow_runner(request, mock_workflow, inputs={'input': 5})
@@ -224,7 +224,7 @@ def test_workflow_function_parameters(request, tmpdir):
     wf_inputs = {'output_path': output_path, 'input1': 'value1', 'input2': 'value2', 'input3': 5}
 
     mock_workflow = _setup_mock_workflow_in_service(
-        request, inputs=dict((name, models.Parameter.wrap(name, val)) for name, val
+        request, inputs=dict((name, models.Input.wrap(name, val)) for name, val
                              in wf_inputs.iteritems()))
 
     _create_workflow_runner(request, mock_workflow,
@@ -255,12 +255,16 @@ def _setup_mock_workflow_in_service(request, inputs=None):
     source = workflow_mocks.__file__
     resource.service_template.upload(str(service.service_template.id), source)
     mock_workflow_name = 'test_workflow'
+    arguments = {}
+    if inputs:
+        for input in inputs.itervalues():
+            arguments[input.name] = input.as_argument()
     workflow = models.Operation(
         name=mock_workflow_name,
         service=service,
         function='workflow.mock_workflow',
         inputs=inputs or {},
-        arguments=inputs or {})
+        arguments=arguments)
     service.workflows[mock_workflow_name] = workflow
     return mock_workflow_name
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/orchestrator/workflows/executor/test_executor.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/executor/test_executor.py b/tests/orchestrator/workflows/executor/test_executor.py
index 9ddaef4..3079c60 100644
--- a/tests/orchestrator/workflows/executor/test_executor.py
+++ b/tests/orchestrator/workflows/executor/test_executor.py
@@ -47,7 +47,7 @@ def execute_and_assert(executor, storage=None):
     successful_task = MockTask(_get_function(mock_successful_task), storage=storage)
     failing_task = MockTask(_get_function(mock_failing_task), storage=storage)
     task_with_inputs = MockTask(_get_function(mock_task_with_input),
-                                arguments={'input': models.Parameter.wrap('input', 'value')},
+                                arguments={'input': models.Argument.wrap('input', 'value')},
                                 storage=storage)
 
     for task in [successful_task, failing_task, task_with_inputs]:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tests/storage/test_model_storage.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_model_storage.py b/tests/storage/test_model_storage.py
index 4dabfaf..518d624 100644
--- a/tests/storage/test_model_storage.py
+++ b/tests/storage/test_model_storage.py
@@ -107,7 +107,11 @@ def test_application_storage_factory():
     assert storage.plugin
     assert storage.task
 
-    assert storage.parameter
+    assert storage.input
+    assert storage.output
+    assert storage.property
+    assert storage.attribute
+
     assert storage.type
     assert storage.metadata
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/tox.ini
----------------------------------------------------------------------
diff --git a/tox.ini b/tox.ini
index 6ab97cb..58e62c3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -19,8 +19,6 @@ passenv =
     PYTHON
     PYTHON_VERSION
     PYTHON_ARCH
-setenv =
-    INSTALL_CTX=1
 deps =
     -rrequirements.txt
     -rtests/requirements.txt


[2/2] incubator-ariatosca git commit: ARIA-180 Separate Parameter models and change relationships

Posted by av...@apache.org.
ARIA-180 Separate Parameter models and change relationships

First, the Parameter model was separated in 6 individual models:
Input, Output, Property, Attribute, Configuration, Argument.

The first four models are TOSCA-related, and we needed to separate them
as according to the TOSCA spec, all four of these represent different
things, and have different fields.

The other two models (Configuration, Argument) are
orchestration-related, as and such are not supposed to represent the
same object as the TOSCA-related objects.

Second, up until now, the relationships of the then-Parameter models
were many-to-many to any other object related to them. This was a problem,
as logically the relationships were one-to-many (from the other models
to the Parameter models).
In this commit, we changed them to one-to-many. In addition, separating
the Parameter models allowed us to more accurately represent the relationship of each individual Parameter-model with its related models.


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/b6d3c43b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/b6d3c43b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/b6d3c43b

Branch: refs/heads/master
Commit: b6d3c43ba42ccc3fa7287aff132c83563abea035
Parents: 9174f94
Author: Avia Efrat <av...@gigaspaces.com>
Authored: Sun May 21 16:28:30 2017 +0300
Committer: Avia Efrat <av...@gigaspaces.com>
Committed: Sun Jun 4 15:40:03 2017 +0300

----------------------------------------------------------------------
 aria/modeling/mixins.py                         | 216 +++++++++-
 aria/modeling/models.py                         |  42 +-
 aria/modeling/orchestration.py                  |  37 +-
 aria/modeling/service_changes.py                |  12 -
 aria/modeling/service_common.py                 | 423 +++++++++++--------
 aria/modeling/service_instance.py               | 177 ++++----
 aria/modeling/service_template.py               | 164 +++----
 aria/modeling/utils.py                          |   6 +-
 .../context/collection_instrumentation.py       |  10 +-
 .../execution_plugin/instantiation.py           |  36 +-
 aria/orchestrator/workflow_runner.py            |   4 +-
 aria/orchestrator/workflows/api/task.py         |   6 +-
 aria/orchestrator/workflows/executor/dry.py     |   2 +-
 examples/hello-world/helloworld.yaml            |   2 +-
 .../simple_v1_0/modeling/__init__.py            |  71 ++--
 tests/cli/test_service_templates.py             |   2 +-
 tests/mock/models.py                            |  21 +-
 tests/mock/topology.py                          |   8 +-
 tests/modeling/test_models.py                   |  49 ++-
 .../context/test_collection_instrumentation.py  |  64 +--
 tests/orchestrator/context/test_toolbelt.py     |   2 +-
 tests/orchestrator/test_workflow_runner.py      |  14 +-
 .../workflows/executor/test_executor.py         |   2 +-
 tests/storage/test_model_storage.py             |   6 +-
 tox.ini                                         |   2 -
 25 files changed, 867 insertions(+), 511 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/mixins.py
----------------------------------------------------------------------
diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py
index 38c812d..c98a866 100644
--- a/aria/modeling/mixins.py
+++ b/aria/modeling/mixins.py
@@ -23,10 +23,14 @@ from sqlalchemy.ext import associationproxy
 from sqlalchemy import (
     Column,
     Integer,
-    Text
+    Text,
+    PickleType
 )
 
-from . import utils
+from ..parser.consumption import ConsumptionContext
+from ..utils import console, collections, caching, formatting
+from ..utils.type import canonical_type_name, full_type_name
+from . import utils, functions
 
 
 class ModelMixin(object):
@@ -140,3 +144,211 @@ class TemplateModelMixin(InstanceModelMixin):
 
     def instantiate(self, container):
         raise NotImplementedError
+
+
+class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods):                                 #pylint: disable=abstract-method
+    """
+    Represents a typed value. The value can contain nested intrinsic functions.
+
+    This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`.
+
+    :ivar name: Name
+    :vartype name: basestring
+    :ivar type_name: Type name
+    :vartype type_name: basestring
+    :ivar value: Value
+    :ivar description: Description
+    :vartype description: basestring
+    """
+
+    __tablename__ = 'parameter'
+
+    name = Column(Text)
+    type_name = Column(Text)
+    description = Column(Text)
+    _value = Column(PickleType)
+
+    @property
+    def value(self):
+        value = self._value
+        if value is not None:
+            evaluation = functions.evaluate(value, self)
+            if evaluation is not None:
+                value = evaluation.value
+        return value
+
+    @value.setter
+    def value(self, value):
+        self._value = value
+
+    @property
+    @caching.cachedmethod
+    def owner(self):
+        """
+        The sole owner of this parameter, which is another model that relates to it.
+
+        *All* parameters should have an owner model. In case this property method fails to find
+        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
+        """
+
+        # Find first non-null relationship
+        for the_relationship in self.__mapper__.relationships:
+            v = getattr(self, the_relationship.key)
+            if v:
+                return v
+
+        raise ValueError('orphaned {class_name}: does not have an owner: {name}'.format(
+            class_name=type(self).__name__, name=self.name))
+
+    @property
+    @caching.cachedmethod
+    def container(self): # pylint: disable=too-many-return-statements,too-many-branches
+        """
+        The logical container for this parameter, which would be another model: service, node,
+        group, or policy (or their templates).
+
+        The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in
+        TOSCA.
+
+        *All* parameters should have a container model. In case this property method fails to find
+        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
+        """
+
+        from . import models
+
+        container = self.owner
+
+        # Extract interface from operation
+        if isinstance(container, models.Operation):
+            container = container.interface
+        elif isinstance(container, models.OperationTemplate):
+            container = container.interface_template
+
+        # Extract from other models
+        if isinstance(container, models.Interface):
+            container = container.node or container.group or container.relationship
+        elif isinstance(container, models.InterfaceTemplate):
+            container = container.node_template or container.group_template \
+                        or container.relationship_template
+        elif isinstance(container, models.Capability) or isinstance(container, models.Artifact):
+            container = container.node
+        elif isinstance(container, models.CapabilityTemplate) \
+                or isinstance(container, models.ArtifactTemplate):
+            container = container.node_template
+        elif isinstance(container, models.Task):
+            container = container.actor
+
+        # Extract node from relationship
+        if isinstance(container, models.Relationship):
+            container = container.source_node
+        elif isinstance(container, models.RelationshipTemplate):
+            container = container.requirement_template.node_template
+
+        if container is not None:
+            return container
+
+        raise ValueError('orphaned parameter: does not have a container: {0}'.format(self.name))
+
+    @property
+    @caching.cachedmethod
+    def service(self):
+        """
+        The :class:`Service` containing this parameter, or None if not contained in a service.
+        """
+
+        from . import models
+        container = self.container
+        if isinstance(container, models.Service):
+            return container
+        elif hasattr(container, 'service'):
+            return container.service
+        return None
+
+    @property
+    @caching.cachedmethod
+    def service_template(self):
+        """
+        The :class:`ServiceTemplate` containing this parameter, or None if not contained in a
+        service template.
+        """
+
+        from . import models
+        container = self.container
+        if isinstance(container, models.ServiceTemplate):
+            return container
+        elif hasattr(container, 'service_template'):
+            return container.service_template
+        return None
+
+    @property
+    def as_raw(self):
+        return collections.OrderedDict((
+            ('name', self.name),
+            ('type_name', self.type_name),
+            ('value', self.value),
+            ('description', self.description)))
+
+    def instantiate(self, container):
+        return self.__class__(name=self.name,  # pylint: disable=unexpected-keyword-arg
+                              type_name=self.type_name,
+                              _value=self._value,
+                              description=self.description)
+
+    def coerce_values(self, report_issues):
+        value = self._value
+        if value is not None:
+            evaluation = functions.evaluate(value, self, report_issues)
+            if (evaluation is not None) and evaluation.final:
+                # A final evaluation can safely replace the existing value
+                self._value = evaluation.value
+
+    def dump(self):
+        context = ConsumptionContext.get_thread_local()
+        if self.type_name is not None:
+            console.puts('{0}: {1} ({2})'.format(
+                context.style.property(self.name),
+                context.style.literal(formatting.as_raw(self.value)),
+                context.style.type(self.type_name)))
+        else:
+            console.puts('{0}: {1}'.format(
+                context.style.property(self.name),
+                context.style.literal(formatting.as_raw(self.value))))
+        if self.description:
+            console.puts(context.style.meta(self.description))
+
+    @property
+    def unwrapped(self):
+        return self.name, self.value
+
+    @classmethod
+    def wrap(cls, name, value, description=None):
+        """
+        Wraps an arbitrary value as a parameter. The type will be guessed via introspection.
+
+        For primitive types, we will prefer their TOSCA aliases. See the `TOSCA Simple Profile v1.0
+        cos01 specification <http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01
+        /TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc373867862>`__
+
+        :param name: Parameter name
+        :type name: basestring
+        :param value: Parameter value
+        :param description: Description (optional)
+        :type description: basestring
+        """
+
+        type_name = canonical_type_name(value)
+        if type_name is None:
+            type_name = full_type_name(value)
+        return cls(name=name,  # pylint: disable=unexpected-keyword-arg
+                   type_name=type_name,
+                   value=value,
+                   description=description)
+
+    def as_other_parameter_model(self, other_model_cls):
+
+        name, value = self.unwrapped
+        return other_model_cls.wrap(name, value)
+
+    def as_argument(self):
+        from . import models
+        return self.as_other_parameter_model(models.Argument)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/models.py
----------------------------------------------------------------------
diff --git a/aria/modeling/models.py b/aria/modeling/models.py
index 584b877..4102090 100644
--- a/aria/modeling/models.py
+++ b/aria/modeling/models.py
@@ -72,7 +72,11 @@ __all__ = (
     'ServiceModification',
 
     # Common service models
-    'Parameter',
+    'Input',
+    'Configuration',
+    'Output',
+    'Property',
+    'Attribute',
     'Type',
     'Metadata',
 
@@ -80,7 +84,8 @@ __all__ = (
     'Execution',
     'Plugin',
     'Task',
-    'Log'
+    'Log',
+    'Argument'
 )
 
 
@@ -206,7 +211,24 @@ class ServiceModification(aria_declarative_base, service_changes.ServiceModifica
 
 # region common service models
 
-class Parameter(aria_declarative_base, service_common.ParameterBase):
+
+class Input(aria_declarative_base, service_common.InputBase):
+    pass
+
+
+class Configuration(aria_declarative_base, service_common.ConfigurationBase):
+    pass
+
+
+class Output(aria_declarative_base, service_common.OutputBase):
+    pass
+
+
+class Property(aria_declarative_base, service_common.PropertyBase):
+    pass
+
+
+class Attribute(aria_declarative_base, service_common.AttributeBase):
     pass
 
 
@@ -237,6 +259,11 @@ class Task(aria_declarative_base, orchestration.TaskBase):
 class Log(aria_declarative_base, orchestration.LogBase):
     pass
 
+
+class Argument(aria_declarative_base, orchestration.ArgumentBase):
+    pass
+
+
 # endregion
 
 
@@ -276,7 +303,11 @@ models_to_register = [
     ServiceModification,
 
     # Common service models
-    Parameter,
+    Input,
+    Configuration,
+    Output,
+    Property,
+    Attribute,
     Type,
     Metadata,
 
@@ -284,5 +315,6 @@ models_to_register = [
     Execution,
     Plugin,
     Task,
-    Log
+    Log,
+    Argument
 ]

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index 97de552..995c8c2 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -39,7 +39,7 @@ from sqlalchemy.ext.associationproxy import association_proxy
 from sqlalchemy.ext.declarative import declared_attr
 
 from ..orchestrator.exceptions import (TaskAbortException, TaskRetryException)
-from .mixins import ModelMixin
+from .mixins import ModelMixin, ParameterMixin
 from . import (
     relationship,
     types as modeling_types
@@ -115,7 +115,7 @@ class ExecutionBase(ModelMixin):
 
     @declared_attr
     def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+        return relationship.one_to_many(cls, 'input', dict_key='name')
 
     # region foreign keys
 
@@ -233,7 +233,7 @@ class TaskBase(ModelMixin):
     :ivar function: Python path to an ``@operation`` function
     :vartype function: basestring
     :ivar arguments: Arguments that can be used by this task
-    :vartype arguments: {basestring: :class:`Parameter`}
+    :vartype arguments: {basestring: :class:`Argument`}
     :ivar max_attempts: Maximum number of retries allowed in case of failure
     :vartype max_attempts: int
     :ivar retry_interval: Interval between retries (in seconds)
@@ -301,7 +301,7 @@ class TaskBase(ModelMixin):
 
     @declared_attr
     def arguments(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='arguments', dict_key='name')
+        return relationship.one_to_many(cls, 'argument', dict_key='name')
 
     function = Column(String)
     max_attempts = Column(Integer, default=1)
@@ -433,3 +433,32 @@ class LogBase(ModelMixin):
     def __repr__(self):
         name = (self.task.actor if self.task else self.execution).name
         return '{name}: {self.msg}'.format(name=name, self=self)
+
+
+class ArgumentBase(ParameterMixin):
+
+    __tablename__ = 'argument'
+
+    # region foreign keys
+
+    @declared_attr
+    def task_fk(cls):
+        return relationship.foreign_key('task', nullable=True)
+
+    @declared_attr
+    def operation_fk(cls):
+        return relationship.foreign_key('operation', nullable=True)
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def task(cls):
+        return relationship.many_to_one(cls, 'task')
+
+    @declared_attr
+    def operation(cls):
+        return relationship.many_to_one(cls, 'operation')
+
+    # endregion

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index 1974424..f632fef 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -105,10 +105,6 @@ class ServiceUpdateBase(ModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     def to_dict(self, suppress_error=False, **kwargs):
         dep_update_dict = super(ServiceUpdateBase, self).to_dict(suppress_error)     #pylint: disable=no-member
         # Taking care of the fact the DeploymentSteps are _BaseModels
@@ -180,10 +176,6 @@ class ServiceUpdateStepBase(ModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     def __hash__(self):
         return hash((getattr(self, self.id_column_name()), self.entity_id))
 
@@ -266,7 +258,3 @@ class ServiceModificationBase(ModelMixin):
         return relationship.many_to_one(cls, 'service', back_populates='modifications')
 
     # endregion
-
-    # region many_to_many relationships
-
-    # endregion

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 8f844a2..272dfd7 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -18,218 +18,287 @@
 from sqlalchemy import (
     Column,
     Text,
-    PickleType
 )
 from sqlalchemy.ext.declarative import declared_attr
 
 from ..parser.consumption import ConsumptionContext
-from ..utils import (collections, formatting, console, caching)
-from ..utils.type import (canonical_type_name, full_type_name)
-from .mixins import (InstanceModelMixin, TemplateModelMixin)
-from . import (
-    relationship,
-    functions
+from ..utils import (
+    collections,
+    formatting,
+    console,
 )
+from .mixins import InstanceModelMixin, TemplateModelMixin, ParameterMixin
+from . import relationship
 
 
-class ParameterBase(TemplateModelMixin, caching.HasCachedMethods):
-    """
-    Represents a typed value. The value can contain nested intrinsic functions.
+class OutputBase(ParameterMixin):
 
-    This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`.
+    __tablename__ = 'output'
 
-    :ivar name: Name
-    :vartype name: basestring
-    :ivar type_name: Type name
-    :vartype type_name: basestring
-    :ivar value: Value
-    :ivar description: Description
-    :vartype description: basestring
-    """
+    # region foreign keys
 
-    __tablename__ = 'parameter'
+    @declared_attr
+    def service_template_fk(cls):
+        return relationship.foreign_key('service_template', nullable=True)
 
-    name = Column(Text)
-    type_name = Column(Text)
-    description = Column(Text)
-    _value = Column(PickleType)
+    @declared_attr
+    def service_fk(cls):
+        return relationship.foreign_key('service', nullable=True)
 
-    @property
-    def value(self):
-        value = self._value
-        if value is not None:
-            evaluation = functions.evaluate(value, self)
-            if evaluation is not None:
-                value = evaluation.value
-        return value
-
-    @value.setter
-    def value(self, value):
-        self._value = value
+    # endregion
 
-    @property
-    @caching.cachedmethod
-    def owner(self):
-        """
-        The sole owner of this parameter, which is another model that relates to it.
+    # region many_to_one relationships
 
-        *All* parameters should have an owner model. In case this property method fails to find
-        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
-        """
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
 
-        # Find first non-null relationship
-        for the_relationship in self.__mapper__.relationships:
-            v = getattr(self, the_relationship.key)
-            if v:
-                return v[0] # because we are many-to-many, the back reference will be a list
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
-        raise ValueError('orphaned parameter: does not have an owner: {0}'.format(self.name))
+    # endregion
 
 
-    @property
-    @caching.cachedmethod
-    def container(self): # pylint: disable=too-many-return-statements,too-many-branches
-        """
-        The logical container for this parameter, which would be another model: service, node,
-        group, or policy (or their templates).
+class InputBase(ParameterMixin):
 
-        The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions in
-        TOSCA.
+    __tablename__ = 'input'
 
-        *All* parameters should have a container model. In case this property method fails to find
-        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
-        """
+    # region foreign keys
 
-        from . import models
+    @declared_attr
+    def service_template_fk(cls):
+        return relationship.foreign_key('service_template', nullable=True)
 
-        container = self.owner
-
-        # Extract interface from operation
-        if isinstance(container, models.Operation):
-            container = container.interface
-        elif isinstance(container, models.OperationTemplate):
-            container = container.interface_template
-
-        # Extract from other models
-        if isinstance(container, models.Interface):
-            container = container.node or container.group or container.relationship
-        elif isinstance(container, models.InterfaceTemplate):
-            container = container.node_template or container.group_template \
-                or container.relationship_template
-        elif isinstance(container, models.Capability) or isinstance(container, models.Artifact):
-            container = container.node
-        elif isinstance(container, models.CapabilityTemplate) \
-            or isinstance(container, models.ArtifactTemplate):
-            container = container.node_template
-        elif isinstance(container, models.Task):
-            container = container.actor
-
-        # Extract node from relationship
-        if isinstance(container, models.Relationship):
-            container = container.source_node
-        elif isinstance(container, models.RelationshipTemplate):
-            container = container.requirement_template.node_template
-
-        if container is not None:
-            return container
-
-        raise ValueError('orphaned parameter: does not have a container: {0}'.format(self.name))
+    @declared_attr
+    def service_fk(cls):
+        return relationship.foreign_key('service', nullable=True)
 
-    @property
-    @caching.cachedmethod
-    def service(self):
-        """
-        The :class:`Service` containing this parameter, or None if not contained in a service.
-        """
+    @declared_attr
+    def interface_fk(cls):
+        return relationship.foreign_key('interface', nullable=True)
 
-        from . import models
-        container = self.container
-        if isinstance(container, models.Service):
-            return container
-        elif hasattr(container, 'service'):
-            return container.service
-        return None
+    @declared_attr
+    def operation_fk(cls):
+        return relationship.foreign_key('operation', nullable=True)
 
-    @property
-    @caching.cachedmethod
-    def service_template(self):
-        """
-        The :class:`ServiceTemplate` containing this parameter, or None if not contained in a
-        service template.
-        """
+    @declared_attr
+    def interface_template_fk(cls):
+        return relationship.foreign_key('interface_template', nullable=True)
 
-        from . import models
-        container = self.container
-        if isinstance(container, models.ServiceTemplate):
-            return container
-        elif hasattr(container, 'service_template'):
-            return container.service_template
-        return None
+    @declared_attr
+    def operation_template_fk(cls):
+        return relationship.foreign_key('operation_template', nullable=True)
 
-    @property
-    def as_raw(self):
-        return collections.OrderedDict((
-            ('name', self.name),
-            ('type_name', self.type_name),
-            ('value', self.value),
-            ('description', self.description)))
+    @declared_attr
+    def execution_fk(cls):
+        return relationship.foreign_key('execution', nullable=True)
 
-    def instantiate(self, container):
-        from . import models
-        return models.Parameter(name=self.name, # pylint: disable=unexpected-keyword-arg
-                                type_name=self.type_name,
-                                _value=self._value,
-                                description=self.description)
+    @declared_attr
+    def task_fk(cls):
+        return relationship.foreign_key('task', nullable=True)
 
-    def coerce_values(self, report_issues):
-        value = self._value
-        if value is not None:
-            evaluation = functions.evaluate(value, self, report_issues)
-            if (evaluation is not None) and evaluation.final:
-                # A final evaluation can safely replace the existing value
-                self._value = evaluation.value
+    # endregion
 
-    def dump(self):
-        context = ConsumptionContext.get_thread_local()
-        if self.type_name is not None:
-            console.puts('{0}: {1} ({2})'.format(
-                context.style.property(self.name),
-                context.style.literal(formatting.as_raw(self.value)),
-                context.style.type(self.type_name)))
-        else:
-            console.puts('{0}: {1}'.format(
-                context.style.property(self.name),
-                context.style.literal(formatting.as_raw(self.value))))
-        if self.description:
-            console.puts(context.style.meta(self.description))
+    # region many_to_one relationships
 
-    @property
-    def unwrapped(self):
-        return self.name, self.value
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
 
-    @classmethod
-    def wrap(cls, name, value, description=None):
-        """
-        Wraps an arbitrary value as a parameter. The type will be guessed via introspection.
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
+
+    @declared_attr
+    def interface(cls):
+        return relationship.many_to_one(cls, 'interface')
 
-        For primitive types, we will prefer their TOSCA aliases. See the `TOSCA Simple Profile v1.0
-        cos01 specification <http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/cos01
-        /TOSCA-Simple-Profile-YAML-v1.0-cos01.html#_Toc373867862>`__
+    @declared_attr
+    def operation(cls):
+        return relationship.many_to_one(cls, 'operation')
 
-        :param name: Parameter name
-        :type name: basestring
-        :param value: Parameter value
-        :param description: Description (optional)
-        :type description: basestring
-        """
+    @declared_attr
+    def interface_template(cls):
+        return relationship.many_to_one(cls, 'interface_template')
+
+    @declared_attr
+    def operation_template(cls):
+        return relationship.many_to_one(cls, 'operation_template')
+
+    @declared_attr
+    def execution(cls):
+        return relationship.many_to_one(cls, 'execution')
+
+    # endregion
+
+
+class ConfigurationBase(ParameterMixin):
+
+    __tablename__ = 'configuration'
+
+    # region foreign keys
+
+    @declared_attr
+    def operation_template_fk(cls):
+        return relationship.foreign_key('operation_template', nullable=True)
+
+    @declared_attr
+    def operation_fk(cls):
+        return relationship.foreign_key('operation', nullable=True)
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def operation_template(cls):
+        return relationship.many_to_one(cls, 'operation_template')
 
-        type_name = canonical_type_name(value)
-        if type_name is None:
-            type_name = full_type_name(value)
-        return cls(name=name, # pylint: disable=unexpected-keyword-arg
-                   type_name=type_name,
-                   value=value,
-                   description=description)
+    @declared_attr
+    def operation(cls):
+        return relationship.many_to_one(cls, 'operation')
+
+    # endregion
+
+
+class PropertyBase(ParameterMixin):
+
+    __tablename__ = 'property'
+
+    # region foreign keys
+
+    @declared_attr
+    def node_template_fk(cls):
+        return relationship.foreign_key('node_template', nullable=True)
+
+    @declared_attr
+    def group_template_fk(cls):
+        return relationship.foreign_key('group_template', nullable=True)
+
+    @declared_attr
+    def policy_template_fk(cls):
+        return relationship.foreign_key('policy_template', nullable=True)
+
+    @declared_attr
+    def relationship_template_fk(cls):
+        return relationship.foreign_key('relationship_template', nullable=True)
+
+    @declared_attr
+    def capability_template_fk(cls):
+        return relationship.foreign_key('capability_template', nullable=True)
+
+    @declared_attr
+    def artifact_template_fk(cls):
+        return relationship.foreign_key('artifact_template', nullable=True)
+
+    @declared_attr
+    def node_fk(cls):
+        return relationship.foreign_key('node', nullable=True)
+
+    @declared_attr
+    def group_fk(cls):
+        return relationship.foreign_key('group', nullable=True)
+
+    @declared_attr
+    def policy_fk(cls):
+        return relationship.foreign_key('policy', nullable=True)
+
+    @declared_attr
+    def relationship_fk(cls):
+        return relationship.foreign_key('relationship', nullable=True)
+
+    @declared_attr
+    def capability_fk(cls):
+        return relationship.foreign_key('capability', nullable=True)
+
+    @declared_attr
+    def artifact_fk(cls):
+        return relationship.foreign_key('artifact', nullable=True)
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def group_template(cls):
+        return relationship.many_to_one(cls, 'group_template')
+
+    @declared_attr
+    def policy_template(cls):
+        return relationship.many_to_one(cls, 'policy_template')
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.many_to_one(cls, 'relationship_template')
+
+    @declared_attr
+    def capability_template(cls):
+        return relationship.many_to_one(cls, 'capability_template')
+
+    @declared_attr
+    def artifact_template(cls):
+        return relationship.many_to_one(cls, 'artifact_template')
+
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def group(cls):
+        return relationship.many_to_one(cls, 'group')
+
+    @declared_attr
+    def policy(cls):
+        return relationship.many_to_one(cls, 'policy')
+
+    @declared_attr
+    def relationship(cls):
+        return relationship.many_to_one(cls, 'relationship')
+
+    @declared_attr
+    def capability(cls):
+        return relationship.many_to_one(cls, 'capability')
+
+    @declared_attr
+    def artifact(cls):
+        return relationship.many_to_one(cls, 'artifact')
+
+    # endregion
+
+
+class AttributeBase(ParameterMixin):
+
+    __tablename__ = 'attribute'
+
+    # region foreign keys
+
+    @declared_attr
+    def node_template_fk(cls):
+        """For Attribute many-to-one to NodeTemplate"""
+        return relationship.foreign_key('node_template', nullable=True)
+
+    @declared_attr
+    def node_fk(cls):
+        """For Attribute many-to-one to Node"""
+        return relationship.foreign_key('node', nullable=True)
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    # endregion
 
 
 class TypeBase(InstanceModelMixin):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 703873e..2bf9872 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -67,9 +67,9 @@ class ServiceBase(InstanceModelMixin):
     :ivar substitution: The entire service can appear as a node
     :vartype substitution: :class:`Substitution`
     :ivar inputs: Externally provided parameters
-    :vartype inputs: {basestring: :class:`Parameter`}
+    :vartype inputs: {basestring: :class:`Input`}
     :ivar outputs: These parameters are filled in after service installation
-    :vartype outputs: {basestring: :class:`Parameter`}
+    :vartype outputs: {basestring: :class:`Output`}
     :ivar workflows: Custom workflows that can be performed on the service
     :vartype workflows: {basestring: :class:`Operation`}
     :ivar plugins: Plugins used by the service
@@ -125,6 +125,14 @@ class ServiceBase(InstanceModelMixin):
     # region one_to_many relationships
 
     @declared_attr
+    def outputs(cls):
+        return relationship.one_to_many(cls, 'output', dict_key='name')
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.one_to_many(cls, 'input', dict_key='name')
+
+    @declared_attr
     def updates(cls):
         return relationship.one_to_many(cls, 'service_update')
 
@@ -170,14 +178,6 @@ class ServiceBase(InstanceModelMixin):
         return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def outputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
-
-    @declared_attr
     def plugins(cls):
         return relationship.many_to_many(cls, 'plugin', dict_key='name')
 
@@ -324,7 +324,7 @@ class NodeBase(InstanceModelMixin):
     :ivar description: Human-readable description
     :vartype description: string
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interface`}
     :ivar artifacts: Associated files
@@ -465,6 +465,14 @@ class NodeBase(InstanceModelMixin):
         return relationship.one_to_many(cls, 'interface', dict_key='name')
 
     @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
+    @declared_attr
+    def attributes(cls):
+        return relationship.one_to_many(cls, 'attribute', dict_key='name')
+
+    @declared_attr
     def artifacts(cls):
         return relationship.one_to_many(cls, 'artifact', dict_key='name')
 
@@ -510,17 +518,6 @@ class NodeBase(InstanceModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    @declared_attr
-    def attributes(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='attributes', dict_key='name')
-
-    # endregion
-
     description = Column(Text)
     state = Column(Enum(*STATES, name='node_state'), nullable=False, default=INITIAL)
     version = Column(Integer, default=1)
@@ -714,7 +711,7 @@ class GroupBase(InstanceModelMixin):
     :ivar nodes: Members of this group
     :vartype nodes: [:class:`Node`]
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interface`}
     :ivar service: Containing service
@@ -757,6 +754,10 @@ class GroupBase(InstanceModelMixin):
     # region one_to_many relationships
 
     @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
+    @declared_attr
     def interfaces(cls):
         return relationship.one_to_many(cls, 'interface', dict_key='name')
 
@@ -784,10 +785,6 @@ class GroupBase(InstanceModelMixin):
     def nodes(cls):
         return relationship.many_to_many(cls, 'node')
 
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # endregion
 
     description = Column(Text)
@@ -842,7 +839,7 @@ class PolicyBase(InstanceModelMixin):
     :ivar groups: Policy will be enacted on all nodes in these groups
     :vartype groups: [:class:`Group`]
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar service: Containing service
     :vartype service: :class:`Service`
     """
@@ -880,6 +877,10 @@ class PolicyBase(InstanceModelMixin):
 
     # region one_to_many relationships
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -901,10 +902,6 @@ class PolicyBase(InstanceModelMixin):
     # region many_to_many relationships
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    @declared_attr
     def nodes(cls):
         return relationship.many_to_many(cls, 'node')
 
@@ -1014,10 +1011,6 @@ class SubstitutionBase(InstanceModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1122,10 +1115,6 @@ class SubstitutionMappingBase(InstanceModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1170,7 +1159,7 @@ class RelationshipBase(InstanceModelMixin):
     :ivar target_capability: Capability at the target node (optional)
     :vartype target_capability: :class:`Capability`
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interfaces`}
     :ivar source_position: The position of the relationship in the outbound relationships.
@@ -1262,6 +1251,10 @@ class RelationshipBase(InstanceModelMixin):
     def interfaces(cls):
         return relationship.one_to_many(cls, 'interface', dict_key='name')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1290,14 +1283,6 @@ class RelationshipBase(InstanceModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    # endregion
-
     source_position = Column(Integer)
     target_position = Column(Integer)
 
@@ -1364,7 +1349,7 @@ class CapabilityBase(InstanceModelMixin):
     :ivar occurrences: Actual number of requirement matches
     :vartype occurrences: int
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar node: Containing node
     :vartype node: :class:`Node`
     :ivar relationship: Available when we are the target of a relationship
@@ -1408,6 +1393,10 @@ class CapabilityBase(InstanceModelMixin):
 
     # region one_to_many relationships
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1426,14 +1415,6 @@ class CapabilityBase(InstanceModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    # endregion
-
     min_occurrences = Column(Integer, default=None)
     max_occurrences = Column(Integer, default=None)
     occurrences = Column(Integer, default=0)
@@ -1492,8 +1473,8 @@ class InterfaceBase(InstanceModelMixin):
     :vartype type: :class:`Type`
     :ivar description: Human-readable description
     :vartype description: string
-    :ivar inputs: Parameters that can be used by all operations in the interface
-    :vartype inputs: {basestring: :class:`Parameter`}
+    :ivar inputs: Inputs that can be used by all operations in the interface
+    :vartype inputs: {basestring: :class:`Input`}
     :ivar operations: Operations
     :vartype operations: {basestring: :class:`Operation`}
     :ivar node: Containing node
@@ -1552,6 +1533,10 @@ class InterfaceBase(InstanceModelMixin):
     # region one_to_many relationships
 
     @declared_attr
+    def inputs(cls):
+        return relationship.one_to_many(cls, 'input', dict_key='name')
+
+    @declared_attr
     def operations(cls):
         return relationship.one_to_many(cls, 'operation', dict_key='name')
 
@@ -1581,14 +1566,6 @@ class InterfaceBase(InstanceModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    # endregion
-
     description = Column(Text)
 
     def configure_operations(self):
@@ -1643,16 +1620,16 @@ class OperationBase(InstanceModelMixin):
     :vartype implementation: basestring
     :ivar dependencies: Dependency strings (interpreted by the plugin)
     :vartype dependencies: [basestring]
-    :ivar inputs: Parameters that can be used by this operation
-    :vartype inputs: {basestring: :class:`Parameter`}
+    :ivar inputs: Input that can be used by this operation
+    :vartype inputs: {basestring: :class:`Input`}
     :ivar plugin: Associated plugin
     :vartype plugin: :class:`Plugin`
-    :ivar configuration: Configuration (interpreted by the plugin)
-    :vartype configuration: {basestring, :class:`Parameter`}
+    :ivar configurations: Configuration (interpreted by the plugin)
+    :vartype configurations: {basestring, :class:`Configuration`}
     :ivar function: Name of the operation function
     :vartype function: basestring
     :ivar arguments: Arguments to send to the operation function
-    :vartype arguments: {basestring: :class:`Parameter`}
+    :vartype arguments: {basestring: :class:`Argument`}
     :ivar executor: Name of executor to run the operation with
     :vartype executor: basestring
     :ivar max_attempts: Maximum number of attempts allowed in case of failure
@@ -1710,6 +1687,18 @@ class OperationBase(InstanceModelMixin):
 
     # region one_to_many relationships
 
+    @declared_attr
+    def inputs(cls):
+        return relationship.one_to_many(cls, 'input', dict_key='name')
+
+    @declared_attr
+    def configurations(cls):
+        return relationship.one_to_many(cls, 'configuration', dict_key='name')
+
+    @declared_attr
+    def arguments(cls):
+        return relationship.one_to_many(cls, 'argument', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1730,18 +1719,6 @@ class OperationBase(InstanceModelMixin):
 
     # region many_to_many relationships
 
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def configuration(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='configuration', dict_key='name')
-
-    @declared_attr
-    def arguments(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='arguments', dict_key='name')
-
     # endregion
 
     description = Column(Text)
@@ -1765,11 +1742,19 @@ class OperationBase(InstanceModelMixin):
             # In the future plugins may be able to add their own "configure_operation" hook that
             # can validate the configuration and otherwise create specially derived arguments. For
             # now, we just send all configuration parameters as arguments without validation.
-            utils.instantiate_dict(self, self.arguments, self.configuration)
+            configurations_as_arguments = {}
+            for configuration in self.configurations.itervalues():
+                configurations_as_arguments[configuration.name] = configuration.as_argument()
+
+            utils.instantiate_dict(self, self.arguments, configurations_as_arguments)
 
         # Send all inputs as extra arguments
         # Note that they will override existing arguments of the same names
-        utils.instantiate_dict(self, self.arguments, self.inputs)
+        inputs_as_arguments = {}
+        for input in self.inputs.itervalues():
+            inputs_as_arguments[input.name] = input.as_argument()
+
+        utils.instantiate_dict(self, self.arguments, inputs_as_arguments)
 
         # Check for reserved arguments
         from ..orchestrator.decorators import OPERATION_DECORATOR_RESERVED_ARGUMENTS
@@ -1796,12 +1781,12 @@ class OperationBase(InstanceModelMixin):
     def validate(self):
         # TODO must be associated with either interface or service
         utils.validate_dict_values(self.inputs)
-        utils.validate_dict_values(self.configuration)
+        utils.validate_dict_values(self.configurations)
         utils.validate_dict_values(self.arguments)
 
     def coerce_values(self, report_issues):
         utils.coerce_dict_values(self.inputs, report_issues)
-        utils.coerce_dict_values(self.configuration, report_issues)
+        utils.coerce_dict_values(self.configurations, report_issues)
         utils.coerce_dict_values(self.arguments, report_issues)
 
     def dump(self):
@@ -1828,7 +1813,7 @@ class OperationBase(InstanceModelMixin):
             if self.plugin is not None:
                 console.puts('Plugin: {0}'.format(
                     context.style.literal(self.plugin.name)))
-            utils.dump_dict_values(self.configuration, 'Configuration')
+            utils.dump_dict_values(self.configurations, 'Configuration')
             if self.function is not None:
                 console.puts('Function: {0}'.format(context.style.literal(self.function)))
             utils.dump_dict_values(self.arguments, 'Arguments')
@@ -1857,7 +1842,7 @@ class ArtifactBase(InstanceModelMixin):
     :ivar repository_credential: Credentials for accessing the repository
     :vartype repository_credential: {basestring: basestring}
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar node: Containing node
     :vartype node: :class:`Node`
     """
@@ -1897,6 +1882,10 @@ class ArtifactBase(InstanceModelMixin):
 
     # region one_to_many relationships
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1913,12 +1902,6 @@ class ArtifactBase(InstanceModelMixin):
         return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
     # endregion
 
-    # region many_to_many relationships
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-    # endregion
-
     description = Column(Text)
     source_path = Column(Text)
     target_path = Column(Text)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 42e0d01..4d1e837 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -67,9 +67,9 @@ class ServiceTemplateBase(TemplateModelMixin):
     :ivar substitution_template: The entire service can appear as a node
     :vartype substitution_template: :class:`SubstitutionTemplate`
     :ivar inputs: Externally provided parameters
-    :vartype inputs: {basestring: :class:`Parameter`}
+    :vartype inputs: {basestring: :class:`Input`}
     :ivar outputs: These parameters are filled in after service installation
-    :vartype outputs: {basestring: :class:`Parameter`}
+    :vartype outputs: {basestring: :class:`Output`}
     :ivar workflow_templates: Custom workflows that can be performed on the service
     :vartype workflow_templates: {basestring: :class:`OperationTemplate`}
     :ivar plugin_specifications: Plugins used by the service
@@ -215,6 +215,14 @@ class ServiceTemplateBase(TemplateModelMixin):
         return relationship.one_to_many(cls, 'node_template', dict_key='name')
 
     @declared_attr
+    def outputs(cls):
+        return relationship.one_to_many(cls, 'output', dict_key='name')
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.one_to_many(cls, 'input', dict_key='name')
+
+    @declared_attr
     def group_templates(cls):
         return relationship.one_to_many(cls, 'group_template', dict_key='name')
 
@@ -243,14 +251,6 @@ class ServiceTemplateBase(TemplateModelMixin):
         # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
         return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def outputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
-
     # endregion
 
     @property
@@ -287,7 +287,7 @@ class ServiceTemplateBase(TemplateModelMixin):
                                  service_template=self)
         context.modeling.instance = service
 
-        service.inputs = utils.merge_parameter_values(inputs, self.inputs)
+        service.inputs = utils.merge_parameter_values(inputs, self.inputs, model_cls=models.Input)
         # TODO: now that we have inputs, we should scan properties and inputs and evaluate functions
 
         for plugin_specification in self.plugin_specifications.itervalues():
@@ -413,7 +413,7 @@ class NodeTemplateBase(TemplateModelMixin):
     :ivar max_instances: Maximum number nodes that will appear in the service
     :vartype max_instances: int
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
     :ivar artifact_templates: Associated files
@@ -495,6 +495,14 @@ class NodeTemplateBase(TemplateModelMixin):
     def requirement_templates(cls):
         return relationship.one_to_many(cls, 'requirement_template', child_fk='node_template_fk')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
+    @declared_attr
+    def attributes(cls):
+        return relationship.one_to_many(cls, 'attribute', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -509,18 +517,6 @@ class NodeTemplateBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    @declared_attr
-    def attributes(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='attributes', dict_key='name')
-
-    # endregion
-
     description = Column(Text)
     default_instances = Column(Integer, default=1)
     min_instances = Column(Integer, default=0)
@@ -629,7 +625,7 @@ class GroupTemplateBase(TemplateModelMixin):
     :ivar node_templates: All nodes instantiated by these templates will be members of the group
     :vartype node_templates: [:class:`NodeTemplate`]
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
     :ivar service_template: Containing service template
@@ -677,6 +673,10 @@ class GroupTemplateBase(TemplateModelMixin):
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -697,10 +697,6 @@ class GroupTemplateBase(TemplateModelMixin):
     def node_templates(cls):
         return relationship.many_to_many(cls, 'node_template')
 
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # endregion
 
     description = Column(Text)
@@ -765,7 +761,7 @@ class PolicyTemplateBase(TemplateModelMixin):
     :ivar group_templates: Policy will be enacted on all nodes in these groups
     :vartype group_templates: [:class:`GroupTemplate`]
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar policies: Instantiated policies
@@ -804,6 +800,10 @@ class PolicyTemplateBase(TemplateModelMixin):
     def policies(cls):
         return relationship.one_to_many(cls, 'policy')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -828,10 +828,6 @@ class PolicyTemplateBase(TemplateModelMixin):
     def group_templates(cls):
         return relationship.many_to_many(cls, 'group_template')
 
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # endregion
 
     description = Column(Text)
@@ -936,10 +932,6 @@ class SubstitutionTemplateBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1051,10 +1043,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1219,10 +1207,6 @@ class RequirementTemplateBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    # endregion
-
     target_capability_name = Column(Text)
     target_node_template_constraints = Column(PickleType)
 
@@ -1343,7 +1327,7 @@ class RelationshipTemplateBase(TemplateModelMixin):
     :ivar description: Human-readable description
     :vartype description: basestring
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
     :ivar requirement_template: Containing requirement template
@@ -1383,6 +1367,10 @@ class RelationshipTemplateBase(TemplateModelMixin):
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1393,14 +1381,6 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    # endregion
-
     description = Column(Text)
 
     @property
@@ -1462,7 +1442,7 @@ class CapabilityTemplateBase(TemplateModelMixin):
     :ivar max_occurrences: Maximum number of requirement matches allowed
     :vartype min_occurrences: int
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar substitution_template_mapping: Our contribution to service substitution
@@ -1505,6 +1485,10 @@ class CapabilityTemplateBase(TemplateModelMixin):
     def capabilities(cls):
         return relationship.one_to_many(cls, 'capability')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1525,10 +1509,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
     def valid_source_node_types(cls):
         return relationship.many_to_many(cls, 'type', prefix='valid_sources')
 
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # endregion
 
     description = Column(Text)
@@ -1616,8 +1596,8 @@ class InterfaceTemplateBase(TemplateModelMixin):
     :vartype type: :class:`Type`
     :ivar description: Human-readable description
     :vartype description: basestring
-    :ivar inputs: Parameters that can be used by all operations in the interface
-    :vartype inputs: {basestring: :class:`Parameter`}
+    :ivar inputs: Inputs that can be used by all operations in the interface
+    :vartype inputs: {basestring: :class:`Input`}
     :ivar operation_templates: Operations
     :vartype operation_templates: {basestring: :class:`OperationTemplate`}
     :ivar node_template: Containing node template
@@ -1637,7 +1617,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
                           'group_template_fk',
                           'relationship_template_fk']
 
-
     # region foreign keys
 
     @declared_attr
@@ -1662,7 +1641,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     # endregion
 
-
     # region association proxies
 
     # endregion
@@ -1674,6 +1652,10 @@ class InterfaceTemplateBase(TemplateModelMixin):
     # region one_to_many relationships
 
     @declared_attr
+    def inputs(cls):
+        return relationship.one_to_many(cls, 'input', dict_key='name')
+
+    @declared_attr
     def interfaces(cls):
         return relationship.one_to_many(cls, 'interface')
 
@@ -1703,14 +1685,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    # endregion
-
     description = Column(Text)
 
     @property
@@ -1770,12 +1744,12 @@ class OperationTemplateBase(TemplateModelMixin):
     :vartype implementation: basestring
     :ivar dependencies: Dependency strings (interpreted by the plugin)
     :vartype dependencies: [basestring]
-    :ivar inputs: Parameters that can be used by this operation
-    :vartype inputs: {basestring: :class:`Parameter`}
+    :ivar inputs: Inputs that can be used by this operation
+    :vartype inputs: {basestring: :class:`Input`}
     :ivar plugin_specification: Associated plugin
     :vartype plugin_specification: :class:`PluginSpecification`
-    :ivar configuration: Configuration (interpreted by the plugin)
-    :vartype configuration: {basestring, :class:`Parameter`}
+    :ivar configurations: Configuration (interpreted by the plugin)
+    :vartype configurations: {basestring, :class:`Configuration`}
     :ivar function: Name of the operation function
     :vartype function: basestring
     :ivar executor: Name of executor to run the operation with
@@ -1833,9 +1807,17 @@ class OperationTemplateBase(TemplateModelMixin):
     # region one_to_many relationships
 
     @declared_attr
+    def inputs(cls):
+        return relationship.one_to_many(cls, 'input', dict_key='name')
+
+    @declared_attr
     def operations(cls):
         return relationship.one_to_many(cls, 'operation')
 
+    @declared_attr
+    def configurations(cls):
+        return relationship.one_to_many(cls, 'configuration', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -1853,14 +1835,6 @@ class OperationTemplateBase(TemplateModelMixin):
 
     # region many_to_many relationships
 
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def configuration(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='configuration', dict_key='name')
-
     # endregion
 
     description = Column(Text)
@@ -1901,17 +1875,17 @@ class OperationTemplateBase(TemplateModelMixin):
                                      operation_template=self)
 
         utils.instantiate_dict(container, operation.inputs, self.inputs)
-        utils.instantiate_dict(container, operation.configuration, self.configuration)
+        utils.instantiate_dict(container, operation.configurations, self.configurations)
 
         return operation
 
     def validate(self):
         utils.validate_dict_values(self.inputs)
-        utils.validate_dict_values(self.configuration)
+        utils.validate_dict_values(self.configurations)
 
     def coerce_values(self, report_issues):
         utils.coerce_dict_values(self.inputs, report_issues)
-        utils.coerce_dict_values(self.configuration, report_issues)
+        utils.coerce_dict_values(self.configurations, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1936,7 +1910,7 @@ class OperationTemplateBase(TemplateModelMixin):
             if self.plugin_specification is not None:
                 console.puts('Plugin specification: {0}'.format(
                     context.style.literal(self.plugin_specification.name)))
-            utils.dump_dict_values(self.configuration, 'Configuration')
+            utils.dump_dict_values(self.configurations, 'Configuration')
             if self.function is not None:
                 console.puts('Function: {0}'.format(context.style.literal(self.function)))
 
@@ -1960,7 +1934,7 @@ class ArtifactTemplateBase(TemplateModelMixin):
     :ivar repository_credential: Credentials for accessing the repository
     :vartype repository_credential: {basestring: basestring}
     :ivar properties: Associated parameters
-    :vartype properties: {basestring: :class:`Parameter`}
+    :vartype properties: {basestring: :class:`Property`}
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar artifacts: Instantiated artifacts
@@ -2000,6 +1974,10 @@ class ArtifactTemplateBase(TemplateModelMixin):
     def artifacts(cls):
         return relationship.one_to_many(cls, 'artifact')
 
+    @declared_attr
+    def properties(cls):
+        return relationship.one_to_many(cls, 'property', dict_key='name')
+
     # endregion
 
     # region many_to_one relationships
@@ -2014,14 +1992,6 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     # endregion
 
-    # region many_to_many relationships
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    # endregion
-
     description = Column(Text)
     source_path = Column(Text)
     target_path = Column(Text)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/modeling/utils.py
----------------------------------------------------------------------
diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py
index 66e9c99..43be410 100644
--- a/aria/modeling/utils.py
+++ b/aria/modeling/utils.py
@@ -53,7 +53,7 @@ class NodeTemplateContainerHolder(object):
         return self.container.service_template
 
 
-def merge_parameter_values(parameter_values, declared_parameters):
+def merge_parameter_values(parameter_values, declared_parameters, model_cls):
     """
     Merges parameter values according to those declared by a type.
 
@@ -74,8 +74,6 @@ def merge_parameter_values(parameter_values, declared_parameters):
             ``parameter_values`` does not match its type in ``declared_parameters``
     """
 
-    from . import models
-
     parameter_values = parameter_values or {}
 
     undeclared_names = list(set(parameter_values.keys()).difference(declared_parameters.keys()))
@@ -106,7 +104,7 @@ def merge_parameter_values(parameter_values, declared_parameters):
                 pass
 
             # Wrap in Parameter model
-            parameters[declared_parameter_name] = models.Parameter( # pylint: disable=unexpected-keyword-arg
+            parameters[declared_parameter_name] = model_cls( # pylint: disable=unexpected-keyword-arg
                 name=declared_parameter_name,
                 type_name=type_name,
                 description=declared_parameter.description,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/orchestrator/context/collection_instrumentation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/context/collection_instrumentation.py b/aria/orchestrator/context/collection_instrumentation.py
index 91cfd35..8f80d4a 100644
--- a/aria/orchestrator/context/collection_instrumentation.py
+++ b/aria/orchestrator/context/collection_instrumentation.py
@@ -84,7 +84,7 @@ class _InstrumentedCollection(object):
         :param value:
         :return:
         """
-        if isinstance(value, models.Parameter):
+        if isinstance(value, models.Attribute):
             return value.value
         return value
 
@@ -96,10 +96,10 @@ class _InstrumentedCollection(object):
         :param value:
         :return:
         """
-        if isinstance(value, models.Parameter):
+        if isinstance(value, models.Attribute):
             return value
         # If it is not wrapped
-        return models.Parameter.wrap(key, value)
+        return models.Attribute.wrap(key, value)
 
     def __setitem__(self, key, value):
         """
@@ -112,7 +112,7 @@ class _InstrumentedCollection(object):
         if self._is_top_level:
             # We are at the top level
             field = getattr(self._parent, self._field_name)
-            mapi = getattr(self._model, models.Parameter.__modelname__)
+            mapi = getattr(self._model, models.Attribute.__modelname__)
             value = self._set_field(field,
                                     key,
                                     value if key in field else self._encapsulate_value(key, value))
@@ -131,7 +131,7 @@ class _InstrumentedCollection(object):
         """
         if isinstance(value, _InstrumentedCollection):
             value = value._raw
-        if key in collection and isinstance(collection[key], models.Parameter):
+        if key in collection and isinstance(collection[key], models.Attribute):
             if isinstance(collection[key], _InstrumentedCollection):
                 self._del(collection, key)
             collection[key].value = value

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/orchestrator/execution_plugin/instantiation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/execution_plugin/instantiation.py b/aria/orchestrator/execution_plugin/instantiation.py
index 9b5152d..b067e8c 100644
--- a/aria/orchestrator/execution_plugin/instantiation.py
+++ b/aria/orchestrator/execution_plugin/instantiation.py
@@ -42,7 +42,7 @@ def configure_operation(operation):
 
     # Any remaining un-handled configuration parameters will become extra arguments, available as
     # kwargs in either "run_script_locally" or "run_script_with_ssh"
-    for key, value in operation.configuration.iteritems():
+    for key, value in operation.configurations.iteritems():
         if key not in ('process', 'ssh'):
             operation.arguments[key] = value.instantiate(None)
 
@@ -52,11 +52,11 @@ def _configure_common(operation):
     Local and remote operations.
     """
 
-    from ...modeling.models import Parameter
-    operation.arguments['script_path'] = Parameter.wrap('script_path', operation.implementation,
-                                                        'Relative path to the executable file.')
-    operation.arguments['process'] = Parameter.wrap('process', _get_process(operation),
-                                                    'Sub-process configuration.')
+    from ...modeling.models import Argument
+    operation.arguments['script_path'] = Argument.wrap('script_path', operation.implementation,
+                                                       'Relative path to the executable file.')
+    operation.arguments['process'] = Argument.wrap('process', _get_process(operation),
+                                                   'Sub-process configuration.')
 
 
 def _configure_local(operation):
@@ -74,7 +74,7 @@ def _configure_remote(operation):
     Remote SSH operation via Fabric.
     """
 
-    from ...modeling.models import Parameter
+    from ...modeling.models import Argument
     from . import operations
 
     ssh = _get_ssh(operation)
@@ -88,11 +88,11 @@ def _configure_remote(operation):
     if ('password' not in ssh) and ('key' not in ssh) and ('key_filename' not in ssh):
         ssh['password'] = default_password
 
-    operation.arguments['use_sudo'] = Parameter.wrap('use_sudo', ssh.get('use_sudo', False),
-                                                     'Whether to execute with sudo.')
+    operation.arguments['use_sudo'] = Argument.wrap('use_sudo', ssh.get('use_sudo', False),
+                                                    'Whether to execute with sudo.')
 
-    operation.arguments['hide_output'] = Parameter.wrap('hide_output', ssh.get('hide_output', []),
-                                                        'Hide output of these Fabric groups.')
+    operation.arguments['hide_output'] = Argument.wrap('hide_output', ssh.get('hide_output', []),
+                                                       'Hide output of these Fabric groups.')
 
     fabric_env = {}
     if 'warn_only' in ssh:
@@ -121,16 +121,17 @@ def _configure_remote(operation):
                                   .format(operation.implementation),
                                   level=validation.Issue.BETWEEN_TYPES)
 
-    operation.arguments['fabric_env'] = Parameter.wrap('fabric_env', fabric_env,
-                                                       'Fabric configuration.')
+    operation.arguments['fabric_env'] = Argument.wrap('fabric_env', fabric_env,
+                                                      'Fabric configuration.')
 
     operation.function = '{0}.{1}'.format(operations.__name__,
                                           operations.run_script_with_ssh.__name__)
 
 
 def _get_process(operation):
-    value = operation.configuration.get('process')._value \
-        if 'process' in operation.configuration else None
+    value = (operation.configurations.get('process')._value
+             if 'process' in operation.configurations
+             else None)
     if value is None:
         return {}
     _validate_type(value, dict, 'process')
@@ -155,8 +156,9 @@ def _get_process(operation):
 
 
 def _get_ssh(operation):
-    value = operation.configuration.get('ssh')._value \
-        if 'ssh' in operation.configuration else None
+    value = (operation.configurations.get('ssh')._value
+             if 'ssh' in operation.configurations
+             else None)
     if value is None:
         return {}
     _validate_type(value, dict, 'ssh')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/orchestrator/workflow_runner.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflow_runner.py b/aria/orchestrator/workflow_runner.py
index 15a55b0..848c59b 100644
--- a/aria/orchestrator/workflow_runner.py
+++ b/aria/orchestrator/workflow_runner.py
@@ -120,7 +120,9 @@ class WorkflowRunner(object):
         else:
             workflow_inputs = self.service.workflows[self._workflow_name].inputs
 
-        execution.inputs = modeling_utils.merge_parameter_values(inputs, workflow_inputs)
+        execution.inputs = modeling_utils.merge_parameter_values(inputs,
+                                                                 workflow_inputs,
+                                                                 model_cls=models.Input)
         # TODO: these two following calls should execute atomically
         self._validate_no_active_executions(execution)
         self._model_storage.execution.put(execution)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/orchestrator/workflows/api/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task.py b/aria/orchestrator/workflows/api/task.py
index feacaf4..bcba56e 100644
--- a/aria/orchestrator/workflows/api/task.py
+++ b/aria/orchestrator/workflows/api/task.py
@@ -70,7 +70,7 @@ class OperationTask(BaseTask):
     :ivar function: path to Python function
     :vartype function: basestring
     :ivar arguments: arguments to send to Python function
-    :vartype arguments: {basestring, :class:`aria.modeling.models.Parameter`}
+    :vartype arguments: {basestring, :class:`aria.modeling.models.Argument`}
     :ivar ignore_failure: whether to ignore failures
     :vartype ignore_failure: bool
     :ivar max_attempts: maximum number of attempts allowed in case of failure
@@ -139,7 +139,9 @@ class OperationTask(BaseTask):
         operation = self.actor.interfaces[self.interface_name].operations[self.operation_name]
         self.plugin = operation.plugin
         self.function = operation.function
-        self.arguments = modeling_utils.merge_parameter_values(arguments, operation.arguments)
+        self.arguments = modeling_utils.merge_parameter_values(arguments,
+                                                               operation.arguments,
+                                                               model_cls=models.Argument)
 
     def __repr__(self):
         return self.name

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/aria/orchestrator/workflows/executor/dry.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/executor/dry.py b/aria/orchestrator/workflows/executor/dry.py
index 8848df8..72080b4 100644
--- a/aria/orchestrator/workflows/executor/dry.py
+++ b/aria/orchestrator/workflows/executor/dry.py
@@ -45,7 +45,7 @@ class DryExecutor(BaseExecutor):
             logger(dry_msg.format(name=name, task=task, suffix='started...'))
             logger(dry_msg.format(name=name, task=task, suffix='successful'))
         else:
-            logger(dry_msg.format(name=name, task=task, suffix='has no function'))
+            logger(dry_msg.format(name=name, task=task, suffix='has no implementation'))
 
         # updating the task manually instead of calling self._task_succeeded(task),
         # to avoid any side effects raising that event might cause

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/examples/hello-world/helloworld.yaml
----------------------------------------------------------------------
diff --git a/examples/hello-world/helloworld.yaml b/examples/hello-world/helloworld.yaml
index 77cef30..be78401 100644
--- a/examples/hello-world/helloworld.yaml
+++ b/examples/hello-world/helloworld.yaml
@@ -29,4 +29,4 @@ topology_template:
         Standard:
           configure: scripts/configure.sh
           start: scripts/start.sh
-          stop: scripts/stop.sh
+          stop: scripts/stop.sh
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b6d3c43b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
index 440cb96..5813ccf 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -36,7 +36,8 @@ from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate,
                                   RequirementTemplate, RelationshipTemplate, CapabilityTemplate,
                                   GroupTemplate, PolicyTemplate, SubstitutionTemplate,
                                   SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate,
-                                  ArtifactTemplate, Metadata, Parameter, PluginSpecification)
+                                  ArtifactTemplate, Metadata, Input, Output, Property,
+                                  Attribute, Configuration, PluginSpecification)
 
 from .parameters import coerce_parameter_value
 from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange,
@@ -94,9 +95,11 @@ def create_service_template_model(context): # pylint: disable=too-many-locals,to
     topology_template = context.presentation.get('service_template', 'topology_template')
     if topology_template is not None:
         create_parameter_models_from_values(model.inputs,
-                                            topology_template._get_input_values(context))
+                                            topology_template._get_input_values(context),
+                                            model_cls=Input)
         create_parameter_models_from_values(model.outputs,
-                                            topology_template._get_output_values(context))
+                                            topology_template._get_output_values(context),
+                                            model_cls=Output)
 
     # Plugin specifications
     policies = context.presentation.get('service_template', 'topology_template', 'policies')
@@ -172,9 +175,11 @@ def create_node_template_model(context, service_template, node_template):
         model.description = node_template.description.value
 
     create_parameter_models_from_values(model.properties,
-                                        node_template._get_property_values(context))
+                                        node_template._get_property_values(context),
+                                        model_cls=Property)
     create_parameter_models_from_values(model.attributes,
-                                        node_template._get_attribute_default_values(context))
+                                        node_template._get_attribute_default_values(context),
+                                        model_cls=Attribute)
     create_interface_template_models(context, service_template, model.interface_templates,
                                      node_template._get_interfaces(context))
 
@@ -219,7 +224,8 @@ def create_group_template_model(context, service_template, group):
     if group.description:
         model.description = group.description.value
 
-    create_parameter_models_from_values(model.properties, group._get_property_values(context))
+    create_parameter_models_from_values(model.properties, group._get_property_values(context),
+                                        model_cls=Property)
     create_interface_template_models(context, service_template, model.interface_templates,
                                      group._get_interfaces(context))
 
@@ -242,7 +248,8 @@ def create_policy_template_model(context, service_template, policy):
     if policy.description:
         model.description = policy.description.value
 
-    create_parameter_models_from_values(model.properties, policy._get_property_values(context))
+    create_parameter_models_from_values(model.properties, policy._get_property_values(context),
+                                        model_cls=Property)
 
     node_templates, groups = policy._get_targets(context)
     if node_templates:
@@ -311,7 +318,9 @@ def create_relationship_template_model(context, service_template, relationship):
         if relationship_template.description:
             model.description = relationship_template.description.value
 
-    create_parameter_models_from_assignments(model.properties, relationship.properties)
+    create_parameter_models_from_assignments(model.properties,
+                                             relationship.properties,
+                                             model_cls=Property)
     create_interface_template_models(context, service_template, model.interface_templates,
                                      relationship.interfaces)
 
@@ -340,7 +349,9 @@ def create_capability_template_model(context, service_template, capability):
             node_type = service_template.node_types.get_descendant(valid_source_type)
             model.valid_source_node_types.append(node_type)
 
-    create_parameter_models_from_assignments(model.properties, capability.properties)
+    create_parameter_models_from_assignments(model.properties,
+                                             capability.properties,
+                                             model_cls=Property)
 
     return model
 
@@ -357,10 +368,10 @@ def create_interface_template_model(context, service_template, interface):
     inputs = interface.inputs
     if inputs:
         for input_name, the_input in inputs.iteritems():
-            model.inputs[input_name] = Parameter(name=input_name, # pylint: disable=unexpected-keyword-arg
-                                                 type_name=the_input.value.type,
-                                                 value=the_input.value.value,
-                                                 description=the_input.value.description)
+            model.inputs[input_name] = Input(name=input_name, # pylint: disable=unexpected-keyword-arg
+                                             type_name=the_input.value.type,
+                                             value=the_input.value.value,
+                                             description=the_input.value.description)
 
     operations = interface.operations
     if operations:
@@ -417,18 +428,18 @@ def create_operation_template_model(context, service_template, operation):
                         model.dependencies = []
                     model.dependencies.append(dependency)
 
-        # Convert configuration to Parameter models
+        # Convert configuration to Configuration models
         for key, value in configuration.iteritems():
-            model.configuration[key] = Parameter.wrap(key, value,
-                                                      description='Operation configuration.')
+            model.configurations[key] = Configuration.wrap(key, value,
+                                                           description='Operation configuration.')
 
     inputs = operation.inputs
     if inputs:
         for input_name, the_input in inputs.iteritems():
-            model.inputs[input_name] = Parameter(name=input_name, # pylint: disable=unexpected-keyword-arg
-                                                 type_name=the_input.value.type,
-                                                 value=the_input.value.value,
-                                                 description=the_input.value.description)
+            model.inputs[input_name] = Input(name=input_name, # pylint: disable=unexpected-keyword-arg
+                                             type_name=the_input.value.type,
+                                             value=the_input.value.value,
+                                             description=the_input.value.description)
 
     return model
 
@@ -454,7 +465,8 @@ def create_artifact_template_model(context, service_template, artifact):
             for k, v in credential.iteritems():
                 model.repository_credential[k] = v
 
-    create_parameter_models_from_values(model.properties, artifact._get_property_values(context))
+    create_parameter_models_from_values(model.properties, artifact._get_property_values(context),
+                                        model_cls=Property)
 
     return model
 
@@ -519,10 +531,10 @@ def create_workflow_operation_template_model(context, service_template, policy):
         if prop_name == 'implementation':
             model.function = prop.value
         else:
-            model.inputs[prop_name] = Parameter(name=prop_name, # pylint: disable=unexpected-keyword-arg
-                                                type_name=prop.type,
-                                                value=prop.value,
-                                                description=prop.description)
+            model.inputs[prop_name] = Input(name=prop_name, # pylint: disable=unexpected-keyword-arg
+                                            type_name=prop.type,
+                                            value=prop.value,
+                                            description=prop.description)
 
     used_reserved_names = WORKFLOW_DECORATOR_RESERVED_ARGUMENTS.intersection(model.inputs.keys())
     if used_reserved_names:
@@ -570,19 +582,20 @@ def create_types(context, root, types):
                         container.children.append(model)
 
 
-def create_parameter_models_from_values(properties, source_properties):
+def create_parameter_models_from_values(properties, source_properties, model_cls):
+
     if source_properties:
         for property_name, prop in source_properties.iteritems():
-            properties[property_name] = Parameter(name=property_name, # pylint: disable=unexpected-keyword-arg
+            properties[property_name] = model_cls(name=property_name,  # pylint: disable=unexpected-keyword-arg
                                                   type_name=prop.type,
                                                   value=prop.value,
                                                   description=prop.description)
 
 
-def create_parameter_models_from_assignments(properties, source_properties):
+def create_parameter_models_from_assignments(properties, source_properties, model_cls):
     if source_properties:
         for property_name, prop in source_properties.iteritems():
-            properties[property_name] = Parameter(name=property_name, # pylint: disable=unexpected-keyword-arg
+            properties[property_name] = model_cls(name=property_name, # pylint: disable=unexpected-keyword-arg
                                                   type_name=prop.value.type,
                                                   value=prop.value.value,
                                                   description=prop.value.description)