ARIA-149 Enhance operation configuration

* Parse special "dependencies" configuration parameters as YAML and
  treat as Parameter models, allowing them full use of intrinsic
  functions, type coersions, and validations
* Rename various functions that process "properties" to more generically
  process "parameters" (properties, inputs, attributes, arguments, etc.)
* The "configuration" field in OperationTemplate and Operation models
  is now now a dict of Parameter models
* Added "function" and "arguments" fields to Operation model to preserve
  user data (in "implementation" and "inputs") and to clearly demarcate
  orchestration data from user data
* Some cleanup of parser code touched by this commit


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

Branch: refs/heads/ARIA-149-functions-in-operation-configuration
Commit: 8fe7f4b1c89c44793a0db6cdb1e78c2722934334
Parents: 07d7951
Author: Tal Liron <tal.li...@gmail.com>
Authored: Thu Apr 20 17:54:47 2017 -0500
Committer: Tal Liron <tal.li...@gmail.com>
Committed: Tue May 30 13:03:04 2017 -0500

----------------------------------------------------------------------
 aria/cli/commands/services.py                   |   2 +-
 aria/core.py                                    |  14 +-
 aria/modeling/constraints.py                    |  28 +++
 aria/modeling/contraints.py                     |  28 ---
 aria/modeling/exceptions.py                     |  16 +-
 aria/modeling/service_common.py                 |   4 +
 aria/modeling/service_instance.py               |  69 +++---
 aria/modeling/service_template.py               |  54 ++---
 aria/modeling/utils.py                          | 105 ++++-----
 .../execution_plugin/instantiation.py           | 133 +++++++-----
 aria/orchestrator/workflow_runner.py            |   2 +-
 aria/orchestrator/workflows/api/task.py         |   4 +-
 aria/orchestrator/workflows/core/task.py        |   1 -
 .../profiles/aria-1.0/aria-1.0.yaml             |  16 +-
 .../simple_v1_0/assignments.py                  |   4 +-
 .../simple_v1_0/modeling/__init__.py            |  65 ++++--
 .../simple_v1_0/modeling/artifacts.py           |   2 +-
 .../simple_v1_0/modeling/capabilities.py        |  24 ++-
 .../simple_v1_0/modeling/constraints.py         |   2 +-
 .../simple_v1_0/modeling/data_types.py          |  16 ++
 .../simple_v1_0/modeling/interfaces.py          |  34 ++-
 .../simple_v1_0/modeling/parameters.py          | 211 +++++++++++++++++++
 .../simple_v1_0/modeling/policies.py            |   2 +
 .../simple_v1_0/modeling/properties.py          | 202 ------------------
 .../simple_v1_0/modeling/requirements.py        |  20 +-
 .../modeling/substitution_mappings.py           |   4 +
 .../simple_v1_0/templates.py                    |  13 +-
 .../aria_extension_tosca/simple_v1_0/types.py   |  24 +--
 tests/cli/test_services.py                      |  14 +-
 tests/mock/models.py                            |  10 +-
 tests/mock/topology.py                          |  12 +-
 tests/orchestrator/context/test_operation.py    |  53 +++--
 tests/orchestrator/context/test_serialize.py    |   2 +-
 tests/orchestrator/context/test_toolbelt.py     |  14 +-
 .../orchestrator/execution_plugin/test_local.py |  10 +-
 tests/orchestrator/execution_plugin/test_ssh.py |  12 +-
 tests/orchestrator/test_workflow_runner.py      |   8 +-
 tests/orchestrator/workflows/api/test_task.py   |  26 +--
 .../workflows/builtin/test_execute_operation.py |   2 +-
 .../orchestrator/workflows/core/test_engine.py  |   6 +-
 .../orchestrator/workflows/core/test_events.py  |   3 +-
 tests/orchestrator/workflows/core/test_task.py  |   6 +-
 .../test_task_graph_into_execution_graph.py     |   2 +-
 ...process_executor_concurrent_modifications.py |  10 +-
 .../executor/test_process_executor_extension.py |  13 +-
 .../test_process_executor_tracked_changes.py    |   8 +-
 .../node-cellar/node-cellar.yaml                |  24 ++-
 47 files changed, 737 insertions(+), 597 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/cli/commands/services.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py
index 24de7c5..476387c 100644
--- a/aria/cli/commands/services.py
+++ b/aria/cli/commands/services.py
@@ -151,7 +151,7 @@ def create(service_template_name,
     except storage_exceptions.StorageError as e:
         utils.check_overriding_storage_exceptions(e, 'service', service_name)
         raise
-    except modeling_exceptions.InputsException:
+    except modeling_exceptions.ParameterException:
         service_templates.print_service_template_inputs(model_storage, 
service_template_name,
                                                         logger)
         raise

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/core.py
----------------------------------------------------------------------
diff --git a/aria/core.py b/aria/core.py
index cc943ef..f660167 100644
--- a/aria/core.py
+++ b/aria/core.py
@@ -56,7 +56,8 @@ class Core(object):
         service_template = 
self.model_storage.service_template.get(service_template_id)
         if service_template.services:
             raise exceptions.DependentServicesError(
-                "Can't delete service template {0} - Service template has 
existing services")
+                'Can\'t delete service template `{0}` - service template has 
existing services'
+                .format(service_template.name))
 
         self.model_storage.service_template.delete(service_template)
         
self.resource_storage.service_template.delete(entry_id=str(service_template.id))
@@ -87,7 +88,8 @@ class Core(object):
                     consumption.CoerceServiceInstanceValues
                 )).consume()
             if context.validation.dump_issues():
-                raise exceptions.InstantiationError('Failed to instantiate 
service template')
+                raise exceptions.InstantiationError('Failed to instantiate 
service template `{0}`'
+                                                    
.format(service_template.name))
 
         storage_session.flush()  # flushing so service.id would auto-populate
         service.name = service_name or '{0}_{1}'.format(service_template.name, 
service.id)
@@ -100,15 +102,15 @@ class Core(object):
         active_executions = [e for e in service.executions if e.is_active()]
         if active_executions:
             raise exceptions.DependentActiveExecutionsError(
-                "Can't delete service {0} - there is an active execution for 
this service. "
-                "Active execution id: {1}".format(service.name, 
active_executions[0].id))
+                'Can\'t delete service `{0}` - there is an active execution 
for this service. '
+                'Active execution ID: {1}'.format(service.name, 
active_executions[0].id))
 
         if not force:
             available_nodes = [str(n.id) for n in service.nodes.values() if 
n.is_available()]
             if available_nodes:
                 raise exceptions.DependentAvailableNodesError(
-                    "Can't delete service {0} - there are available nodes for 
this service. "
-                    "Available node ids: {1}".format(service.name, ', 
'.join(available_nodes)))
+                    'Can\'t delete service `{0}` - there are available nodes 
for this service. '
+                    'Available node IDs: {1}'.format(service.name, ', 
'.join(available_nodes)))
 
         self.model_storage.service.delete(service)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/constraints.py
----------------------------------------------------------------------
diff --git a/aria/modeling/constraints.py b/aria/modeling/constraints.py
new file mode 100644
index 0000000..107b010
--- /dev/null
+++ b/aria/modeling/constraints.py
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class NodeTemplateConstraint(object):
+    """
+    Used to constrain requirements for node templates.
+
+    Must be serializable.
+    """
+
+    def matches(self, source_node_template, target_node_template):
+        """
+        Returns true is the target matches the constraint for the source.
+        """
+        raise NotImplementedError

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/contraints.py
----------------------------------------------------------------------
diff --git a/aria/modeling/contraints.py b/aria/modeling/contraints.py
deleted file mode 100644
index 107b010..0000000
--- a/aria/modeling/contraints.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-class NodeTemplateConstraint(object):
-    """
-    Used to constrain requirements for node templates.
-
-    Must be serializable.
-    """
-
-    def matches(self, source_node_template, target_node_template):
-        """
-        Returns true is the target matches the constraint for the source.
-        """
-        raise NotImplementedError

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/exceptions.py
----------------------------------------------------------------------
diff --git a/aria/modeling/exceptions.py b/aria/modeling/exceptions.py
index 19fd942..d0e3e22 100644
--- a/aria/modeling/exceptions.py
+++ b/aria/modeling/exceptions.py
@@ -22,9 +22,9 @@ class ModelingException(AriaException):
     """
 
 
-class InputsException(ModelingException):
+class ParameterException(ModelingException):
     """
-    ARIA inputs exception.
+    ARIA parameter exception.
     """
     pass
 
@@ -41,19 +41,19 @@ class CannotEvaluateFunctionException(ModelingException):
     """
 
 
-class MissingRequiredInputsException(InputsException):
+class MissingRequiredParametersException(ParameterException):
     """
-    ARIA modeling exception: Required inputs have been omitted.
+    ARIA modeling exception: Required parameters have been omitted.
     """
 
 
-class InputsOfWrongTypeException(InputsException):
+class ParametersOfWrongTypeException(ParameterException):
     """
-    ARIA modeling exception: Inputs of the wrong types have been provided.
+    ARIA modeling exception: Parameters of the wrong types have been provided.
     """
 
 
-class UndeclaredInputsException(InputsException):
+class UndeclaredParametersException(ParameterException):
     """
-    ARIA modeling exception: Undeclared inputs have been provided.
+    ARIA modeling exception: Undeclared parameters have been provided.
     """

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index ef19c8e..3bae490 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -211,6 +211,10 @@ class ParameterBase(TemplateModelMixin, 
caching.HasCachedMethods):
         """
         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

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py 
b/aria/modeling/service_instance.py
index 7058969..31f7212 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -1631,20 +1631,24 @@ class OperationBase(InstanceModelMixin):
     :vartype operation_template: :class:`OperationTemplate`
     :ivar description: Human-readable description
     :vartype description: string
-    :ivar plugin: Associated plugin
-    :vartype plugin: :class:`Plugin`
     :ivar relationship_edge: When true specified that the operation is on the 
relationship's
                              target edge instead of its source (only used by 
relationship
                              operations)
     :vartype relationship_edge: bool
     :ivar implementation: Implementation (interpreted by the plugin)
     :vartype implementation: basestring
-    :ivar configuration: Configuration (interpreted by the plugin)
-    :vartype configuration: {basestring, object}
     :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 plugin: Associated plugin
+    :vartype plugin: :class:`Plugin`
+    :ivar configuration: Configuration (interpreted by the plugin)
+    :vartype configuration: {basestring, :class:`Parameter`}
+    :ivar function: Name of the operation function
+    :vartype function: basestring
+    :ivar arguments: Arguments to send to the operation function
+    :vartype arguments: {basestring: :class:`Parameter`}
     :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
@@ -1726,34 +1730,41 @@ class OperationBase(InstanceModelMixin):
     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)
     relationship_edge = Column(Boolean)
     implementation = Column(Text)
-    configuration = Column(modeling_types.StrictDict(key_cls=basestring))
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
+    function = Column(Text)
     executor = Column(Text)
     max_attempts = Column(Integer)
     retry_interval = Column(Integer)
 
     def configure(self):
-        from . import models
-        # Note: for workflows (operations attached directly to the service) 
"interface" will be None
-        if (self.implementation is None) or (self.interface is None):
+        if (self.implementation is None) and (self.function is None):
             return
 
-        if self.plugin is None:
-            arguments = 
execution_plugin.instantiation.configure_operation(self)
+        if (self.plugin is None) and (self.interface is not None):
+            # Default to execution plugin ("interface" is None for workflow 
operations)
+            execution_plugin.instantiation.configure_operation(self)
         else:
             # In the future plugins may be able to add their own 
"configure_operation" hook that
-            # can validate the configuration and otherwise return specially 
derived arguments
-            arguments = self.configuration
+            # can validate the configuration and otherwise create specially 
derived arguments. For
+            # now, we just send all configuration parameters as arguments
+            utils.instantiate_dict(self, self.arguments, self.configuration)
 
-        # Note: the arguments will *override* operation inputs of the same name
-        if arguments:
-            for k, v in arguments.iteritems():
-                self.inputs[k] = models.Parameter.wrap(k, v)
+        # 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)
 
     @property
     def as_raw(self):
@@ -1762,17 +1773,18 @@ class OperationBase(InstanceModelMixin):
             ('description', self.description),
             ('implementation', self.implementation),
             ('dependencies', self.dependencies),
-            ('executor', self.executor),
-            ('max_attempts', self.max_attempts),
-            ('retry_interval', self.retry_interval),
             ('inputs', formatting.as_raw_dict(self.inputs))))
 
     def validate(self):
-        # TODO must be associated with interface or service
+        # 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.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.arguments, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1780,21 +1792,14 @@ class OperationBase(InstanceModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            if self.plugin is not None:
-                console.puts('Plugin: {0}'.format(
-                    context.style.literal(self.plugin.name)))
             if self.implementation is not None:
                 console.puts('Implementation: {0}'.format(
                     context.style.literal(self.implementation)))
-            if self.configuration:
-                with context.style.indent:
-                    for k, v in self.configuration.iteritems():
-                        console.puts('{0}: 
{1}'.format(context.style.property(k),
-                                                       
context.style.literal(v)))
             if self.dependencies:
                 console.puts(
                     'Dependencies: {0}'.format(
                         ', '.join((str(context.style.literal(v)) for v in 
self.dependencies))))
+            utils.dump_dict_values(self.inputs, 'Inputs')
             if self.executor is not None:
                 console.puts('Executor: 
{0}'.format(context.style.literal(self.executor)))
             if self.max_attempts is not None:
@@ -1802,7 +1807,13 @@ class OperationBase(InstanceModelMixin):
             if self.retry_interval is not None:
                 console.puts('Retry interval: {0}'.format(
                     context.style.literal(self.retry_interval)))
-            utils.dump_dict_values(self.inputs, 'Inputs')
+            if self.plugin is not None:
+                console.puts('Plugin: {0}'.format(
+                    context.style.literal(self.plugin.name)))
+            utils.dump_dict_values(self.configuration, 'Configuration')
+            if self.function is not None:
+                console.puts('Function: 
{0}'.format(context.style.literal(self.function)))
+            utils.dump_dict_values(self.arguments, 'Arguments')
 
 
 class ArtifactBase(InstanceModelMixin):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py 
b/aria/modeling/service_template.py
index 3110248..b4a54ca 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -287,7 +287,7 @@ class ServiceTemplateBase(TemplateModelMixin):
                                  service_template=self)
         context.modeling.instance = service
 
-        service.inputs = utils.create_inputs(inputs or {}, self.inputs)
+        service.inputs = utils.create_parameters(inputs or {}, self.inputs)
         # TODO: now that we have inputs, we should scan properties and inputs 
and evaluate functions
 
         for plugin_specification in self.plugin_specifications.itervalues():
@@ -1762,20 +1762,22 @@ class OperationTemplateBase(TemplateModelMixin):
     :vartype name: basestring
     :ivar description: Human-readable description
     :vartype description: basestring
-    :ivar plugin_specification: Associated plugin
-    :vartype plugin_specification: :class:`PluginSpecification`
     :ivar relationship_edge: When true specified that the operation is on the 
relationship's
                              target edge instead of its source (only used by 
relationship
                              operations)
     :vartype relationship_edge: bool
     :ivar implementation: Implementation (interpreted by the plugin)
     :vartype implementation: basestring
-    :ivar configuration: Configuration (interpreted by the plugin)
-    :vartype configuration: {basestring, object}
     :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 plugin_specification: Associated plugin
+    :vartype plugin_specification: :class:`PluginSpecification`
+    :ivar configuration: Configuration (interpreted by the plugin)
+    :vartype configuration: {basestring, :class:`Parameter`}
+    :ivar function: Name of the operation function
+    :vartype function: basestring
     :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
@@ -1855,13 +1857,17 @@ class OperationTemplateBase(TemplateModelMixin):
     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)
     relationship_edge = Column(Boolean)
     implementation = Column(Text)
-    configuration = Column(modeling_types.StrictDict(key_cls=basestring))
     dependencies = Column(modeling_types.StrictList(item_cls=basestring))
+    function = Column(Text)
     executor = Column(Text)
     max_attempts = Column(Integer)
     retry_interval = Column(Integer)
@@ -1873,9 +1879,6 @@ class OperationTemplateBase(TemplateModelMixin):
             ('description', self.description),
             ('implementation', self.implementation),
             ('dependencies', self.dependencies),
-            ('executor', self.executor),
-            ('max_attempts', self.max_attempts),
-            ('retry_interval', self.retry_interval),
             ('inputs', formatting.as_raw_dict(self.inputs))))
 
     def instantiate(self, container):
@@ -1883,38 +1886,41 @@ class OperationTemplateBase(TemplateModelMixin):
         if self.plugin_specification:
             if self.plugin_specification.enabled:
                 plugin = self.plugin_specification.plugin
-                implementation = self.implementation if plugin is not None 
else None
+                function = self.function if plugin is not None else None
                 # "plugin" would be none if a match was not found. In that 
case, a validation error
                 # should already have been reported in 
ServiceTemplateBase.instantiate, so we will
                 # continue silently here
             else:
                 # If the plugin is disabled, the operation should be disabled, 
too
                 plugin = None
-                implementation = None
+                function = None
         else:
-            # Using the execution plugin
+            # Using the default execution plugin (plugin=None)
             plugin = None
-            implementation = self.implementation
+            function = self.function
 
         operation = models.Operation(name=self.name,
                                      
description=deepcopy_with_locators(self.description),
                                      relationship_edge=self.relationship_edge,
-                                     plugin=plugin,
-                                     implementation=implementation,
-                                     configuration=self.configuration,
+                                     implementation=self.implementation,
                                      dependencies=self.dependencies,
                                      executor=self.executor,
+                                     plugin=plugin,
+                                     function=function,
                                      max_attempts=self.max_attempts,
                                      retry_interval=self.retry_interval,
                                      operation_template=self)
         utils.instantiate_dict(container, operation.inputs, self.inputs)
+        utils.instantiate_dict(container, operation.configuration, 
self.configuration)
         return operation
 
     def validate(self):
         utils.validate_dict_values(self.inputs)
+        utils.validate_dict_values(self.configuration)
 
     def coerce_values(self, report_issues):
         utils.coerce_dict_values(self.inputs, report_issues)
+        utils.coerce_dict_values(self.configuration, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1922,20 +1928,13 @@ class OperationTemplateBase(TemplateModelMixin):
         if self.description:
             console.puts(context.style.meta(self.description))
         with context.style.indent:
-            if self.plugin_specification is not None:
-                console.puts('Plugin specification: {0}'.format(
-                    context.style.literal(self.plugin_specification.name)))
             if self.implementation is not None:
                 console.puts('Implementation: {0}'.format(
                     context.style.literal(self.implementation)))
-            if self.configuration:
-                with context.style.indent:
-                    for k, v in self.configuration.iteritems():
-                        console.puts('{0}: 
{1}'.format(context.style.property(k),
-                                                       
context.style.literal(v)))
             if self.dependencies:
                 console.puts('Dependencies: {0}'.format(
                     ', '.join((str(context.style.literal(v)) for v in 
self.dependencies))))
+            utils.dump_dict_values(self.inputs, 'Inputs')
             if self.executor is not None:
                 console.puts('Executor: 
{0}'.format(context.style.literal(self.executor)))
             if self.max_attempts is not None:
@@ -1943,7 +1942,12 @@ class OperationTemplateBase(TemplateModelMixin):
             if self.retry_interval is not None:
                 console.puts('Retry interval: {0}'.format(
                     context.style.literal(self.retry_interval)))
-            utils.dump_dict_values(self.inputs, 'Inputs')
+            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')
+            if self.function is not None:
+                console.puts('Function: 
{0}'.format(context.style.literal(self.function)))
 
 
 class ArtifactTemplateBase(TemplateModelMixin):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/modeling/utils.py
----------------------------------------------------------------------
diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py
index 0404fe4..6f4022c 100644
--- a/aria/modeling/utils.py
+++ b/aria/modeling/utils.py
@@ -21,6 +21,7 @@ from . import exceptions
 from ..parser.consumption import ConsumptionContext
 from ..utils.console import puts
 from ..utils.type import validate_value_type
+from ..utils.collections import OrderedDict
 
 
 class ModelJSONEncoder(JSONEncoder):
@@ -39,7 +40,7 @@ class ModelJSONEncoder(JSONEncoder):
 class NodeTemplateContainerHolder(object):
     """
     Wrapper that allows using a :class:`aria.modeling.models.NodeTemplate` 
model directly as the
-    ``container_holder`` argument for :func:`aria.modeling.functions.evaluate`.
+    ``container_holder`` input for :func:`aria.modeling.functions.evaluate`.
     """
 
     def __init__(self, node_template):
@@ -51,74 +52,84 @@ class NodeTemplateContainerHolder(object):
         return self.container.service_template
 
 
-def create_inputs(inputs, template_inputs):
+def create_parameters(parameters, declared_parameters):
     """
-    :param inputs: key-value dict
-    :param template_inputs: parameter name to parameter object dict
-    :return: dict of parameter name to Parameter models
+    Validates, merges, and wraps parameter values according to those declared 
by a type.
+
+    Exceptions will be raised for validation errors:
+
+    * :class:`aria.modeling.exceptions.UndeclaredParametersException` if a key 
in ``parameters``
+      does not exist in ``declared_parameters``
+    * :class:`aria.modeling.exceptions.MissingRequiredParametersException` if 
a key in
+      ``declared_parameters`` does not exist in ``parameters`` and also has no 
default value
+    * :class:`aria.modeling.exceptions.ParametersOfWrongTypeException` if a 
value in ``parameters``
+      does not match its type in ``declared_parameters``
+
+    :param parameters: Provided parameter values
+    :type parameters: {basestring, object}
+    :param declared_parameters: Declared parameters
+    :type declared_parameters: {basestring, 
:class:`aria.modeling.models.Parameter`}
+    :return: The merged parameters
+    :rtype: {basestring, :class:`aria.modeling.models.Parameter`}
     """
-    merged_inputs = _merge_and_validate_inputs(inputs, template_inputs)
+
+    merged_parameters = _merge_and_validate_parameters(parameters, 
declared_parameters)
 
     from . import models
-    input_models = []
-    for input_name, input_val in merged_inputs.iteritems():
+    parameters_models = OrderedDict()
+    for parameter_name, parameter_value in merged_parameters.iteritems():
         parameter = models.Parameter( # pylint: disable=unexpected-keyword-arg
-            name=input_name,
-            type_name=template_inputs[input_name].type_name,
-            description=template_inputs[input_name].description,
-            value=input_val)
-        input_models.append(parameter)
+            name=parameter_name,
+            type_name=declared_parameters[parameter_name].type_name,
+            description=declared_parameters[parameter_name].description,
+            value=parameter_value)
+        parameters_models[parameter.name] = parameter
 
-    return dict((inp.name, inp) for inp in input_models)
+    return parameters_models
 
 
-def _merge_and_validate_inputs(inputs, template_inputs):
-    """
-    :param inputs: key-value dict
-    :param template_inputs: parameter name to parameter object dict
-    :return:
-    """
-    merged_inputs = inputs.copy()
-
-    missing_inputs = []
-    wrong_type_inputs = {}
-    for input_name, input_template in template_inputs.iteritems():
-        if input_name not in inputs:
-            if input_template.value is not None:
-                merged_inputs[input_name] = input_template.value  # apply 
default value
+def _merge_and_validate_parameters(parameters, declared_parameters):
+    merged_parameters = OrderedDict(parameters)
+
+    missing_parameters = []
+    wrong_type_parameters = OrderedDict()
+    for parameter_name, declared_parameter in declared_parameters.iteritems():
+        if parameter_name not in parameters:
+            if declared_parameter.value is not None:
+                merged_parameters[parameter_name] = declared_parameter.value  
# apply default value
             else:
-                missing_inputs.append(input_name)
+                missing_parameters.append(parameter_name)
         else:
-            # Validate input type
+            # Validate parameter type
             try:
-                validate_value_type(inputs[input_name], 
input_template.type_name)
+                validate_value_type(parameters[parameter_name], 
declared_parameter.type_name)
             except ValueError:
-                wrong_type_inputs[input_name] = input_template.type_name
+                wrong_type_parameters[parameter_name] = 
declared_parameter.type_name
             except RuntimeError:
                 # TODO: This error shouldn't be raised (or caught), but right 
now we lack support
                 # for custom data_types, which will raise this error. Skipping 
their validation.
                 pass
 
-    if missing_inputs:
-        raise exceptions.MissingRequiredInputsException(
-            'Required inputs {0} have not been specified - expected inputs: 
{1}'
-            .format(missing_inputs, template_inputs.keys()))
+    if missing_parameters:
+        raise exceptions.MissingRequiredParametersException(
+            'Required parameters {0} have not been specified; Expected 
parameters: {1}'
+            .format(missing_parameters, declared_parameters.keys()))
 
-    if wrong_type_inputs:
+    if wrong_type_parameters:
         error_message = StringIO()
-        for param_name, param_type in wrong_type_inputs.iteritems():
-            error_message.write('Input "{0}" must be of type {1}{2}'
+        for param_name, param_type in wrong_type_parameters.iteritems():
+            error_message.write('Parameter "{0}" must be of type {1}{2}'
                                 .format(param_name, param_type, os.linesep))
-        raise exceptions.InputsOfWrongTypeException(error_message.getvalue())
+        raise 
exceptions.ParametersOfWrongTypeException(error_message.getvalue())
 
-    undeclared_inputs = [input_name for input_name in inputs.keys()
-                         if input_name not in template_inputs]
-    if undeclared_inputs:
-        raise exceptions.UndeclaredInputsException(
-            'Undeclared inputs have been specified: {0}; Expected inputs: {1}'
-            .format(undeclared_inputs, template_inputs.keys()))
+    undeclared_parameters = [parameter_name for parameter_name in 
parameters.keys()
+                             if parameter_name not in declared_parameters]
+    if undeclared_parameters:
+        raise exceptions.UndeclaredParametersException(
+            'Undeclared parameters have been specified: {0}; Expected 
parameters: {1}'
+            .format(undeclared_parameters, declared_parameters.keys()))
 
-    return merged_inputs
+    return merged_parameters
 
 
 def coerce_dict_values(the_dict, report_issues=False):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/orchestrator/execution_plugin/instantiation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/execution_plugin/instantiation.py 
b/aria/orchestrator/execution_plugin/instantiation.py
index c09434e..26c3913 100644
--- a/aria/orchestrator/execution_plugin/instantiation.py
+++ b/aria/orchestrator/execution_plugin/instantiation.py
@@ -16,19 +16,13 @@
 # TODO: this module will eventually be moved to a new "aria.instantiation" 
package
 
 from ...utils.type import full_type_name
-from ...utils.collections import OrderedDict
+from ...utils.formatting import safe_repr
 from ...parser import validation
 from ...parser.consumption import ConsumptionContext
+from ...modeling.functions import Function
 
 
 def configure_operation(operation):
-    configuration = OrderedDict(operation.configuration) if 
operation.configuration else {}
-
-    arguments = OrderedDict()
-    arguments['script_path'] = operation.implementation
-    arguments['process'] = _get_process(configuration.pop('process')) \
-        if 'process' in configuration else dict()
-
     host = None
     interface = operation.interface
     if interface.node is not None:
@@ -36,87 +30,118 @@ def configure_operation(operation):
     elif interface.relationship is not None:
         if operation.relationship_edge is True:
             host = interface.relationship.target_node.host
-        else: # either False or None
+        else: # either False or None (None meaning that edge was not specified)
             host = interface.relationship.source_node.host
 
+    _configure_common(operation)
     if host is None:
         _configure_local(operation)
     else:
-        _configure_remote(operation, configuration, arguments)
+        _configure_remote(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():
+        if key not in ('process', 'ssh'):
+            operation.arguments[key] = value.instantiate()
 
-    # Any remaining unhandled configuration values will become extra 
arguments, available as kwargs
-    # in either "run_script_locally" or "run_script_with_ssh"
-    arguments.update(configuration)
 
-    return arguments
+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.')
+
 
 def _configure_local(operation):
     """
     Local operation.
     """
+
     from . import operations
-    operation.implementation = '{0}.{1}'.format(operations.__name__,
-                                                
operations.run_script_locally.__name__)
+    operation.function = '{0}.{1}'.format(operations.__name__,
+                                          
operations.run_script_locally.__name__)
 
 
-def _configure_remote(operation, configuration, arguments):
+def _configure_remote(operation):
     """
     Remote SSH operation via Fabric.
     """
+
+    from ...modeling.models import Parameter
+    from . import operations
+
+    ssh = _get_ssh(operation)
+
+    # Defaults
     # TODO: find a way to configure these generally in the service template
     default_user = ''
     default_password = ''
-
-    ssh = _get_ssh(configuration.pop('ssh')) if 'ssh' in configuration else {}
     if 'user' not in ssh:
         ssh['user'] = default_user
     if ('password' not in ssh) and ('key' not in ssh) and ('key_filename' not 
in ssh):
         ssh['password'] = default_password
 
-    arguments['use_sudo'] = ssh.get('use_sudo', False)
-    arguments['hide_output'] = ssh.get('hide_output', [])
-    arguments['fabric_env'] = {}
+    operation.arguments['use_sudo'] = Parameter.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.')
+
+    fabric_env = {}
     if 'warn_only' in ssh:
-        arguments['fabric_env']['warn_only'] = ssh['warn_only']
-    arguments['fabric_env']['user'] = ssh.get('user')
-    arguments['fabric_env']['password'] = ssh.get('password')
-    arguments['fabric_env']['key'] = ssh.get('key')
-    arguments['fabric_env']['key_filename'] = ssh.get('key_filename')
+        fabric_env['warn_only'] = ssh['warn_only']
+    fabric_env['user'] = ssh.get('user')
+    fabric_env['password'] = ssh.get('password')
+    fabric_env['key'] = ssh.get('key')
+    fabric_env['key_filename'] = ssh.get('key_filename')
     if 'address' in ssh:
-        arguments['fabric_env']['host_string'] = ssh['address']
+        fabric_env['host_string'] = ssh['address']
 
-    if arguments['fabric_env'].get('user') is None:
+    # Make sure we have a user
+    if fabric_env.get('user') is None:
         context = ConsumptionContext.get_thread_local()
         context.validation.report('must configure "ssh.user" for "{0}"'
                                   .format(operation.implementation),
                                   level=validation.Issue.BETWEEN_TYPES)
-    if (arguments['fabric_env'].get('password') is None) and \
-        (arguments['fabric_env'].get('key') is None) and \
-        (arguments['fabric_env'].get('key_filename') is None):
+
+    # Make sure we have an authentication value
+    if (fabric_env.get('password') is None) and \
+        (fabric_env.get('key') is None) and \
+        (fabric_env.get('key_filename') is None):
         context = ConsumptionContext.get_thread_local()
         context.validation.report('must configure "ssh.password", "ssh.key", 
or "ssh.key_filename" '
                                   'for "{0}"'
                                   .format(operation.implementation),
                                   level=validation.Issue.BETWEEN_TYPES)
 
-    from . import operations
-    operation.implementation = '{0}.{1}'.format(operations.__name__,
-                                                
operations.run_script_with_ssh.__name__)
+    operation.arguments['fabric_env'] = Parameter.wrap('fabric_env', 
fabric_env,
+                                                       'Fabric configuration.')
 
+    operation.function = '{0}.{1}'.format(operations.__name__,
+                                          
operations.run_script_with_ssh.__name__)
 
-def _get_process(value):
+
+def _get_process(operation):
+    value = operation.configuration.get('process')._value \
+        if 'process' in operation.configuration else None
     if value is None:
-        return None
+        return {}
     _validate_type(value, dict, 'process')
     for k, v in value.iteritems():
         if k == 'eval_python':
-            value[k] = _str_to_bool(v, 'process.eval_python')
+            value[k] = _coerce_bool(v, 'process.eval_python')
         elif k == 'cwd':
             _validate_type(v, basestring, 'process.cwd')
         elif k == 'command_prefix':
             _validate_type(v, basestring, 'process.command_prefix')
         elif k == 'args':
-            value[k] = _dict_to_list(v, 'process.args')
+            value[k] = _dict_to_list_of_strings(v, 'process.args')
         elif k == 'env':
             _validate_type(v, dict, 'process.env')
         else:
@@ -126,17 +151,19 @@ def _get_process(value):
     return value
 
 
-def _get_ssh(value):
+def _get_ssh(operation):
+    value = operation.configuration.get('ssh')._value \
+        if 'process' in operation.configuration else None
     if value is None:
         return {}
     _validate_type(value, dict, 'ssh')
     for k, v in value.iteritems():
         if k == 'use_sudo':
-            value[k] = _str_to_bool(v, 'ssh.use_sudo')
+            value[k] = _coerce_bool(v, 'ssh.use_sudo')
         elif k == 'hide_output':
-            value[k] = _dict_to_list(v, 'ssh.hide_output')
+            value[k] = _dict_to_list_of_strings(v, 'ssh.hide_output')
         elif k == 'warn_only':
-            value[k] = _str_to_bool(v, 'ssh.warn_only')
+            value[k] = _coerce_bool(v, 'ssh.warn_only')
         elif k == 'user':
             _validate_type(v, basestring, 'ssh.user')
         elif k == 'password':
@@ -155,16 +182,20 @@ def _get_ssh(value):
 
 
 def _validate_type(value, the_type, name):
+    if isinstance(value, Function):
+        return
     if not isinstance(value, the_type):
         context = ConsumptionContext.get_thread_local()
-        context.validation.report('"{0}" configuration is not a {1}'
-                                  .format(name, full_type_name(the_type)),
+        context.validation.report('"{0}" configuration is not a {1}: {2}'
+                                  .format(name, full_type_name(the_type), 
safe_repr(value)),
                                   level=validation.Issue.BETWEEN_TYPES)
 
 
-def _str_to_bool(value, name):
+def _coerce_bool(value, name):
     if value is None:
         return None
+    if isinstance(value, bool):
+        return value
     _validate_type(value, basestring, name)
     if value == 'true':
         return True
@@ -173,19 +204,15 @@ def _str_to_bool(value, name):
     else:
         context = ConsumptionContext.get_thread_local()
         context.validation.report('"{0}" configuration is not "true" or 
"false": {1}'
-                                  .format(name, repr(value)),
+                                  .format(name, safe_repr(value)),
                                   level=validation.Issue.BETWEEN_TYPES)
 
 
-def _dict_to_list(the_dict, name):
+def _dict_to_list_of_strings(the_dict, name):
     _validate_type(the_dict, dict, name)
     value = []
     for k in sorted(the_dict):
         v = the_dict[k]
-        if not isinstance(v, basestring):
-            context = ConsumptionContext.get_thread_local()
-            context.validation.report('"{0}.{1}" configuration is not a 
string: {2}'
-                                      .format(name, k, repr(v)),
-                                      level=validation.Issue.BETWEEN_TYPES)
+        _validate_type(v, basestring, '{0}.{1}'.format(name, k))
         value.append(v)
     return value

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/orchestrator/workflow_runner.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflow_runner.py 
b/aria/orchestrator/workflow_runner.py
index 8f25cce..0c6321f 100644
--- a/aria/orchestrator/workflow_runner.py
+++ b/aria/orchestrator/workflow_runner.py
@@ -119,7 +119,7 @@ class WorkflowRunner(object):
         else:
             workflow_inputs = 
self.service.workflows[self._workflow_name].inputs
 
-        execution.inputs = modeling_utils.create_inputs(inputs, 
workflow_inputs)
+        execution.inputs = modeling_utils.create_parameters(inputs, 
workflow_inputs)
         # 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/8fe7f4b1/aria/orchestrator/workflows/api/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/api/task.py 
b/aria/orchestrator/workflows/api/task.py
index cb79eb3..aa6ac45 100644
--- a/aria/orchestrator/workflows/api/task.py
+++ b/aria/orchestrator/workflows/api/task.py
@@ -99,8 +99,8 @@ class OperationTask(BaseTask):
 
         operation = 
self.actor.interfaces[self.interface_name].operations[self.operation_name]
         self.plugin = operation.plugin
-        self.inputs = modeling_utils.create_inputs(inputs or {}, 
operation.inputs)
-        self.implementation = operation.implementation
+        self.inputs = modeling_utils.create_parameters(inputs or {}, 
operation.arguments)
+        self.implementation = operation.function
 
     def __repr__(self):
         return self.name

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/aria/orchestrator/workflows/core/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/task.py 
b/aria/orchestrator/workflows/core/task.py
index b3dfb3c..0d6eb11 100644
--- a/aria/orchestrator/workflows/core/task.py
+++ b/aria/orchestrator/workflows/core/task.py
@@ -148,7 +148,6 @@ class OperationTask(BaseTask):
             plugin=api_task.plugin,
             implementation=api_task.implementation,
             inputs=api_task.inputs
-
         )
         self._workflow_context.model.task.put(task_model)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml 
b/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml
index 0c5e77f..abac03b 100644
--- a/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml
+++ b/extensions/aria_extension_tosca/profiles/aria-1.0/aria-1.0.yaml
@@ -52,18 +52,10 @@ policy_types:
       should be inherited and extended with additional properties.
     derived_from: tosca.policies.Root
     properties:
-      implementation:
+      function:
         description: >-
-          The interpretation of the implementation string depends on the 
orchestrator. In ARIA it is
-          the full path to a Python @workflow function that generates a task 
graph based on the
-          service topology.
+          The interpretation of the function string depends on the 
orchestrator. In ARIA it is the
+          full path to a Python @workflow function that generates a task graph 
based on the service
+          topology.
         type: string
         required: true
-      dependencies:
-        description: >-
-          The optional ordered list of one or more dependent or secondary 
implementation artifact
-          name which are referenced by the primary implementation artifact 
(e.g., a library the
-          script installs or a secondary script).
-        type: list
-        entry_schema: string
-        required: false

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/assignments.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/assignments.py 
b/extensions/aria_extension_tosca/simple_v1_0/assignments.py
index d929ce0..79f6377 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/assignments.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/assignments.py
@@ -23,7 +23,7 @@ from aria.parser.presentation import (AsIsPresentation, 
has_fields, allow_unknow
 
 from .filters import NodeFilter
 from .misc import Description, OperationImplementation
-from .modeling.properties import get_assigned_and_defined_property_values
+from .modeling.parameters import get_assigned_and_defined_parameter_values
 from .presentation.extensible import ExtensiblePresentation
 from .presentation.field_validators import (node_template_or_type_validator,
                                             
relationship_template_or_type_validator,
@@ -428,7 +428,7 @@ class ArtifactAssignment(ExtensiblePresentation):
 
     @cachedmethod
     def _get_property_values(self, context):
-        return FrozenDict(get_assigned_and_defined_property_values(context, 
self))
+        return FrozenDict(get_assigned_and_defined_parameter_values(context, 
self, 'property'))
 
     @cachedmethod
     def _validate(self, context):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/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 99389e4..0b04fdc 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -26,14 +26,17 @@ import re
 from types import FunctionType
 from datetime import datetime
 
+from ruamel import yaml
+
 from aria.parser.validation import Issue
-from aria.utils.collections import StrictDict
+from aria.utils.collections import (StrictDict, OrderedDict)
 from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate,
                                   RequirementTemplate, RelationshipTemplate, 
CapabilityTemplate,
                                   GroupTemplate, PolicyTemplate, 
SubstitutionTemplate,
                                   SubstitutionTemplateMapping, 
InterfaceTemplate, OperationTemplate,
                                   ArtifactTemplate, Metadata, Parameter, 
PluginSpecification)
 
+from .parameters import coerce_parameter_value
 from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, 
LessOrEqual, InRange,
                           ValidValues, Length, MinLength, MaxLength, Pattern)
 from ..data_types import coerce_value
@@ -375,7 +378,7 @@ def create_operation_template_model(context, 
service_template, operation):
     implementation = operation.implementation
     if implementation is not None:
         primary = implementation.primary
-        parse_implementation_string(context, service_template, operation, 
model, primary)
+        set_implementation(context, service_template, operation, model, 
primary)
         relationship_edge = 
operation._get_extensions(context).get('relationship_edge')
         if relationship_edge is not None:
             if relationship_edge == 'source':
@@ -384,18 +387,37 @@ def create_operation_template_model(context, 
service_template, operation):
                 model.relationship_edge = True
 
         dependencies = implementation.dependencies
+        configuration = OrderedDict()
         if dependencies:
             for dependency in dependencies:
                 key, value = split_prefix(dependency)
                 if key is not None:
-                    if model.configuration is None:
-                        model.configuration = {}
-                    set_nested(model.configuration, key.split('.'), value)
+                    # Parse as YAML
+                    try:
+                        value = yaml.load(value)
+                    except yaml.parser.MarkedYAMLError as e:
+                        context.validation.report(
+                            'YAML parser {0} in operation configuration: {1}'
+                            .format(e.problem, value),
+                            locator=implementation._locator,
+                            level=Issue.FIELD)
+                        continue
+
+                    # Coerce to intrinsic functions, if there are any
+                    value = coerce_parameter_value(context, implementation, 
None, value).value
+
+                    # Support dot-notation nesting
+                    set_nested(configuration, key.split('.'), value)
                 else:
                     if model.dependencies is None:
                         model.dependencies = []
                     model.dependencies.append(dependency)
 
+        # Convert configuration to Parameter models
+        for key, value in configuration.iteritems():
+            model.configuration[key] = Parameter.wrap(key, value,
+                                                      description='Operation 
configuration.')
+
     inputs = operation.inputs
     if inputs:
         for input_name, the_input in inputs.iteritems():
@@ -490,15 +512,15 @@ def create_workflow_operation_template_model(context, 
service_template, policy):
 
     properties = policy._get_property_values(context)
     for prop_name, prop in properties.iteritems():
-        if prop_name == 'implementation':
-            parse_implementation_string(context, service_template, policy, 
model, prop.value)
+        if prop_name == 'function':
+            model.function = prop.value
         elif prop_name == 'dependencies':
             model.dependencies = 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.configuration[prop_name] = Parameter(name=prop_name, # 
pylint: disable=unexpected-keyword-arg
+                                                       type_name=prop.type,
+                                                       value=prop.value,
+                                                       
description=prop.description)
 
     return model
 
@@ -639,12 +661,12 @@ def create_constraint(context, node_filter, 
constraint_clause, property_name, ca
 
 def split_prefix(string):
     """
-    Splits the prefix on the first unescaped ">".
+    Splits the prefix on the first non-escaped ">".
     """
 
-    split = IMPLEMENTATION_PREFIX_REGEX.split(string, 2)
+    split = IMPLEMENTATION_PREFIX_REGEX.split(string, 1)
     if len(split) < 2:
-        return None, string
+        return None, None
     return split[0].strip(), split[1].lstrip()
 
 
@@ -671,13 +693,18 @@ def set_nested(the_dict, keys, value):
         set_nested(the_dict[key], keys, value)
 
 
-def parse_implementation_string(context, service_template, presentation, 
model, implementation):
-    plugin_name, model.implementation = split_prefix(implementation)
-    if plugin_name is not None:
-        model.plugin_specification = 
service_template.plugin_specifications.get(plugin_name)
+def set_implementation(context, service_template, presentation, model, 
primary):
+    prefix, postfix = split_prefix(primary)
+    if prefix:
+        # Special ARIA prefix
+        model.plugin_specification = 
service_template.plugin_specifications.get(prefix)
+        model.function = postfix
         if model.plugin_specification is None:
             context.validation.report(
                 'no policy for plugin "{0}" specified in operation 
implementation: {1}'
-                .format(plugin_name, implementation),
+                .format(prefix, primary),
                 locator=presentation._get_child_locator('properties', 
'implementation'),
                 level=Issue.BETWEEN_TYPES)
+    else:
+        # Standard TOSCA artifact
+        model.implementation = primary

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py
index 4f61ef5..dd9eeb4 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/artifacts.py
@@ -15,11 +15,11 @@
 
 from aria.utils.collections import OrderedDict
 
+
 #
 # NodeType, NodeTemplate
 #
 
-
 def get_inherited_artifact_definitions(context, presentation, 
for_presentation=None):
 
     if hasattr(presentation, '_get_type'):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
----------------------------------------------------------------------
diff --git 
a/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
index 6df7177..a90a9fc 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/capabilities.py
@@ -16,8 +16,9 @@
 from aria.utils.collections import deepcopy_with_locators, OrderedDict
 from aria.parser.validation import Issue
 
-from .properties import (convert_property_definitions_to_values, 
merge_raw_property_definitions,
-                         get_assigned_and_defined_property_values)
+from .parameters import (convert_parameter_definitions_to_values, 
merge_raw_parameter_definitions,
+                         get_assigned_and_defined_parameter_values)
+
 
 #
 # CapabilityType
@@ -38,6 +39,7 @@ def get_inherited_valid_source_types(context, presentation):
 
     return valid_source_types
 
+
 #
 # NodeType
 #
@@ -92,6 +94,7 @@ def get_inherited_capability_definitions(context, 
presentation, for_presentation
 
     return capability_definitions
 
+
 #
 # NodeTemplate
 #
@@ -127,8 +130,9 @@ def get_template_capabilities(context, presentation):
                 capability_assignment = capability_assignments[capability_name]
 
                 # Assign properties
-                values = get_assigned_and_defined_property_values(context,
-                                                                  
our_capability_assignment)
+                values = get_assigned_and_defined_parameter_values(context,
+                                                                   
our_capability_assignment,
+                                                                   'property')
                 if values:
                     capability_assignment._raw['properties'] = values
             else:
@@ -139,6 +143,7 @@ def get_template_capabilities(context, presentation):
 
     return capability_assignments
 
+
 #
 # Utils
 #
@@ -150,24 +155,25 @@ def 
convert_capability_from_definition_to_assignment(context, presentation, cont
 
     properties = presentation.properties
     if properties is not None:
-        raw['properties'] = convert_property_definitions_to_values(context, 
properties)
+        raw['properties'] = convert_parameter_definitions_to_values(context, 
properties)
 
     # TODO attributes
 
     return CapabilityAssignment(name=presentation._name, raw=raw, 
container=container)
 
+
 def merge_capability_definition_from_type(context, presentation, 
capability_definition):
     raw_properties = OrderedDict()
 
     # Merge properties from type
     the_type = capability_definition._get_type(context)
     type_property_defintions = the_type._get_properties(context)
-    merge_raw_property_definitions(context, presentation, raw_properties, 
type_property_defintions,
-                                   'properties')
+    merge_raw_parameter_definitions(context, presentation, raw_properties, 
type_property_defintions,
+                                    'properties')
 
     # Merge our properties
-    merge_raw_property_definitions(context, presentation, raw_properties,
-                                   capability_definition.properties, 
'properties')
+    merge_raw_parameter_definitions(context, presentation, raw_properties,
+                                    capability_definition.properties, 
'properties')
 
     if raw_properties:
         capability_definition._raw['properties'] = raw_properties

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py
----------------------------------------------------------------------
diff --git 
a/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py
index 7c99eab..9a30cc1 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/constraints.py
@@ -15,7 +15,7 @@
 
 import re
 
-from aria.modeling.contraints import NodeTemplateConstraint
+from aria.modeling.constraints import NodeTemplateConstraint
 from aria.modeling.utils import NodeTemplateContainerHolder
 from aria.modeling.functions import evaluate
 from aria.parser import implements_specification

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
index 3952785..c0d79e5 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
@@ -26,6 +26,7 @@ from aria.parser.validation import Issue
 from .functions import get_function
 from ..presentation.types import get_type_by_full_or_shorthand_name
 
+
 #
 # DataType
 #
@@ -50,6 +51,7 @@ def get_inherited_constraints(context, presentation):
 
     return constraints
 
+
 def coerce_data_type_value(context, presentation, data_type, entry_schema, 
constraints, value, # pylint: disable=unused-argument
                            aspect):
     """
@@ -121,6 +123,7 @@ def coerce_data_type_value(context, presentation, 
data_type, entry_schema, const
 
     return value
 
+
 def validate_data_type_name(context, presentation):
     """
     Makes sure the complex data type's name is not that of a built-in type.
@@ -132,6 +135,7 @@ def validate_data_type_name(context, presentation):
                                   % safe_repr(name),
                                   locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
 
+
 #
 # PropertyDefinition, AttributeDefinition, EntrySchema, DataType
 #
@@ -172,6 +176,7 @@ def get_data_type(context, presentation, field_name, 
allow_none=False):
     # Try primitive data type
     return get_primitive_data_type(type_name)
 
+
 #
 # PropertyDefinition, EntrySchema
 #
@@ -195,6 +200,7 @@ def get_property_constraints(context, presentation):
 
     return constraints
 
+
 #
 # ConstraintClause
 #
@@ -310,6 +316,7 @@ def apply_constraint_to_value(context, presentation, 
constraint_clause, value):
 
     return True
 
+
 #
 # Repository
 #
@@ -326,6 +333,7 @@ def get_data_type_value(context, presentation, field_name, 
type_name):
                                   locator=presentation._locator, 
level=Issue.BETWEEN_TYPES)
     return None
 
+
 #
 # Utils
 #
@@ -345,6 +353,7 @@ PRIMITIVE_DATA_TYPES = {
     'boolean': bool,
     'null': None.__class__}
 
+
 @implements_specification('3.2.1-3', 'tosca-simple-1.0')
 def get_primitive_data_type(type_name):
     """
@@ -358,6 +367,7 @@ def get_primitive_data_type(type_name):
 
     return PRIMITIVE_DATA_TYPES.get(type_name)
 
+
 def get_data_type_name(the_type):
     """
     Returns the name of the type, whether it's a DataType, a primitive type, 
or another class.
@@ -365,6 +375,7 @@ def get_data_type_name(the_type):
 
     return the_type._name if hasattr(the_type, '_name') else 
full_type_name(the_type)
 
+
 def coerce_value(context, presentation, the_type, entry_schema, constraints, 
value, aspect=None): # pylint: disable=too-many-return-statements
     """
     Returns the value after it's coerced to its type, reporting validation 
errors if it cannot be
@@ -410,6 +421,7 @@ def coerce_value(context, presentation, the_type, 
entry_schema, constraints, val
     # Coerce to primitive type
     return coerce_to_primitive(context, presentation, the_type, constraints, 
value, aspect)
 
+
 def coerce_to_primitive(context, presentation, primitive_type, constraints, 
value, aspect=None):
     """
     Returns the value after it's coerced to a primitive type, translating 
exceptions to validation
@@ -435,6 +447,7 @@ def coerce_to_primitive(context, presentation, 
primitive_type, constraints, valu
 
     return value
 
+
 def coerce_to_data_type_class(context, presentation, cls, entry_schema, 
constraints, value,
                               aspect=None):
     """
@@ -463,6 +476,7 @@ def coerce_to_data_type_class(context, presentation, cls, 
entry_schema, constrai
 
     return value
 
+
 def apply_constraints_to_value(context, presentation, constraints, value):
     """
     Applies all constraints to the value. If the value conforms, returns the 
value. If it does not
@@ -478,6 +492,7 @@ def apply_constraints_to_value(context, presentation, 
constraints, value):
             value = None
     return value
 
+
 def get_container_data_type(presentation):
     if presentation is None:
         return None
@@ -485,6 +500,7 @@ def get_container_data_type(presentation):
         return presentation
     return get_container_data_type(presentation._container)
 
+
 def report_issue_for_bad_format(context, presentation, the_type, value, 
aspect, e):
     if aspect == 'default':
         aspect = '"default" value'

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
index 3e6aa6f..e04ac4a 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/interfaces.py
@@ -13,11 +13,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from aria.utils.collections import merge, deepcopy_with_locators, OrderedDict
+from aria.utils.collections import (merge, deepcopy_with_locators, OrderedDict)
 from aria.parser.presentation import get_locator
 from aria.parser.validation import Issue
 
-from .properties import (coerce_property_value, 
convert_property_definitions_to_values)
+from .parameters import (coerce_parameter_value, 
convert_parameter_definitions_to_values)
+
 
 #
 # InterfaceType
@@ -45,6 +46,7 @@ def get_inherited_operations(context, presentation):
 
     return operations
 
+
 #
 # InterfaceDefinition
 #
@@ -73,6 +75,7 @@ def get_and_override_input_definitions_from_type(context, 
presentation):
 
     return inputs
 
+
 def get_and_override_operation_definitions_from_type(context, presentation):
     """
     Returns our operation definitions added on top of those of the interface 
type, if specified.
@@ -96,6 +99,7 @@ def get_and_override_operation_definitions_from_type(context, 
presentation):
 
     return operations
 
+
 #
 # NodeType, RelationshipType, GroupType
 #
@@ -124,6 +128,7 @@ def get_inherited_interface_definitions(context, 
presentation, type_name, for_pr
 
     return interfaces
 
+
 #
 # NodeTemplate, RelationshipTemplate, GroupTemplate
 #
@@ -186,6 +191,7 @@ def get_template_interfaces(context, presentation, 
type_name):
 
     return template_interfaces
 
+
 #
 # Utils
 #
@@ -200,13 +206,14 @@ def 
convert_interface_definition_from_type_to_template(context, presentation, co
     raw = convert_interface_definition_from_type_to_raw_template(context, 
presentation)
     return InterfaceAssignment(name=presentation._name, raw=raw, 
container=container)
 
+
 def convert_interface_definition_from_type_to_raw_template(context, 
presentation): # pylint: disable=invalid-name
     raw = OrderedDict()
 
     # Copy default values for inputs
     inputs = presentation._get_inputs(context)
     if inputs is not None:
-        raw['inputs'] = convert_property_definitions_to_values(context, inputs)
+        raw['inputs'] = convert_parameter_definitions_to_values(context, 
inputs)
 
     # Copy operations
     operations = presentation._get_operations(context)
@@ -221,11 +228,12 @@ def 
convert_interface_definition_from_type_to_raw_template(context, presentation
                 raw[operation_name]['implementation'] = 
deepcopy_with_locators(implementation._raw)
             inputs = operation.inputs
             if inputs is not None:
-                raw[operation_name]['inputs'] = 
convert_property_definitions_to_values(context,
-                                                                               
        inputs)
+                raw[operation_name]['inputs'] = 
convert_parameter_definitions_to_values(context,
+                                                                               
         inputs)
 
     return raw
 
+
 def 
convert_requirement_interface_definitions_from_type_to_raw_template(context, 
raw_requirement, # pylint: disable=invalid-name
                                                                         
interface_definitions):
     if not interface_definitions:
@@ -240,6 +248,7 @@ def 
convert_requirement_interface_definitions_from_type_to_raw_template(context,
         else:
             raw_requirement['interfaces'][interface_name] = raw_interface
 
+
 def merge_interface(context, presentation, interface_assignment, 
our_interface_assignment,
                     interface_definition, interface_name):
     # Assign/merge interface inputs
@@ -282,6 +291,7 @@ def merge_interface(context, presentation, 
interface_assignment, our_interface_a
                               our_input_assignments, input_definitions, 
interface_name,
                               operation_name, presentation)
 
+
 def merge_raw_input_definition(context, the_raw_input, our_input, 
interface_name, operation_name,
                                presentation, type_name):
     # Check if we changed the type
@@ -305,6 +315,7 @@ def merge_raw_input_definition(context, the_raw_input, 
our_input, interface_name
     # Merge
     merge(the_raw_input, our_input._raw)
 
+
 def merge_input_definitions(context, inputs, our_inputs, interface_name, 
operation_name,
                             presentation, type_name):
     for input_name, our_input in our_inputs.iteritems():
@@ -314,6 +325,7 @@ def merge_input_definitions(context, inputs, our_inputs, 
interface_name, operati
         else:
             inputs[input_name] = our_input._clone(presentation)
 
+
 def merge_raw_input_definitions(context, raw_inputs, our_inputs, 
interface_name, operation_name,
                                 presentation, type_name):
     for input_name, our_input in our_inputs.iteritems():
@@ -323,6 +335,7 @@ def merge_raw_input_definitions(context, raw_inputs, 
our_inputs, interface_name,
         else:
             raw_inputs[input_name] = deepcopy_with_locators(our_input._raw)
 
+
 def merge_raw_operation_definition(context, raw_operation, our_operation, 
interface_name,
                                    presentation, type_name):
     if not isinstance(our_operation._raw, dict):
@@ -353,6 +366,7 @@ def merge_raw_operation_definition(context, raw_operation, 
our_operation, interf
             raw_operation['implementation'] = \
                 deepcopy_with_locators(our_operation._raw['implementation'])
 
+
 def merge_operation_definitions(context, operations, our_operations, 
interface_name, presentation,
                                 type_name):
     if not our_operations:
@@ -364,6 +378,7 @@ def merge_operation_definitions(context, operations, 
our_operations, interface_n
         else:
             operations[operation_name] = our_operation._clone(presentation)
 
+
 def merge_raw_operation_definitions(context, raw_operations, our_operations, 
interface_name,
                                     presentation, type_name):
     for operation_name, our_operation in our_operations.iteritems():
@@ -378,6 +393,7 @@ def merge_raw_operation_definitions(context, 
raw_operations, our_operations, int
         else:
             raw_operations[operation_name] = 
deepcopy_with_locators(our_operation._raw)
 
+
 # From either an InterfaceType or an InterfaceDefinition:
 def merge_interface_definition(context, interface, our_source, presentation, 
type_name):
     if hasattr(our_source, 'type'):
@@ -408,6 +424,7 @@ def merge_interface_definition(context, interface, 
our_source, presentation, typ
         merge_raw_operation_definitions(context, interface._raw, 
our_operations, our_source._name,
                                         presentation, type_name)
 
+
 def merge_interface_definitions(context, interfaces, our_interfaces, 
presentation,
                                 for_presentation=None):
     if not our_interfaces:
@@ -419,12 +436,14 @@ def merge_interface_definitions(context, interfaces, 
our_interfaces, presentatio
         else:
             interfaces[name] = our_interface._clone(for_presentation)
 
+
 def merge_interface_definitions_from_their_types(context, interfaces, 
presentation):
     for interface in interfaces.itervalues():
         the_type = interface._get_type(context) # InterfaceType
         if the_type is not None:
             merge_interface_definition(context, interface, the_type, 
presentation, 'type')
 
+
 def assign_raw_inputs(context, values, assignments, definitions, 
interface_name, operation_name,
                       presentation):
     if not assignments:
@@ -454,8 +473,9 @@ def assign_raw_inputs(context, values, assignments, 
definitions, interface_name,
         # Note: default value has already been assigned
 
         # Coerce value
-        values['inputs'][input_name] = coerce_property_value(context, 
assignment, definition,
-                                                             assignment.value)
+        values['inputs'][input_name] = coerce_parameter_value(context, 
assignment, definition,
+                                                              assignment.value)
+
 
 def validate_required_inputs(context, presentation, assignment, definition, 
original_assignment,
                              interface_name, operation_name=None):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
new file mode 100644
index 0000000..c910956
--- /dev/null
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/parameters.py
@@ -0,0 +1,211 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from aria.utils.collections import (merge, deepcopy_with_locators, OrderedDict)
+from aria.utils.formatting import pluralize
+from aria.parser.presentation import Value
+from aria.parser.validation import Issue
+
+from .data_types import coerce_value
+
+
+#
+# ArtifactType, DataType, CapabilityType, RelationshipType, NodeType, 
GroupType, PolicyType
+#
+
+def get_inherited_parameter_definitions(context, presentation, field_name, 
for_presentation=None):
+    """
+    Returns our parameter definitions added on top of those of our parent, if 
we have one
+    (recursively).
+
+    Allows overriding all aspects of parent properties except data type.
+    """
+
+    # Get definitions from parent
+    # If we inherit from a primitive, it does not have a parent:
+    parent = presentation._get_parent(context) if hasattr(presentation, 
'_get_parent') else None
+    definitions = get_inherited_parameter_definitions(context, parent, 
field_name,
+                                                      
for_presentation=presentation) \
+                                                      if parent is not None 
else OrderedDict()
+
+    # Add/merge our definitions
+    # If we inherit from a primitive, it does not have our field
+    our_definitions = getattr(presentation, field_name, None)
+    if our_definitions:
+        our_definitions_clone = OrderedDict()
+        for name, our_definition in our_definitions.iteritems():
+            our_definitions_clone[name] = 
our_definition._clone(for_presentation)
+        our_definitions = our_definitions_clone
+        merge_parameter_definitions(context, presentation, definitions, 
our_definitions, field_name)
+
+    for definition in definitions.itervalues():
+        definition._reset_method_cache()
+
+    return definitions
+
+
+#
+# NodeTemplate, RelationshipTemplate, GroupTemplate, PolicyTemplate
+#
+
+def get_assigned_and_defined_parameter_values(context, presentation, 
field_name):
+    """
+    Returns the assigned property values while making sure they are defined in 
our type.
+
+    The property definition's default value, if available, will be used if we 
did not assign it.
+
+    Makes sure that required properties indeed end up with a value.
+    """
+
+    values = OrderedDict()
+
+    the_type = presentation._get_type(context)
+    field_name_plural = pluralize(field_name)
+    assignments = getattr(presentation, field_name_plural)
+    get_fn_name = '_get_{0}'.format(field_name_plural)
+    definitions = getattr(the_type, get_fn_name)(context) if the_type is not 
None else None
+
+    # Fill in our assignments, but make sure they are defined
+    if assignments:
+        for name, value in assignments.iteritems():
+            if (definitions is not None) and (name in definitions):
+                definition = definitions[name]
+                values[name] = coerce_parameter_value(context, value, 
definition, value.value)
+            else:
+                context.validation.report('assignment to undefined {0} "{1}" 
in "{2}"'
+                                          .format(field_name, name, 
presentation._fullname),
+                                          locator=value._locator, 
level=Issue.BETWEEN_TYPES)
+
+    # Fill in defaults from the definitions
+    if definitions:
+        for name, definition in definitions.iteritems():
+            if values.get(name) is None:
+                values[name] = coerce_parameter_value(context, presentation, 
definition,
+                                                      definition.default)
+
+    validate_required_values(context, presentation, values, definitions)
+
+    return values
+
+
+#
+# TopologyTemplate
+#
+
+def get_parameter_values(context, presentation, field_name):
+    values = OrderedDict()
+
+    parameters = getattr(presentation, field_name)
+
+    # Fill in defaults and values
+    if parameters:
+        for name, parameter in parameters.iteritems():
+            if values.get(name) is None:
+                if hasattr(parameter, 'value') and (parameter.value is not 
None):
+                    # For parameters only:
+                    values[name] = coerce_parameter_value(context, 
presentation, parameter,
+                                                          parameter.value)
+                else:
+                    default = parameter.default if hasattr(parameter, 
'default') else None
+                    values[name] = coerce_parameter_value(context, 
presentation, parameter, default)
+
+    return values
+
+
+#
+# Utils
+#
+
+def validate_required_values(context, presentation, values, definitions):
+    """
+    Check if required properties have not been assigned.
+    """
+
+    if not definitions:
+        return
+    for name, definition in definitions.iteritems():
+        if getattr(definition, 'required', False) \
+            and ((values is None) or (values.get(name) is None)):
+            context.validation.report('required property "%s" is not assigned 
a value in "%s"'
+                                      % (name, presentation._fullname),
+                                      
locator=presentation._get_child_locator('properties'),
+                                      level=Issue.BETWEEN_TYPES)
+
+
+def merge_raw_parameter_definition(context, presentation, 
raw_property_definition,
+                                   our_property_definition, field_name, 
property_name):
+    # Check if we changed the type
+    # TODO: allow a sub-type?
+    type1 = raw_property_definition.get('type')
+    type2 = our_property_definition.type
+    if type1 != type2:
+        context.validation.report(
+            'override changes type from "%s" to "%s" for property "%s" in "%s"'
+            % (type1, type2, property_name, presentation._fullname),
+            locator=presentation._get_child_locator(field_name, property_name),
+            level=Issue.BETWEEN_TYPES)
+
+    merge(raw_property_definition, our_property_definition._raw)
+
+
+def merge_raw_parameter_definitions(context, presentation, 
raw_property_definitions,
+                                    our_property_definitions, field_name):
+    if not our_property_definitions:
+        return
+    for property_name, our_property_definition in 
our_property_definitions.iteritems():
+        if property_name in raw_property_definitions:
+            raw_property_definition = raw_property_definitions[property_name]
+            merge_raw_parameter_definition(context, presentation, 
raw_property_definition,
+                                           our_property_definition, 
field_name, property_name)
+        else:
+            raw_property_definitions[property_name] = \
+                deepcopy_with_locators(our_property_definition._raw)
+
+
+def merge_parameter_definitions(context, presentation, property_definitions,
+                                our_property_definitions, field_name):
+    if not our_property_definitions:
+        return
+    for property_name, our_property_definition in 
our_property_definitions.iteritems():
+        if property_name in property_definitions:
+            property_definition = property_definitions[property_name]
+            merge_raw_parameter_definition(context, presentation, 
property_definition._raw,
+                                           our_property_definition, 
field_name, property_name)
+        else:
+            property_definitions[property_name] = our_property_definition
+
+
+# Works on properties, inputs, and parameters
+def coerce_parameter_value(context, presentation, definition, value, 
aspect=None):
+    the_type = definition._get_type(context) if definition is not None else 
None
+    entry_schema = definition.entry_schema if definition is not None else None
+    constraints = definition._get_constraints(context) \
+        if ((definition is not None) and hasattr(definition, 
'_get_constraints')) else None
+    value = coerce_value(context, presentation, the_type, entry_schema, 
constraints, value, aspect)
+    if (the_type is not None) and hasattr(the_type, '_name'):
+        type_name = the_type._name
+    else:
+        type_name = getattr(definition, 'type', None)
+    description = getattr(definition, 'description', None)
+    description = description.value if description is not None else None
+    return Value(type_name, value, description)
+
+
+def convert_parameter_definitions_to_values(context, definitions):
+    values = OrderedDict()
+    for name, definition in definitions.iteritems():
+        default = definition.default
+        values[name] = coerce_parameter_value(context, definition, definition, 
default)
+    return values

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8fe7f4b1/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py 
b/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
index fba1972..7dd803b 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/policies.py
@@ -15,6 +15,7 @@
 
 from ..presentation.types import convert_shorthand_to_full_type_name
 
+
 #
 # PolicyType
 #
@@ -49,6 +50,7 @@ def get_inherited_targets(context, presentation):
 
     return node_types, group_types
 
+
 #
 # PolicyTemplate
 #


Reply via email to