ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@apache.org
Subject [15/19] incubator-ariatosca git commit: ARIA-139 Support attributes
Date Mon, 22 May 2017 12:17:42 GMT
ARIA-139 Support attributes

* Fully implement attribute support in parser
* New intrinsic function evaluation mechanism
* Implemented more intrinsic functions, including get_attribute
* Fix to one-on-one relationship back population
* Fixes to TOSCA use case examples
* Indirectly related: re-enabled node_filter mechanism and reworked
filter constraints in order to make them serializable
* utils/type is much more robust now and consolidates all conversions
and names
* Moved dsl_specification to new utils/specification (because utils/type
uses it)


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

Branch: refs/heads/ARIA-208-Missing-back-refrences-for-models
Commit: 60ea3ebb21e762d36115db26563a93dd3cb72003
Parents: 2ee06b8
Author: Tal Liron <tal.liron@gmail.com>
Authored: Wed Apr 19 20:07:33 2017 -0500
Committer: Tal Liron <tal.liron@gmail.com>
Committed: Thu May 11 11:31:02 2017 -0500

----------------------------------------------------------------------
 aria/core.py                                    |   6 +-
 aria/modeling/contraints.py                     |  28 +
 aria/modeling/functions.py                      | 104 ++-
 aria/modeling/mixins.py                         |   2 +-
 aria/modeling/relationship.py                   |  19 +-
 aria/modeling/service_common.py                 | 164 ++++-
 aria/modeling/service_instance.py               |  78 ++-
 aria/modeling/service_template.py               | 126 ++--
 aria/modeling/utils.py                          |  50 +-
 .../execution_plugin/instantiation.py           |   2 +-
 aria/parser/__init__.py                         |   4 +-
 aria/parser/consumption/__init__.py             |  11 +-
 aria/parser/consumption/modeling.py             |   4 +-
 aria/parser/presentation/fields.py              |   3 +-
 aria/parser/presentation/presentation.py        |   3 +-
 aria/parser/presentation/utils.py               |   3 +-
 aria/parser/specification.py                    |  39 +-
 aria/parser/validation/issue.py                 |   2 +-
 aria/utils/caching.py                           |  13 +-
 aria/utils/formatting.py                        |  16 +-
 aria/utils/specification.py                     |  53 ++
 aria/utils/type.py                              | 157 ++++-
 .../block-storage-1/block-storage-1.yaml        |   2 +-
 .../block-storage-2/block-storage-2.yaml        |   2 +-
 .../block-storage-3/block-storage-3.yaml        |   2 +-
 .../block-storage-4/block-storage-4.yaml        |   2 +-
 .../block-storage-5/block-storage-5.yaml        |   6 +-
 .../block-storage-6/block-storage-6.yaml        |   4 +-
 .../use-cases/multi-tier-1/multi-tier-1.yaml    |  14 +-
 .../simple_v1_0/__init__.py                     |  12 +-
 .../simple_v1_0/assignments.py                  |  16 +-
 .../simple_v1_0/data_types.py                   |  20 +-
 .../simple_v1_0/definitions.py                  |  18 +-
 .../aria_extension_tosca/simple_v1_0/filters.py |   6 +-
 .../simple_v1_0/functions.py                    | 536 ---------------
 .../aria_extension_tosca/simple_v1_0/misc.py    |  20 +-
 .../simple_v1_0/modeling/__init__.py            | 185 ++---
 .../simple_v1_0/modeling/constraints.py         | 144 ++++
 .../simple_v1_0/modeling/data_types.py          |  23 +-
 .../simple_v1_0/modeling/functions.py           | 677 +++++++++++++++++++
 .../simple_v1_0/modeling/properties.py          |  17 +-
 .../presentation/field_validators.py            |  13 +-
 .../simple_v1_0/presenter.py                    |   4 +-
 .../simple_v1_0/templates.py                    |  47 +-
 .../aria_extension_tosca/simple_v1_0/types.py   |  18 +-
 .../node-cellar/node-cellar.yaml                |   6 +-
 46 files changed, 1644 insertions(+), 1037 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/core.py
----------------------------------------------------------------------
diff --git a/aria/core.py b/aria/core.py
index af1984a..cc943ef 100644
--- a/aria/core.py
+++ b/aria/core.py
@@ -77,10 +77,14 @@ class Core(object):
             consumption.ConsumerChain(
                 context,
                 (
+                    consumption.CoerceServiceInstanceValues,
+                    consumption.ValidateServiceInstance,
                     consumption.SatisfyRequirements,
+                    consumption.CoerceServiceInstanceValues,
                     consumption.ValidateCapabilities,
                     consumption.FindHosts,
-                    consumption.ConfigureOperations
+                    consumption.ConfigureOperations,
+                    consumption.CoerceServiceInstanceValues
                 )).consume()
             if context.validation.dump_issues():
                 raise exceptions.InstantiationError('Failed to instantiate service template')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/contraints.py
----------------------------------------------------------------------
diff --git a/aria/modeling/contraints.py b/aria/modeling/contraints.py
new file mode 100644
index 0000000..107b010
--- /dev/null
+++ b/aria/modeling/contraints.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/60ea3ebb/aria/modeling/functions.py
----------------------------------------------------------------------
diff --git a/aria/modeling/functions.py b/aria/modeling/functions.py
index 02f4454..06fd19f 100644
--- a/aria/modeling/functions.py
+++ b/aria/modeling/functions.py
@@ -13,20 +13,118 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from ..parser.consumption import ConsumptionContext
+from ..parser.exceptions import InvalidValueError
+from ..utils.collections import OrderedDict
+from . import exceptions
+
+
 class Function(object):
     """
-    An intrinsic function.
+    Base class for intrinsic functions. Serves as a placeholder for a value that should eventually
+    be derived by "evaluating" (calling) the function.
 
-    Serves as a placeholder for a value that should eventually be derived by calling the function.
+    Note that this base class is provided as a convenience and you do not have to inherit it: any
+    object with an ``__evaluate__`` method would be treated similarly.
     """
 
     @property
     def as_raw(self):
         raise NotImplementedError
 
-    def _evaluate(self, context, container):
+    def __evaluate__(self, container_holder):
+        """
+        Evaluates the function if possible. If impossible, raises
+        :class:`CannotEvaluateFunctionException` (do not just return None).
+
+        :rtype: Evaluation (or any object with ``value`` and ``final`` properties)
+        """
+
         raise NotImplementedError
 
     def __deepcopy__(self, memo):
         # Circumvent cloning in order to maintain our state
         return self
+
+
+class Evaluation(object):
+    """
+    An evaluated :class:`Function` return value.
+    """
+
+    def __init__(self, value, final=False):
+        self.value = value
+        self.final = final
+
+
+def evaluate(value, container_holder, report_issues=False): # pylint: disable=too-many-branches
+    """
+    Recursively attempts to call ``__evaluate__``. If an evaluation occurred will return an
+    :class:`Evaluation`, otherwise it will be None. If any evaluation is non-final, then the entire
+    evaluation will also be non-final.
+
+    The ``container_holder`` argument should have three properties: ``container`` should return
+    the model that contains the value, ``service`` should return the containing
+    :class:`aria.modeling.models.Service` model or None, and ``service_template`` should return the
+    containing :class:`aria.modeling.models.ServiceTemplate` model or None.
+    """
+
+    evaluated = False
+    final = True
+
+    if hasattr(value, '__evaluate__'):
+        try:
+            evaluation = value.__evaluate__(container_holder)
+
+            # Verify evaluation structure
+            if (evaluation is None) \
+                or (not hasattr(evaluation, 'value')) \
+                or (not hasattr(evaluation, 'final')):
+                raise InvalidValueError('bad __evaluate__ implementation')
+
+            evaluated = True
+            value = evaluation.value
+            final = evaluation.final
+
+            # The evaluated value might itself be evaluable
+            evaluation = evaluate(value, container_holder, report_issues)
+            if evaluation is not None:
+                value = evaluation.value
+                if not evaluation.final:
+                    final = False
+        except exceptions.CannotEvaluateFunctionException:
+            pass
+        except InvalidValueError as e:
+            if report_issues:
+                context = ConsumptionContext.get_thread_local()
+                context.validation.report(e.issue)
+
+    elif isinstance(value, list):
+        evaluated_list = []
+        for v in value:
+            evaluation = evaluate(v, container_holder, report_issues)
+            if evaluation is not None:
+                evaluated_list.append(evaluation.value)
+                evaluated = True
+                if not evaluation.final:
+                    final = False
+            else:
+                evaluated_list.append(v)
+        if evaluated:
+            value = evaluated_list
+
+    elif isinstance(value, dict):
+        evaluated_dict = OrderedDict()
+        for k, v in value.iteritems():
+            evaluation = evaluate(v, container_holder, report_issues)
+            if evaluation is not None:
+                evaluated_dict[k] = evaluation.value
+                evaluated = True
+                if not evaluation.final:
+                    final = False
+            else:
+                evaluated_dict[k] = v
+        if evaluated:
+            value = evaluated_dict
+
+    return Evaluation(value, final) if evaluated else None

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/mixins.py
----------------------------------------------------------------------
diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py
index e6db5a3..38c812d 100644
--- a/aria/modeling/mixins.py
+++ b/aria/modeling/mixins.py
@@ -124,7 +124,7 @@ class InstanceModelMixin(ModelMixin):
     def validate(self):
         pass
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         pass
 
     def dump(self):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
index 291d08c..40be5b2 100644
--- a/aria/modeling/relationship.py
+++ b/aria/modeling/relationship.py
@@ -146,13 +146,18 @@ def one_to_one(model_class,
                        false to disable
     :type back_populates: basestring|bool
     """
-    if back_populates is None:
-        back_populates = model_class.__tablename__
+    backref_kwargs = None
+    if back_populates is not NO_BACK_POP:
+        if back_populates is None:
+            back_populates = model_class.__tablename__
+        backref_kwargs = {'name': back_populates, 'uselist': False}
+        back_populates = None
 
     return _relationship(model_class,
                          other_table,
                          fk=fk,
                          back_populates=back_populates,
+                         backref_kwargs=backref_kwargs,
                          other_fk=other_fk)
 
 
@@ -190,6 +195,7 @@ def one_to_many(model_class,
     rel_kwargs.setdefault('cascade', 'all')
     if back_populates is None:
         back_populates = model_class.__tablename__
+
     return _relationship(
         model_class,
         child_table,
@@ -330,10 +336,11 @@ def _relationship(model_class,
 
     if backref_kwargs:
         assert back_populates is None
-        return relationship(lambda: _get_class_for_table(model_class, other_table_name),
-                            backref=backref(**backref_kwargs),
-                            **relationship_kwargs
-                           )
+        return relationship(
+            lambda: _get_class_for_table(model_class, other_table_name),
+            backref=backref(**backref_kwargs),
+            **relationship_kwargs
+        )
     else:
         if back_populates is not NO_BACK_POP:
             relationship_kwargs['back_populates'] = back_populates

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 1188f34..e9c96a4 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -23,19 +23,20 @@ from sqlalchemy import (
 from sqlalchemy.ext.declarative import declared_attr
 
 from ..parser.consumption import ConsumptionContext
-from ..utils import collections, formatting, console
-from .mixins import InstanceModelMixin, TemplateModelMixin
+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,
-    utils
+    functions
 )
 
 
-class ParameterBase(TemplateModelMixin):
+class ParameterBase(TemplateModelMixin, caching.HasCachedMethods):
     """
-    Represents a typed value.
+    Represents a typed value. The value can contain nested intrinsic functions.
 
-    This model is used by both service template and service instance elements.
+    This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`.
 
     :ivar name: Name
     :vartype name: basestring
@@ -50,8 +51,120 @@ class ParameterBase(TemplateModelMixin):
 
     name = Column(Text)
     type_name = Column(Text)
-    value = Column(PickleType)
     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[0] # because we are many-to-many, the back reference will be a list
+
+        raise ValueError('orphaned parameter: does not have an owner: {0}'.format(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):
@@ -63,27 +176,30 @@ class ParameterBase(TemplateModelMixin):
 
     def instantiate(self, container):
         from . import models
-        return models.Parameter(name=self.name,
+        return models.Parameter(name=self.name, # pylint: disable=unexpected-keyword-arg
                                 type_name=self.type_name,
-                                value=self.value,
+                                _value=self._value,
                                 description=self.description)
 
-    def coerce_values(self, container, report_issues):
-        if self.value is not None:
-            self.value = utils.coerce_value(container, self.value,
-                                            report_issues)
+    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(self.value),
+                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(self.value)))
+                context.style.literal(formatting.as_raw(self.value))))
         if self.description:
             console.puts(context.style.meta(self.description))
 
@@ -101,11 +217,15 @@ class ParameterBase(TemplateModelMixin):
         :param description: Description (optional)
         :type description: basestring
         """
-        return cls(name=name,
-                   type_name=formatting.full_type_name(value)
-                   if value is not None else None,
-                   value=value,
-                   description=description)
+
+        from . import models
+        type_name = canonical_type_name(value)
+        if type_name is None:
+            type_name = full_type_name(value)
+        return models.Parameter(name=name, # pylint: disable=unexpected-keyword-arg
+                                type_name=type_name,
+                                value=value,
+                                description=description)
 
 
 class TypeBase(InstanceModelMixin):
@@ -188,7 +308,7 @@ class TypeBase(InstanceModelMixin):
         self._append_raw_children(types)
         return types
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         pass
 
     def dump(self):
@@ -237,7 +357,7 @@ class MetadataBase(TemplateModelMixin):
             ('name', self.name),
             ('value', self.value)))
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         pass
 
     def instantiate(self, container):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index ad8e7ed..1efe1e1 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -251,16 +251,16 @@ class ServiceBase(InstanceModelMixin):
         utils.validate_dict_values(self.outputs)
         utils.validate_dict_values(self.workflows)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.meta_data, report_issues)
-        utils.coerce_dict_values(container, self.nodes, report_issues)
-        utils.coerce_dict_values(container, self.groups, report_issues)
-        utils.coerce_dict_values(container, self.policies, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.meta_data, report_issues)
+        utils.coerce_dict_values(self.nodes, report_issues)
+        utils.coerce_dict_values(self.groups, report_issues)
+        utils.coerce_dict_values(self.policies, report_issues)
         if self.substitution is not None:
-            self.substitution.coerce_values(container, report_issues)
-        utils.coerce_dict_values(container, self.inputs, report_issues)
-        utils.coerce_dict_values(container, self.outputs, report_issues)
-        utils.coerce_dict_values(container, self.workflows, report_issues)
+            self.substitution.coerce_values(report_issues)
+        utils.coerce_dict_values(self.inputs, report_issues)
+        utils.coerce_dict_values(self.outputs, report_issues)
+        utils.coerce_dict_values(self.workflows, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -513,6 +513,10 @@ class NodeBase(InstanceModelMixin):
     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)
@@ -646,6 +650,7 @@ class NodeBase(InstanceModelMixin):
             ('name', self.name),
             ('type_name', self.type.name),
             ('properties', formatting.as_raw_dict(self.properties)),
+            ('attributes', formatting.as_raw_dict(self.properties)),
             ('interfaces', formatting.as_raw_list(self.interfaces)),
             ('artifacts', formatting.as_raw_list(self.artifacts)),
             ('capabilities', formatting.as_raw_list(self.capabilities)),
@@ -664,17 +669,19 @@ class NodeBase(InstanceModelMixin):
         # TODO: validate that node template is of type?
 
         utils.validate_dict_values(self.properties)
+        utils.validate_dict_values(self.attributes)
         utils.validate_dict_values(self.interfaces)
         utils.validate_dict_values(self.artifacts)
         utils.validate_dict_values(self.capabilities)
         utils.validate_list_values(self.outbound_relationships)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.properties, report_issues)
-        utils.coerce_dict_values(self, self.interfaces, report_issues)
-        utils.coerce_dict_values(self, self.artifacts, report_issues)
-        utils.coerce_dict_values(self, self.capabilities, report_issues)
-        utils.coerce_list_values(self, self.outbound_relationships, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
+        utils.coerce_dict_values(self.attributes, report_issues)
+        utils.coerce_dict_values(self.interfaces, report_issues)
+        utils.coerce_dict_values(self.artifacts, report_issues)
+        utils.coerce_dict_values(self.capabilities, report_issues)
+        utils.coerce_list_values(self.outbound_relationships, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -683,6 +690,7 @@ class NodeBase(InstanceModelMixin):
             console.puts('Type: {0}'.format(context.style.type(self.type.name)))
             console.puts('Template: {0}'.format(context.style.node(self.node_template.name)))
             utils.dump_dict_values(self.properties, 'Properties')
+            utils.dump_dict_values(self.attributes, 'Attributes')
             utils.dump_interfaces(self.interfaces)
             utils.dump_dict_values(self.artifacts, 'Artifacts')
             utils.dump_dict_values(self.capabilities, 'Capabilities')
@@ -797,9 +805,9 @@ class GroupBase(InstanceModelMixin):
         utils.validate_dict_values(self.properties)
         utils.validate_dict_values(self.interfaces)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.properties, report_issues)
-        utils.coerce_dict_values(container, self.interfaces, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
+        utils.coerce_dict_values(self.interfaces, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -916,8 +924,8 @@ class PolicyBase(InstanceModelMixin):
     def validate(self):
         utils.validate_dict_values(self.properties)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.properties, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1017,8 +1025,8 @@ class SubstitutionBase(InstanceModelMixin):
     def validate(self):
         utils.validate_dict_values(self.mappings)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.mappings, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.mappings, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1121,7 +1129,7 @@ class SubstitutionMappingBase(InstanceModelMixin):
         return collections.OrderedDict((
             ('name', self.name)))
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         pass
 
     def validate(self):
@@ -1311,9 +1319,9 @@ class RelationshipBase(InstanceModelMixin):
         utils.validate_dict_values(self.properties)
         utils.validate_dict_values(self.interfaces)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.properties, report_issues)
-        utils.coerce_dict_values(container, self.interfaces, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
+        utils.coerce_dict_values(self.interfaces, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1451,8 +1459,8 @@ class CapabilityBase(InstanceModelMixin):
     def validate(self):
         utils.validate_dict_values(self.properties)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.properties, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1598,9 +1606,9 @@ class InterfaceBase(InstanceModelMixin):
         utils.validate_dict_values(self.inputs)
         utils.validate_dict_values(self.operations)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.inputs, report_issues)
-        utils.coerce_dict_values(container, self.operations, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.inputs, report_issues)
+        utils.coerce_dict_values(self.operations, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1765,8 +1773,8 @@ class OperationBase(InstanceModelMixin):
         # TODO must be associated with interface or service
         utils.validate_dict_values(self.inputs)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.inputs, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.inputs, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1905,8 +1913,8 @@ class ArtifactBase(InstanceModelMixin):
     def validate(self):
         utils.validate_dict_values(self.properties)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.properties, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index e3320fa..7a192a7 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -17,7 +17,6 @@
 
 from __future__ import absolute_import  # so we can import standard 'types'
 
-from types import FunctionType
 from datetime import datetime
 
 from sqlalchemy import (
@@ -25,7 +24,8 @@ from sqlalchemy import (
     Text,
     Integer,
     Boolean,
-    DateTime
+    DateTime,
+    PickleType
 )
 from sqlalchemy.ext.declarative import declared_attr
 from sqlalchemy.ext.associationproxy import association_proxy
@@ -347,16 +347,16 @@ class ServiceTemplateBase(TemplateModelMixin):
         if self.artifact_types is not None:
             self.artifact_types.validate()
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.meta_data, report_issues)
-        utils.coerce_dict_values(container, self.node_templates, report_issues)
-        utils.coerce_dict_values(container, self.group_templates, report_issues)
-        utils.coerce_dict_values(container, self.policy_templates, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.meta_data, report_issues)
+        utils.coerce_dict_values(self.node_templates, report_issues)
+        utils.coerce_dict_values(self.group_templates, report_issues)
+        utils.coerce_dict_values(self.policy_templates, report_issues)
         if self.substitution_template is not None:
-            self.substitution_template.coerce_values(container, report_issues)
-        utils.coerce_dict_values(container, self.inputs, report_issues)
-        utils.coerce_dict_values(container, self.outputs, report_issues)
-        utils.coerce_dict_values(container, self.workflow_templates, report_issues)
+            self.substitution_template.coerce_values(report_issues)
+        utils.coerce_dict_values(self.inputs, report_issues)
+        utils.coerce_dict_values(self.outputs, report_issues)
+        utils.coerce_dict_values(self.workflow_templates, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -427,7 +427,7 @@ class NodeTemplateBase(TemplateModelMixin):
     :ivar requirement_templates: Potential relationships with other nodes
     :vartype requirement_templates: [:class:`RequirementTemplate`]
     :ivar target_node_template_constraints: Constraints for filtering relationship targets
-    :vartype target_node_template_constraints: [:class:`FunctionType`]
+    :vartype target_node_template_constraints: [:class:`NodeTemplateConstraint`]
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar group_templates: We are a member of these groups
@@ -504,6 +504,10 @@ class NodeTemplateBase(TemplateModelMixin):
         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')
+
+    @declared_attr
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
@@ -525,12 +529,12 @@ class NodeTemplateBase(TemplateModelMixin):
     default_instances = Column(Integer, default=1)
     min_instances = Column(Integer, default=0)
     max_instances = Column(Integer, default=None)
-    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
+    target_node_template_constraints = Column(PickleType)
 
-    def is_target_node_valid(self, target_node_template):
+    def is_target_node_template_valid(self, target_node_template):
         if self.target_node_template_constraints:
-            for node_type_constraint in self.target_node_template_constraints:
-                if not node_type_constraint(target_node_template, self):
+            for node_template_constraint in self.target_node_template_constraints:
+                if not node_template_constraint.matches(self, target_node_template):
                     return False
         return True
 
@@ -544,6 +548,7 @@ class NodeTemplateBase(TemplateModelMixin):
             ('min_instances', self.min_instances),
             ('max_instances', self.max_instances),
             ('properties', formatting.as_raw_dict(self.properties)),
+            ('attributes', formatting.as_raw_dict(self.properties)),
             ('interface_templates', formatting.as_raw_list(self.interface_templates)),
             ('artifact_templates', formatting.as_raw_list(self.artifact_templates)),
             ('capability_templates', formatting.as_raw_list(self.capability_templates)),
@@ -564,24 +569,34 @@ class NodeTemplateBase(TemplateModelMixin):
                            runtime_properties={},
                            node_template=self)
         utils.instantiate_dict(node, node.properties, self.properties)
+        utils.instantiate_dict(node, node.attributes, self.attributes)
         utils.instantiate_dict(node, node.interfaces, self.interface_templates)
         utils.instantiate_dict(node, node.artifacts, self.artifact_templates)
         utils.instantiate_dict(node, node.capabilities, self.capability_templates)
+
+        # Default attributes
+        if 'tosca_name' in node.attributes:
+            node.attributes['tosca_name'].value = self.name
+        if 'tosca_id' in node.attributes:
+            node.attributes['tosca_id'].value = name
+
         return node
 
     def validate(self):
         utils.validate_dict_values(self.properties)
+        utils.validate_dict_values(self.attributes)
         utils.validate_dict_values(self.interface_templates)
         utils.validate_dict_values(self.artifact_templates)
         utils.validate_dict_values(self.capability_templates)
         utils.validate_list_values(self.requirement_templates)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.properties, report_issues)
-        utils.coerce_dict_values(self, self.interface_templates, report_issues)
-        utils.coerce_dict_values(self, self.artifact_templates, report_issues)
-        utils.coerce_dict_values(self, self.capability_templates, report_issues)
-        utils.coerce_list_values(self, self.requirement_templates, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
+        utils.coerce_dict_values(self.attributes, report_issues)
+        utils.coerce_dict_values(self.interface_templates, report_issues)
+        utils.coerce_dict_values(self.artifact_templates, report_issues)
+        utils.coerce_dict_values(self.capability_templates, report_issues)
+        utils.coerce_list_values(self.requirement_templates, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -597,6 +612,7 @@ class NodeTemplateBase(TemplateModelMixin):
                 if self.max_instances is not None
                 else ' or more'))
             utils.dump_dict_values(self.properties, 'Properties')
+            utils.dump_dict_values(self.attributes, 'Attributes')
             utils.dump_interfaces(self.interface_templates)
             utils.dump_dict_values(self.artifact_templates, 'Artifact templates')
             utils.dump_dict_values(self.capability_templates, 'Capability templates')
@@ -720,9 +736,9 @@ class GroupTemplateBase(TemplateModelMixin):
         utils.validate_dict_values(self.properties)
         utils.validate_dict_values(self.interface_templates)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.properties, report_issues)
-        utils.coerce_dict_values(self, self.interface_templates, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
+        utils.coerce_dict_values(self.interface_templates, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -851,8 +867,8 @@ class PolicyTemplateBase(TemplateModelMixin):
     def validate(self):
         utils.validate_dict_values(self.properties)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.properties, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -945,8 +961,8 @@ class SubstitutionTemplateBase(TemplateModelMixin):
     def validate(self):
         utils.validate_dict_values(self.mappings)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.mappings, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.mappings, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1049,7 +1065,7 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
         return collections.OrderedDict((
             ('name', self.name)))
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         pass
 
     def instantiate(self, container):
@@ -1113,7 +1129,7 @@ class RequirementTemplateBase(TemplateModelMixin):
     :ivar target_capability_name: Name of capability in target node (optional)
     :vartype target_capability_name: basestring
     :ivar target_node_template_constraints: Constraints for filtering relationship targets
-    :vartype target_node_template_constraints: [:class:`FunctionType`]
+    :vartype target_node_template_constraints: [:class:`NodeTemplateConstraint`]
     :ivar relationship_template: Template for relationships (optional)
     :vartype relationship_template: :class:`RelationshipTemplate`
     :ivar node_template: Containing node template
@@ -1183,9 +1199,7 @@ class RequirementTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def relationship_template(cls):
-        return relationship.one_to_one(cls,
-                                       'relationship_template',
-                                       back_populates=relationship.NO_BACK_POP)
+        return relationship.one_to_one(cls, 'relationship_template')
 
     # endregion
 
@@ -1215,18 +1229,18 @@ class RequirementTemplateBase(TemplateModelMixin):
     # endregion
 
     target_capability_name = Column(Text)
-    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
+    target_node_template_constraints = Column(PickleType)
 
     def find_target(self, source_node_template):
         context = ConsumptionContext.get_thread_local()
 
         # We might already have a specific node template, so we'll just verify it
         if self.target_node_template is not None:
-            if not source_node_template.is_target_node_valid(self.target_node_template):
+            if not source_node_template.is_target_node_template_valid(self.target_node_template):
                 context.validation.report('requirement "{0}" of node template "{1}" is for node '
                                           'template "{2}" but it does not match constraints'.format(
                                               self.name,
-                                              self.target_node_template_name,
+                                              self.target_node_template.name,
                                               source_node_template.name),
                                           level=validation.Issue.BETWEEN_TYPES)
             if (self.target_capability_type is not None) \
@@ -1247,7 +1261,7 @@ class RequirementTemplateBase(TemplateModelMixin):
                 if self.target_node_type.get_descendant(target_node_template.type.name) is None:
                     continue
 
-                if not source_node_template.is_target_node_valid(target_node_template):
+                if not source_node_template.is_target_node_template_valid(target_node_template):
                     continue
 
                 target_node_capability = self.find_target_capability(source_node_template,
@@ -1284,9 +1298,9 @@ class RequirementTemplateBase(TemplateModelMixin):
         if self.relationship_template:
             self.relationship_template.validate()
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         if self.relationship_template is not None:
-            self.relationship_template.coerce_values(container, report_issues)
+            self.relationship_template.coerce_values(report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1417,9 +1431,9 @@ class RelationshipTemplateBase(TemplateModelMixin):
         utils.validate_dict_values(self.properties)
         utils.validate_dict_values(self.interface_templates)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.properties, report_issues)
-        utils.coerce_dict_values(self, self.interface_templates, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
+        utils.coerce_dict_values(self.interface_templates, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1543,8 +1557,8 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
         # Apply requirement constraints
         if requirement.target_node_template_constraints:
-            for node_type_constraint in requirement.target_node_template_constraints:
-                if not node_type_constraint(target_node_template, source_node_template):
+            for node_template_constraint in requirement.target_node_template_constraints:
+                if not node_template_constraint.matches(source_node_template, target_node_template):
                     return False
 
         return True
@@ -1574,8 +1588,8 @@ class CapabilityTemplateBase(TemplateModelMixin):
     def validate(self):
         utils.validate_dict_values(self.properties)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(self, self.properties, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1728,9 +1742,9 @@ class InterfaceTemplateBase(TemplateModelMixin):
         utils.validate_dict_values(self.inputs)
         utils.validate_dict_values(self.operation_templates)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.inputs, report_issues)
-        utils.coerce_dict_values(container, self.operation_templates, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.inputs, report_issues)
+        utils.coerce_dict_values(self.operation_templates, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -1882,7 +1896,7 @@ class OperationTemplateBase(TemplateModelMixin):
                 plugin = None
                 implementation = None
         else:
-            # using the execution plugin
+            # Using the execution plugin
             plugin = None
             implementation = self.implementation
 
@@ -1903,8 +1917,8 @@ class OperationTemplateBase(TemplateModelMixin):
     def validate(self):
         utils.validate_dict_values(self.inputs)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.inputs, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.inputs, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -2051,8 +2065,8 @@ class ArtifactTemplateBase(TemplateModelMixin):
     def validate(self):
         utils.validate_dict_values(self.properties)
 
-    def coerce_values(self, container, report_issues):
-        utils.coerce_dict_values(container, self.properties, report_issues)
+    def coerce_values(self, report_issues):
+        utils.coerce_dict_values(self.properties, report_issues)
 
     def dump(self):
         context = ConsumptionContext.get_thread_local()
@@ -2128,7 +2142,7 @@ class PluginSpecificationBase(TemplateModelMixin):
             ('version', self.version),
             ('enabled', self.enabled)))
 
-    def coerce_values(self, container, report_issues):
+    def coerce_values(self, report_issues):
         pass
 
     def resolve(self, model_storage):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/modeling/utils.py
----------------------------------------------------------------------
diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py
index 91d7b9c..0404fe4 100644
--- a/aria/modeling/utils.py
+++ b/aria/modeling/utils.py
@@ -19,9 +19,6 @@ from StringIO import StringIO
 
 from . import exceptions
 from ..parser.consumption import ConsumptionContext
-from ..parser.exceptions import InvalidValueError
-from ..parser.presentation import Value
-from ..utils.collections import OrderedDict
 from ..utils.console import puts
 from ..utils.type import validate_value_type
 
@@ -39,6 +36,21 @@ class ModelJSONEncoder(JSONEncoder):
             return JSONEncoder.default(self, o)
 
 
+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`.
+    """
+
+    def __init__(self, node_template):
+        self.container = node_template
+        self.service = None
+
+    @property
+    def service_template(self):
+        return self.container.service_template
+
+
 def create_inputs(inputs, template_inputs):
     """
     :param inputs: key-value dict
@@ -50,7 +62,7 @@ def create_inputs(inputs, template_inputs):
     from . import models
     input_models = []
     for input_name, input_val in merged_inputs.iteritems():
-        parameter = models.Parameter(
+        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,
@@ -109,39 +121,17 @@ def _merge_and_validate_inputs(inputs, template_inputs):
     return merged_inputs
 
 
-def coerce_value(container, value, report_issues=False):
-    if isinstance(value, Value):
-        value = value.value
-
-    if isinstance(value, list):
-        return [coerce_value(container, v, report_issues) for v in value]
-    elif isinstance(value, dict):
-        return OrderedDict((k, coerce_value(container, v, report_issues))
-                           for k, v in value.iteritems())
-    elif hasattr(value, '_evaluate'):
-        context = ConsumptionContext.get_thread_local()
-        try:
-            value = value._evaluate(context, container)
-            value = coerce_value(container, value, report_issues)
-        except exceptions.CannotEvaluateFunctionException:
-            pass
-        except InvalidValueError as e:
-            if report_issues:
-                context.validation.report(e.issue)
-    return value
-
-
-def coerce_dict_values(container, the_dict, report_issues=False):
+def coerce_dict_values(the_dict, report_issues=False):
     if not the_dict:
         return
-    coerce_list_values(container, the_dict.itervalues(), report_issues)
+    coerce_list_values(the_dict.itervalues(), report_issues)
 
 
-def coerce_list_values(container, the_list, report_issues=False):
+def coerce_list_values(the_list, report_issues=False):
     if not the_list:
         return
     for value in the_list:
-        value.coerce_values(container, report_issues)
+        value.coerce_values(report_issues)
 
 
 def validate_dict_values(the_dict):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/orchestrator/execution_plugin/instantiation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/execution_plugin/instantiation.py b/aria/orchestrator/execution_plugin/instantiation.py
index ce114f0..c09434e 100644
--- a/aria/orchestrator/execution_plugin/instantiation.py
+++ b/aria/orchestrator/execution_plugin/instantiation.py
@@ -15,7 +15,7 @@
 
 # TODO: this module will eventually be moved to a new "aria.instantiation" package
 
-from ...utils.formatting import full_type_name
+from ...utils.type import full_type_name
 from ...utils.collections import OrderedDict
 from ...parser import validation
 from ...parser.consumption import ConsumptionContext

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/__init__.py b/aria/parser/__init__.py
index 9ab8785..64df88a 100644
--- a/aria/parser/__init__.py
+++ b/aria/parser/__init__.py
@@ -13,7 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from .specification import dsl_specification, iter_specifications
+from .specification import implements_specification, iter_specifications
 
 
 MODULES = (
@@ -26,5 +26,5 @@ MODULES = (
 
 __all__ = (
     'MODULES',
-    'dsl_specification',
+    'implements_specification',
     'iter_specifications')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/consumption/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/__init__.py b/aria/parser/consumption/__init__.py
index 8f6d2b6..76e73be 100644
--- a/aria/parser/consumption/__init__.py
+++ b/aria/parser/consumption/__init__.py
@@ -28,9 +28,11 @@ from .modeling import (
     Types,
     ServiceInstance,
     FindHosts,
+    ValidateServiceInstance,
     ConfigureOperations,
     SatisfyRequirements,
-    ValidateCapabilities
+    ValidateCapabilities,
+    CoerceServiceInstanceValues
 )
 from .inputs import Inputs
 
@@ -45,7 +47,10 @@ __all__ = (
     'ServiceTemplate',
     'Types',
     'ServiceInstance',
-    'Inputs',
+    'FindHosts',
+    'ValidateServiceInstance',
+    'ConfigureOperations',
     'SatisfyRequirements',
-    'ValidateCapabilities'
+    'ValidateCapabilities',
+    'CoerceServiceInstanceValues'
 )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/consumption/modeling.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/modeling.py b/aria/parser/consumption/modeling.py
index 771fd7f..44027b9 100644
--- a/aria/parser/consumption/modeling.py
+++ b/aria/parser/consumption/modeling.py
@@ -42,7 +42,7 @@ class CoerceServiceTemplateValues(Consumer):
     """
 
     def consume(self):
-        self.context.modeling.template.coerce_values(None, True)
+        self.context.modeling.template.coerce_values(True)
 
 
 class ValidateServiceTemplate(Consumer):
@@ -116,7 +116,7 @@ class CoerceServiceInstanceValues(Consumer):
     """
 
     def consume(self):
-        self.context.modeling.instance.coerce_values(None, True)
+        self.context.modeling.instance.coerce_values(True)
 
 
 class ValidateServiceInstance(Consumer):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/presentation/fields.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/fields.py b/aria/parser/presentation/fields.py
index da3cb05..7f85723 100644
--- a/aria/parser/presentation/fields.py
+++ b/aria/parser/presentation/fields.py
@@ -21,7 +21,8 @@ from ...exceptions import AriaException
 from ...utils.collections import FrozenDict, FrozenList, deepcopy_with_locators, merge, OrderedDict
 from ...utils.caching import cachedmethod
 from ...utils.console import puts
-from ...utils.formatting import as_raw, safe_repr, full_type_name
+from ...utils.formatting import as_raw, safe_repr
+from ...utils.type import full_type_name
 from ...utils.exceptions import print_exception
 from ..exceptions import InvalidValueError
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/presentation/presentation.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/presentation.py b/aria/parser/presentation/presentation.py
index 0f098b5..644d880 100644
--- a/aria/parser/presentation/presentation.py
+++ b/aria/parser/presentation/presentation.py
@@ -15,7 +15,8 @@
 
 from ...utils.caching import HasCachedMethods
 from ...utils.collections import deepcopy_with_locators
-from ...utils.formatting import full_type_name, safe_repr
+from ...utils.formatting import safe_repr
+from ...utils.type import full_type_name
 from ...utils.console import puts
 from ..validation import Issue
 from .null import none_to_null

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/presentation/utils.py
----------------------------------------------------------------------
diff --git a/aria/parser/presentation/utils.py b/aria/parser/presentation/utils.py
index 74adbd1..fbe971b 100644
--- a/aria/parser/presentation/utils.py
+++ b/aria/parser/presentation/utils.py
@@ -15,7 +15,8 @@
 
 from types import FunctionType
 
-from ...utils.formatting import full_type_name, safe_repr
+from ...utils.formatting import safe_repr
+from ...utils.type import full_type_name
 from ..validation import Issue
 from .null import NULL
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/specification.py
----------------------------------------------------------------------
diff --git a/aria/parser/specification.py b/aria/parser/specification.py
index 1df11ce..714bed1 100644
--- a/aria/parser/specification.py
+++ b/aria/parser/specification.py
@@ -17,40 +17,7 @@ import re
 
 from ..extension import parser
 from ..utils.collections import OrderedDict
-from ..utils.formatting import full_type_name
-
-_DSL_SPECIFICATIONS = {}
-
-
-def dsl_specification(section, spec):
-    """
-    Decorator for TOSCA specification.
-
-    Used for documentation and standards compliance.
-    """
-    def decorator(obj):
-        specification = _DSL_SPECIFICATIONS.get(spec)
-
-        if specification is None:
-            specification = {}
-            _DSL_SPECIFICATIONS[spec] = specification
-
-        if section in specification:
-            raise Exception('you cannot specify the same @dsl_specification twice, consider'
-                            ' adding \'-1\', \'-2\', etc.: %s, %s' % (spec, section))
-
-        specification[section] = OrderedDict((
-            ('code', full_type_name(obj)),
-            ('doc', obj.__doc__)))
-
-        try:
-            setattr(obj, '_dsl_specifications', {section: section, spec: spec})
-        except BaseException:
-            pass
-
-        return obj
-
-    return decorator
+from ..utils.specification import (DSL_SPECIFICATIONS, implements_specification) # pylint: disable=unused-import
 
 
 def iter_specifications():
@@ -63,12 +30,10 @@ def iter_specifications():
             details['code'] = sections[k]['code']
             yield k, _fix_details(sections[k], spec)
 
-    for spec, sections in _DSL_SPECIFICATIONS.iteritems():
+    for spec, sections in DSL_SPECIFICATIONS.iteritems():
         yield spec, iter_sections(spec, sections)
 
 
-# Utils
-
 def _section_key(value):
     try:
         parts = value.split('-', 1)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/parser/validation/issue.py
----------------------------------------------------------------------
diff --git a/aria/parser/validation/issue.py b/aria/parser/validation/issue.py
index f001efc..db8065d 100644
--- a/aria/parser/validation/issue.py
+++ b/aria/parser/validation/issue.py
@@ -16,7 +16,7 @@
 from __future__ import absolute_import  # so we can import standard 'collections'
 
 from ...utils.collections import OrderedDict
-from ...utils.formatting import full_type_name
+from ...utils.type import full_type_name
 
 
 class Issue(object):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/utils/caching.py
----------------------------------------------------------------------
diff --git a/aria/utils/caching.py b/aria/utils/caching.py
index 613ade6..c9e475a 100644
--- a/aria/utils/caching.py
+++ b/aria/utils/caching.py
@@ -65,22 +65,24 @@ class cachedmethod(object):  # pylint: disable=invalid-name
             return self.func(*args, **kwargs)
 
         instance = args[0]
-        cache = instance.get_method_cache()
+        if not hasattr(instance, '_method_cache'):
+            instance._method_cache = {}
+        method_cache = instance._method_cache
 
         key = (self.func, args[1:], frozenset(kwargs.items()))
 
         try:
             with self.lock:
-                return_value = cache[key]
+                return_value = method_cache[key]
                 self.hits += 1
         except KeyError:
             return_value = self.func(*args, **kwargs)
             with self.lock:
-                cache[key] = return_value
+                method_cache[key] = return_value
                 self.misses += 1
             # Another thread may override our cache entry here, so we need to read
             # it again to make sure all threads use the same return value
-            return_value = cache.get(key, return_value)
+            return_value = method_cache.get(key, return_value)
 
         return return_value
 
@@ -93,9 +95,6 @@ class HasCachedMethods(object):
     def __init__(self, method_cache=None):
         self._method_cache = method_cache or {}
 
-    def get_method_cache(self):
-        return self._method_cache
-
     @property
     def _method_cache_info(self):
         """

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/utils/formatting.py
----------------------------------------------------------------------
diff --git a/aria/utils/formatting.py b/aria/utils/formatting.py
index b5e141d..f96a4ce 100644
--- a/aria/utils/formatting.py
+++ b/aria/utils/formatting.py
@@ -71,18 +71,6 @@ class YamlAsRawDumper(yaml.dumper.RoundTripDumper):  # pylint: disable=too-many-
         return super(YamlAsRawDumper, self).represent_data(data)
 
 
-def full_type_name(value):
-    """
-    The full class name of a type or object.
-    """
-
-    if not isinstance(value, type):
-        value = value.__class__
-    module = str(value.__module__)
-    name = str(value.__name__)
-    return name if module == '__builtin__' else '%s.%s' % (module, name)
-
-
 def decode_list(data):
     decoded_list = []
     for item in data:
@@ -163,8 +151,8 @@ def as_raw(value):
             value = value()
     elif isinstance(value, list):
         value = list(value)
-        for i, _ in enumerate(value):
-            value[i] = as_raw(value[i])
+        for i, v in enumerate(value):
+            value[i] = as_raw(v)
     elif isinstance(value, dict):
         value = dict(value)
         for k, v in value.iteritems():

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/utils/specification.py
----------------------------------------------------------------------
diff --git a/aria/utils/specification.py b/aria/utils/specification.py
new file mode 100644
index 0000000..e74c103
--- /dev/null
+++ b/aria/utils/specification.py
@@ -0,0 +1,53 @@
+# 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 .collections import OrderedDict
+
+
+DSL_SPECIFICATIONS = {}
+
+
+def implements_specification(section, spec):
+    """
+    Decorator for specification implementations.
+
+    Used for documentation and standards compliance.
+    """
+
+    from .type import full_type_name
+
+    def decorator(obj):
+        specification = DSL_SPECIFICATIONS.get(spec)
+
+        if specification is None:
+            specification = {}
+            DSL_SPECIFICATIONS[spec] = specification
+
+        if section in specification:
+            raise Exception('you cannot specify the same @implements_specification twice, consider'
+                            ' adding \'-1\', \'-2\', etc.: {0}, {1}'.format(spec, section))
+
+        specification[section] = OrderedDict((
+            ('code', full_type_name(obj)),
+            ('doc', obj.__doc__)))
+
+        try:
+            setattr(obj, '_dsl_specifications', {section: section, spec: spec})
+        except BaseException:
+            pass
+
+        return obj
+
+    return decorator

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/aria/utils/type.py
----------------------------------------------------------------------
diff --git a/aria/utils/type.py b/aria/utils/type.py
index dad5427..f08159a 100644
--- a/aria/utils/type.py
+++ b/aria/utils/type.py
@@ -13,49 +13,142 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import datetime
+
+from .specification import implements_specification
+
+
+BASE_TYPES_TO_CANONICAL_NAMES = {
+    # TOSCA aliases:
+    None.__class__: 'null',
+    basestring: 'string',
+    int: 'integer',
+    float: 'float',
+    bool: 'boolean',
+    list: 'list',
+    tuple: 'list',
+    dict: 'map',
+    datetime.datetime: 'timestamp'
+}
+
+NAMES_TO_CANONICAL_TYPES = {
+    # Python:
+    'none': None.__class__,
+    'basestring': unicode,
+    'str': unicode,
+    'unicode': unicode,
+    'int': int,
+    'float': float, # also a TOSCA alias
+    'bool': bool,
+    'list': list, # also a TOSCA alias
+    'tuple': list,
+    'dict': dict,
+    'datetime': datetime.datetime,
+
+    # YAML 1.2:
+    'tag:yaml.org,2002:null': None.__class__,
+    'tag:yaml.org,2002:str': unicode,
+    'tag:yaml.org,2002:integer': int,
+    'tag:yaml.org,2002:float': float,
+    'tag:yaml.org,2002:bool': bool,
+
+    # TOSCA aliases:
+    'null': None.__class__,
+    'string': unicode,
+    'integer': int,
+    'boolean': bool,
+
+    # TOSCA custom types:
+    'map': dict,
+    'timestamp': datetime.datetime
+}
+
+
+def full_type_name(value):
+    """
+    The full class name of a type or instance.
+    """
+
+    if not isinstance(value, type):
+        value = value.__class__
+    module = str(value.__module__)
+    name = str(value.__name__)
+    return name if module == '__builtin__' else '{0}.{1}'.format(module, name)
+
+
+@implements_specification('3.2.1-1', 'tosca-simple-1.0')
+def canonical_type_name(value):
+    """
+    Returns the canonical TOSCA type name of a primitive value, or None if unknown.
+
+    For a list of TOSCA type names, 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>`__
+    """
+
+    for the_type, name in BASE_TYPES_TO_CANONICAL_NAMES.iteritems():
+        if isinstance(value, the_type):
+            return name
+    return None
+
+
+@implements_specification('3.2.1-2', 'tosca-simple-1.0')
+def canonical_type(type_name):
+    """
+    Return the canonical type for any Python, YAML, or TOSCA type name or alias, or None if
+    unsupported.
+
+    :param type_name: Type name (case insensitive)
+    """
+
+    return NAMES_TO_CANONICAL_TYPES.get(type_name.lower())
+
 
 def validate_value_type(value, type_name):
     """
-    Validate a value is of a specific type.
+    Validate that a value is of a specific type. Supports Python, YAML, and TOSCA type names and
+    aliases.
+
     A ValueError will be raised on type mismatch.
-    Supports both python and yaml type names.
-    """
-
-    #TODO add timestamp type?
-    name_to_type = {
-        'list': list,
-        'dict': dict,
-        'tuple': tuple,
-        'str': str,
-        'unicode': str,
-        'string': str,
-        'int': int,
-        'integer': int,
-        'bool': bool,
-        'boolean': bool,
-        'float': float
-    }
-
-    type_ = name_to_type.get(type_name.lower())
-    if type_ is None:
-        raise RuntimeError('No supported type_name was provided')
-
-    if not isinstance(value, type_):
+
+    :param type_name: Type name (case insensitive)
+    """
+
+    the_type = canonical_type(type_name)
+    if the_type is None:
+        raise RuntimeError('Unsupported type name: {0}'.format(type_name))
+
+    # The following Python types do not inherit from the canonical type, but are considered valid
+    if (the_type is unicode) and isinstance(value, str):
+        return
+    if (the_type is list) and isinstance(value, tuple):
+        return
+
+    if not isinstance(value, the_type):
         raise ValueError('Value {0} is not of type {1}'.format(value, type_name))
 
 
-def convert_value_to_type(str_value, type_name):
+def convert_value_to_type(str_value, python_type_name):
+    """
+    Converts a value to a specific Python primitive type.
+
+    A ValueError will be raised for unsupported types or conversion failure.
+
+    :param python_type_name: Python primitive type name (case insensitive)
+    """
+
+    python_type_name = python_type_name.lower()
     try:
-        if type_name.lower() in ['str', 'unicode']:
+        if python_type_name in ('str', 'unicode'):
             return str_value.decode('utf-8')
-        elif type_name.lower() == 'int':
+        elif python_type_name == 'int':
             return int(str_value)
-        elif type_name.lower() == 'bool':
+        elif python_type_name == 'bool':
             return bool(str_value)
-        elif type_name.lower() == 'float':
+        elif python_type_name == 'float':
             return float(str_value)
         else:
-            raise ValueError('No supported type_name was provided')
+            raise ValueError('Unsupported Python type name: {0}'.format(python_type_name))
     except ValueError:
-        raise ValueError('Trying to convert {0} to {1} failed'.format(str_value,
-                                                                      type_name))
+        raise ValueError('Failed to to convert {0} to {1}'.format(str_value,
+                                                                  python_type_name))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml
index ff6dc92..b912fb2 100644
--- a/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml
@@ -65,4 +65,4 @@ topology_template:
       value: { get_attribute: [ my_server, private_address ] }
     volume_id:
       description: The volume id of the block storage instance.
-      value: { get_attribute: [ my_storage, volume_id ] }
+      value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml
index 09c30a7..ac475cf 100644
--- a/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml
@@ -72,4 +72,4 @@ topology_template:
 
     volume_id:
       description: The volume id of the block storage instance.
-      value: { get_attribute: [ my_storage, volume_id ] }
+      value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml
index 3018fe9..c3f183e 100644
--- a/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml
@@ -65,4 +65,4 @@ topology_template:
       value: { get_attribute: [ my_server, private_address ] }
     volume_id:
       description: The volume id of the block storage instance.
-      value: { get_attribute: [ my_storage, volume_id ] }
+      value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml
index 0693ddd..e2bdb9f 100644
--- a/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml
@@ -93,4 +93,4 @@ topology_template:
       value: { get_attribute: [ my_web_app_tier_2, private_address ] }
     volume_id:
       description: The volume id of the block storage instance.
-      value: { get_attribute: [ my_storage, volume_id ] }
+      value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml
index 5f5cf71..a0c2229 100644
--- a/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml
@@ -100,10 +100,10 @@ topology_template:
   outputs:
     private_ip_1:
       description: The private IP address of the application's first tier.
-      value: { get_attribute: [my_web_app_tier_1, private_address] }
+      value: { get_attribute: [ my_web_app_tier_1, private_address ] }
     private_ip_2:
       description: The private IP address of the application's second tier.
-      value: { get_attribute: [my_web_app_tier_2, private_address] }
+      value: { get_attribute: [ my_web_app_tier_2, private_address ] }
     volume_id:
       description: The volume id of the block storage instance.
-      value: { get_attribute: [my_storage, volume_id] }
+      value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml
index 808245b..534884a 100644
--- a/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml
+++ b/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml
@@ -96,7 +96,7 @@ topology_template:
       value: { get_attribute: [ my_server2, private_address ] }
     volume_id_1:
       description: The volume id of the first block storage instance.
-      value: { get_attribute: [my_storage, volume_id] }
+      value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec
     volume_id_2:
       description: The volume id of the second block storage instance.
-      value: { get_attribute: [ my_storage2, volume_id ] }
+      value: { get_property: [ my_storage2, volume_id ] } # ARIA NOTE: wrong in spec

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml
----------------------------------------------------------------------
diff --git a/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml b/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml
index 3485e49..50401ec 100644
--- a/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml
+++ b/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml
@@ -59,7 +59,7 @@ topology_template:
              implementation: scripts/nodejs/configure.sh
              inputs:
                github_url: { get_property: [ SELF, github_url ] }
-               mongodb_ip: { get_attribute: [mongo_server, private_address] }
+               mongodb_ip: { get_attribute: [ mongo_server, private_address ] }
            start: scripts/nodejs/start.sh
 
     nodejs:
@@ -90,7 +90,7 @@ topology_template:
           configure:
             implementation: scripts/mongodb/config.sh
             inputs:
-              mongodb_ip: { get_attribute: [mongo_server, ip_address] }
+              mongodb_ip: { get_attribute: [ mongo_server, private_address ] } # ARIA NOTE: wrong in spec
           start: scripts/mongodb/start.sh
 
     elasticsearch:
@@ -115,7 +115,7 @@ topology_template:
                   pre_configure_source:
                     implementation: python/logstash/configure_elasticsearch.py
                     inputs:
-                      elasticsearch_ip: { get_attribute: [elasticsearch_server, ip_address] }
+                      elasticsearch_ip: { get_attribute: [ elasticsearch_server, private_address ] } # ARIA NOTE: wrong in spec
       interfaces:
         Standard: # ARIA NOTE: wrong in spec
           create: scripts/lostash/create.sh
@@ -133,8 +133,8 @@ topology_template:
           configure:
             implementation: scripts/kibana/config.sh
             inputs:
-              elasticsearch_ip: { get_attribute: [ elasticsearch_server, ip_address ] }
-              kibana_ip: { get_attribute: [ kibana_server, ip_address ] }
+              elasticsearch_ip: { get_attribute: [ elasticsearch_server, private_address ] } # ARIA NOTE: wrong in spec
+              kibana_ip: { get_attribute: [ kibana_server, private_address ] } # ARIA NOTE: wrong in spec
           start: scripts/kibana/start.sh
 
     app_collectd:
@@ -155,7 +155,7 @@ topology_template:
           configure:
             implementation: python/collectd/config.py
             inputs:
-              logstash_ip: { get_attribute: [ logstash_server, ip_address ] }
+              logstash_ip: { get_attribute: [ logstash_server, private_address ] } # ARIA NOTE: wrong in spec
           start: scripts/collectd/start.sh
 
     app_rsyslog:
@@ -176,7 +176,7 @@ topology_template:
           configure:
             implementation: scripts/rsyslog/config.sh
             inputs:
-              logstash_ip: { get_attribute: [ logstash_server, ip_address ] }
+              logstash_ip: { get_attribute: [ logstash_server, private_address ] } # ARIA NOTE: wrong in spec
           start: scripts/rsyslog/start.sh
 
     app_server:

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/extensions/aria_extension_tosca/simple_v1_0/__init__.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/__init__.py
index 29df362..7dcc60a 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/__init__.py
@@ -30,8 +30,6 @@ from .types import (ArtifactType, DataType, CapabilityType, InterfaceType, Relat
                     NodeType, GroupType, PolicyType)
 from .data_types import (Timestamp, Version, Range, List, Map, ScalarSize, ScalarTime,
                          ScalarFrequency)
-from .functions import (Concat, Token, GetInput, GetProperty, GetAttribute, GetOperationOutput,
-                        GetNodesOfType, GetArtifact)
 
 MODULES = (
     'modeling',
@@ -89,12 +87,4 @@ __all__ = (
     'Map',
     'ScalarSize',
     'ScalarTime',
-    'ScalarFrequency',
-    'Concat',
-    'Token',
-    'GetInput',
-    'GetProperty',
-    'GetAttribute',
-    'GetOperationOutput',
-    'GetNodesOfType',
-    'GetArtifact')
+    'ScalarFrequency')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/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 9a2179a..d929ce0 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/assignments.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/assignments.py
@@ -15,7 +15,7 @@
 
 from aria.utils.collections import FrozenDict
 from aria.utils.caching import cachedmethod
-from aria.parser import dsl_specification
+from aria.parser import implements_specification
 from aria.parser.presentation import (AsIsPresentation, has_fields, allow_unknown_fields,
                                       short_form_field, primitive_field, object_field,
                                       object_dict_field, object_dict_unknown_fields,
@@ -32,7 +32,7 @@ from .presentation.field_validators import (node_template_or_type_validator,
 from .presentation.types import (convert_shorthand_to_full_type_name,
                                  get_type_by_full_or_shorthand_name)
 
-@dsl_specification('3.5.9', 'tosca-simple-1.0')
+@implements_specification('3.5.9', 'tosca-simple-1.0')
 class PropertyAssignment(AsIsPresentation):
     """
     This section defines the grammar for assigning values to named properties within TOSCA Node and
@@ -45,7 +45,7 @@ class PropertyAssignment(AsIsPresentation):
 
 @short_form_field('implementation')
 @has_fields
-@dsl_specification('3.5.13-2', 'tosca-simple-1.0')
+@implements_specification('3.5.13-2', 'tosca-simple-1.0')
 class OperationAssignment(ExtensiblePresentation):
     """
     An operation definition defines a named function or procedure that can be bound to an
@@ -105,7 +105,7 @@ class OperationAssignment(ExtensiblePresentation):
 
 @allow_unknown_fields
 @has_fields
-@dsl_specification('3.5.14-2', 'tosca-simple-1.0')
+@implements_specification('3.5.14-2', 'tosca-simple-1.0')
 class InterfaceAssignment(ExtensiblePresentation):
     """
     An interface definition defines a named interface that can be associated with a Node or
@@ -200,7 +200,7 @@ class RelationshipAssignment(ExtensiblePresentation):
 
 @short_form_field('node')
 @has_fields
-@dsl_specification('3.7.2', 'tosca-simple-1.0')
+@implements_specification('3.7.2', 'tosca-simple-1.0')
 class RequirementAssignment(ExtensiblePresentation):
     """
     A Requirement assignment allows template authors to provide either concrete names of TOSCA
@@ -297,7 +297,7 @@ class RequirementAssignment(ExtensiblePresentation):
 
         return None, None
 
-@dsl_specification('3.5.11', 'tosca-simple-1.0')
+@implements_specification('3.5.11', 'tosca-simple-1.0')
 class AttributeAssignment(AsIsPresentation):
     """
     This section defines the grammar for assigning values to named attributes within TOSCA Node and
@@ -309,7 +309,7 @@ class AttributeAssignment(AsIsPresentation):
     """
 
 @has_fields
-@dsl_specification('3.7.1', 'tosca-simple-1.0')
+@implements_specification('3.7.1', 'tosca-simple-1.0')
 class CapabilityAssignment(ExtensiblePresentation):
     """
     A capability assignment allows node template authors to assign values to properties and
@@ -351,7 +351,7 @@ class CapabilityAssignment(ExtensiblePresentation):
             if capability_definition is not None else None
 
 @has_fields
-@dsl_specification('3.5.6', 'tosca-simple-1.0')
+@implements_specification('3.5.6', 'tosca-simple-1.0')
 class ArtifactAssignment(ExtensiblePresentation):
     """
     An artifact definition defines a named, typed file that can be associated with Node Type or Node

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/60ea3ebb/extensions/aria_extension_tosca/simple_v1_0/data_types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/data_types.py b/extensions/aria_extension_tosca/simple_v1_0/data_types.py
index a06834c..c385f78 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/data_types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/data_types.py
@@ -20,7 +20,7 @@ try:
 except ImportError:
     from total_ordering import total_ordering
 
-from aria.parser import dsl_specification
+from aria.parser import implements_specification
 from aria.utils.collections import StrictDict, OrderedDict
 from aria.utils.formatting import safe_repr
 
@@ -51,7 +51,7 @@ class Timezone(tzinfo):
 UTC = Timezone()
 
 @total_ordering
-@dsl_specification('timestamp', 'yaml-1.1')
+@implements_specification('timestamp', 'yaml-1.1')
 class Timestamp(object):
     '''
     TOSCA timestamps follow the YAML specification, which in turn is a variant of ISO8601.
@@ -146,7 +146,7 @@ class Timestamp(object):
         return '{0:g}'.format(the_datetime.microsecond / 1000000.0).lstrip('0')
 
 @total_ordering
-@dsl_specification('3.2.2', 'tosca-simple-1.0')
+@implements_specification('3.2.2', 'tosca-simple-1.0')
 class Version(object):
     """
     TOSCA supports the concept of "reuse" of type definitions, as well as template definitions which
@@ -229,7 +229,7 @@ class Version(object):
                             return True
         return False
 
-@dsl_specification('3.2.3', 'tosca-simple-1.0')
+@implements_specification('3.2.3', 'tosca-simple-1.0')
 class Range(object):
     """
     The range type can be used to define numeric ranges with a lower and upper boundary. For
@@ -276,7 +276,7 @@ class Range(object):
     def as_raw(self):
         return list(self.value)
 
-@dsl_specification('3.2.4', 'tosca-simple-1.0')
+@implements_specification('3.2.4', 'tosca-simple-1.0')
 class List(list):
     """
     The list type allows for specifying multiple values for a parameter of property. For example, if
@@ -309,7 +309,7 @@ class List(list):
     def as_raw(self):
         return list(self)
 
-@dsl_specification('3.2.5', 'tosca-simple-1.0')
+@implements_specification('3.2.5', 'tosca-simple-1.0')
 class Map(StrictDict):
     """
     The map type allows for specifying multiple values for a parameter of property as a map. In
@@ -349,7 +349,7 @@ class Map(StrictDict):
         return OrderedDict(self)
 
 @total_ordering
-@dsl_specification('3.2.6', 'tosca-simple-1.0')
+@implements_specification('3.2.6', 'tosca-simple-1.0')
 class Scalar(object):
     """
     The scalar-unit type can be used to define scalar values along with a unit from the list of
@@ -416,7 +416,7 @@ class Scalar(object):
             value = self.TYPE(scalar) # pylint: disable=no-member
         return self.value < value
 
-@dsl_specification('3.2.6.4', 'tosca-simple-1.0')
+@implements_specification('3.2.6.4', 'tosca-simple-1.0')
 class ScalarSize(Scalar):
     """
     Integer scalar for counting bytes.
@@ -444,7 +444,7 @@ class ScalarSize(Scalar):
     TYPE = int
     UNIT = 'bytes'
 
-@dsl_specification('3.2.6.5', 'tosca-simple-1.0')
+@implements_specification('3.2.6.5', 'tosca-simple-1.0')
 class ScalarTime(Scalar):
     """
     Floating point scalar for counting seconds.
@@ -469,7 +469,7 @@ class ScalarTime(Scalar):
     TYPE = float
     UNIT = 'seconds'
 
-@dsl_specification('3.2.6.6', 'tosca-simple-1.0')
+@implements_specification('3.2.6.6', 'tosca-simple-1.0')
 class ScalarFrequency(Scalar):
     """
     Floating point scalar for counting cycles per second (Hz).



Mime
View raw message