ariatosca-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mxm...@apache.org
Subject [2/2] incubator-ariatosca git commit: removed all unnecessary method from models into the topology package
Date Tue, 25 Jul 2017 12:34:48 GMT
removed all unnecessary method from models into the topology package


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

Branch: refs/heads/ARIA-174-Refactor-instantiation-phase
Commit: 4ae0e5f99549655a074ef3a5653180339655a921
Parents: a964076
Author: max-orlov <maxim@gigaspaces.com>
Authored: Tue Jul 25 15:34:41 2017 +0300
Committer: max-orlov <maxim@gigaspaces.com>
Committed: Tue Jul 25 15:34:41 2017 +0300

----------------------------------------------------------------------
 aria/modeling/service_instance.py               | 247 +-------
 aria/modeling/service_template.py               | 135 +----
 .../execution_plugin/instantiation.py           |   3 -
 aria/orchestrator/topology/__init__.py          | 152 +++--
 aria/orchestrator/topology/common.py            |   7 +-
 aria/orchestrator/topology/instance.py          | 593 +++++++++++++------
 aria/orchestrator/topology/template.py          | 590 +++++++++---------
 aria/parser/consumption/modeling.py             |  10 +-
 8 files changed, 866 insertions(+), 871 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4ae0e5f9/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 15cf8fd..8bd3b9e 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -32,16 +32,13 @@ from sqlalchemy.ext.orderinglist import ordering_list
 
 from . import (
     relationship,
-    utils,
     types as modeling_types
 )
 from .mixins import InstanceModelMixin
-from ..orchestrator import execution_plugin
-from ..parser import validation
+
 from ..utils import (
     collections,
     formatting,
-    console
 )
 
 
@@ -231,50 +228,6 @@ class ServiceBase(InstanceModelMixin):
     :type: :class:`~datetime.datetime`
     """)
 
-    def satisfy_requirements(self):
-        satisfied = True
-        for node in self.nodes.itervalues():
-            if not node.satisfy_requirements():
-                satisfied = False
-        return satisfied
-
-    def validate_capabilities(self):
-        satisfied = True
-        for node in self.nodes.itervalues():
-            if not node.validate_capabilities():
-                satisfied = False
-        return satisfied
-
-    def find_hosts(self):
-        for node in self.nodes.itervalues():
-            node.find_host()
-
-    def configure_operations(self):
-        for node in self.nodes.itervalues():
-            node.configure_operations()
-        for group in self.groups.itervalues():
-            group.configure_operations()
-        for operation in self.workflows.itervalues():
-            operation.configure()
-
-    def is_node_a_target(self, target_node):
-        for node in self.nodes.itervalues():
-            if self._is_node_a_target(node, target_node):
-                return True
-        return False
-
-    def _is_node_a_target(self, source_node, target_node):
-        if source_node.outbound_relationships:
-            for relationship_model in source_node.outbound_relationships:
-                if relationship_model.target_node.name == target_node.name:
-                    return True
-                else:
-                    node = relationship_model.target_node
-                    if node is not None:
-                        if self._is_node_a_target(node, target_node):
-                            return True
-        return False
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -288,33 +241,6 @@ class ServiceBase(InstanceModelMixin):
             ('outputs', formatting.as_raw_dict(self.outputs)),
             ('workflows', formatting.as_raw_list(self.workflows))))
 
-    def dump_graph(self):
-        for node in self.nodes.itervalues():
-            if not self.is_node_a_target(node):
-                self._dump_graph_node(node)
-
-    def _dump_graph_node(self, node, capability=None):
-        from ..parser.consumption import ConsumptionContext
-
-        context = ConsumptionContext.get_thread_local()
-        console.puts(context.style.node(node.name))
-        if capability is not None:
-            console.puts('{0} ({1})'.format(context.style.property(capability.name),
-                                            context.style.type(capability.type.name)))
-        if node.outbound_relationships:
-            with context.style.indent:
-                for relationship_model in node.outbound_relationships:
-                    relationship_name = context.style.property(relationship_model.name)
-                    if relationship_model.type is not None:
-                        console.puts('-> {0} ({1})'.format(relationship_name,
-                                                           context.style.type(
-                                                               relationship_model.type.name)))
-                    else:
-                        console.puts('-> {0}'.format(relationship_name))
-                    with console.indent(3):
-                        self._dump_graph_node(relationship_model.target_node,
-                                              relationship_model.target_capability)
-
 
 class NodeBase(InstanceModelMixin):
     """
@@ -578,123 +504,6 @@ class NodeBase(InstanceModelMixin):
             return attribute.value if attribute else None
         return None
 
-    def satisfy_requirements(self):
-        node_template = self.node_template
-        satisfied = True
-        for requirement_template in node_template.requirement_templates:
-            # Find target template
-            target_node_template, target_node_capability = \
-                requirement_template.find_target(node_template)
-            if target_node_template is not None:
-                satisfied = self._satisfy_capability(target_node_capability,
-                                                     target_node_template,
-                                                     requirement_template)
-            else:
-                # TODO: fix
-
-                # context = ConsumptionContext.get_thread_local()
-                # context.validation.report('requirement "{0}" of node "{1}" has no target node '
-                #                           'template'.format(requirement_template.name, self.name),
-                #                           level=validation.Issue.BETWEEN_INSTANCES)
-                satisfied = False
-        return satisfied
-
-    def _satisfy_capability(self, target_node_capability, target_node_template,
-                            requirement_template):
-        from . import models
-        # TODO: fix reporting
-        # context = ConsumptionContext.get_thread_local()
-        # Find target nodes
-        target_nodes = target_node_template.nodes
-        if target_nodes:
-            target_node = None
-            target_capability = None
-
-            if target_node_capability is not None:
-                # Relate to the first target node that has capacity
-                for node in target_nodes:
-                    a_target_capability = node.capabilities.get(target_node_capability.name)
-                    if a_target_capability.relate():
-                        target_node = node
-                        target_capability = a_target_capability
-                        break
-            else:
-                # Use first target node
-                target_node = target_nodes[0]
-
-            if target_node is not None:
-                if requirement_template.relationship_template is not None:
-                    from aria.orchestrator import topology
-                    relationship_model = topology.handler.instantiate(
-                        requirement_template.relationship_template)
-                else:
-                    relationship_model = models.Relationship()
-                relationship_model.name = requirement_template.name
-                relationship_model.requirement_template = requirement_template
-                relationship_model.target_node = target_node
-                relationship_model.target_capability = target_capability
-                self.outbound_relationships.append(relationship_model)
-                return True
-            else:
-                # context.validation.report('requirement "{0}" of node "{1}" targets node '
-                #                           'template "{2}" but its instantiated nodes do not '
-                #                           'have enough capacity'.format(
-                #                               requirement_template.name,
-                #                               self.name,
-                #                               target_node_template.name),
-                #                           level=validation.Issue.BETWEEN_INSTANCES)
-                return False
-        else:
-            # context.validation.report('requirement "{0}" of node "{1}" targets node template '
-            #                           '"{2}" but it has no instantiated nodes'.format(
-            #                               requirement_template.name,
-            #                               self.name,
-            #                               target_node_template.name),
-            #                           level=validation.Issue.BETWEEN_INSTANCES)
-            return False
-
-    def validate_capabilities(self):
-        # TODO: fix
-        # context = ConsumptionContext.get_thread_local()
-        satisfied = False
-        for capability in self.capabilities.itervalues():
-            if not capability.has_enough_relationships:
-                # context.validation.report('capability "{0}" of node "{1}" requires at least {2:d} '
-                #                           'relationships but has {3:d}'.format(
-                #                               capability.name,
-                #                               self.name,
-                #                               capability.min_occurrences,
-                #                               capability.occurrences),
-                #                           level=validation.Issue.BETWEEN_INSTANCES)
-                satisfied = False
-        return satisfied
-
-    def find_host(self):
-        def _find_host(node):
-            if node.type.role == 'host':
-                return node
-            for the_relationship in node.outbound_relationships:
-                if (the_relationship.target_capability is not None) and \
-                    the_relationship.target_capability.type.role == 'host':
-                    host = _find_host(the_relationship.target_node)
-                    if host is not None:
-                        return host
-            for the_relationship in node.inbound_relationships:
-                if (the_relationship.target_capability is not None) and \
-                    the_relationship.target_capability.type.role == 'feature':
-                    host = _find_host(the_relationship.source_node)
-                    if host is not None:
-                        return host
-            return None
-
-        self.host = _find_host(self)
-
-    def configure_operations(self):
-        for interface in self.interfaces.itervalues():
-            interface.configure_operations()
-        for the_relationship in self.outbound_relationships:
-            the_relationship.configure_operations()
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -812,10 +621,6 @@ class GroupBase(InstanceModelMixin):
     :type: :obj:`basestring`
     """)
 
-    def configure_operations(self):
-        for interface in self.interfaces.itervalues():
-            interface.configure_operations()
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1281,10 +1086,6 @@ class RelationshipBase(InstanceModelMixin):
     :type: :obj:`int`
     """)
 
-    def configure_operations(self):
-        for interface in self.interfaces.itervalues():
-            interface.configure_operations()
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1537,10 +1338,6 @@ class InterfaceBase(InstanceModelMixin):
     :type: :obj:`basestring`
     """)
 
-    def configure_operations(self):
-        for operation in self.operations.itervalues():
-            operation.configure()
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1725,47 +1522,6 @@ class OperationBase(InstanceModelMixin):
     :type: :obj:`float`
     """)
 
-    def configure(self):
-        from aria.orchestrator import topology
-        if (self.implementation is None) and (self.function is None):
-            return
-
-        if (self.interface is not None) and (self.plugin is None) and (self.function is None):
-            # ("interface" is None for workflow operations, which do not currently use "plugin")
-            # The default (None) plugin is the execution plugin
-            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 create specially derived arguments. For
-            # now, we just send all configuration parameters as arguments without validation.
-            for key, conf in self.configurations.items():
-                self.arguments[key] = topology.handler.instantiate(conf.as_argument())
-
-        if self.interface is not None:
-            # Send all interface inputs as extra arguments
-            # ("interface" is None for workflow operations)
-            # Note that they will override existing arguments of the same names
-            for key, input in self.interface.inputs.items():
-                self.arguments[key] = topology.handler.instantiate(input.as_argument())
-
-        # Send all inputs as extra arguments
-        # Note that they will override existing arguments of the same names
-        for key, input in self.inputs.items():
-            self.arguments[key] = topology.handler.instantiate(input.as_argument())
-
-        # Check for reserved arguments
-        from ..orchestrator.decorators import OPERATION_DECORATOR_RESERVED_ARGUMENTS
-        used_reserved_names = \
-            OPERATION_DECORATOR_RESERVED_ARGUMENTS.intersection(self.arguments.keys())
-        # if used_reserved_names:
-        #     # context = ConsumptionContext.get_thread_local()
-        #     context.validation.report('using reserved arguments in operation "{0}": {1}'
-        #                               .format(
-        #                                   self.name,
-        #                                   formatting.string_list_as_string(used_reserved_names)),
-        #                               level=validation.Issue.EXTERNAL)
-
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1776,7 +1532,6 @@ class OperationBase(InstanceModelMixin):
             ('inputs', formatting.as_raw_dict(self.inputs))))
 
 
-
 class ArtifactBase(InstanceModelMixin):
     """
     Typed file, either provided in a CSAR or downloaded from a repository.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4ae0e5f9/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 80a5dbb..f2e1e78 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -31,11 +31,10 @@ from sqlalchemy import (
 )
 from sqlalchemy.ext.declarative import declared_attr
 
-from ..utils import (collections, formatting, console)
+from ..utils import (collections, formatting)
 from .mixins import TemplateModelMixin
 from . import (
     relationship,
-    utils,
     types as modeling_types
 )
 
@@ -495,63 +494,6 @@ class NodeTemplateBase(TemplateModelMixin):
             ('capability_templates', formatting.as_raw_list(self.capability_templates)),
             ('requirement_templates', formatting.as_raw_list(self.requirement_templates))))
 
-    @property
-    def scaling(self):
-        scaling = {}
-
-        def extract_property(properties, name):
-            if name in scaling:
-                return
-            prop = properties.get(name)
-            if (prop is not None) and (prop.type_name == 'integer') and (prop.value is not None):
-                scaling[name] = prop.value
-
-        def extract_properties(properties):
-            extract_property(properties, 'min_instances')
-            extract_property(properties, 'max_instances')
-            extract_property(properties, 'default_instances')
-
-        def default_property(name, value):
-            if name not in scaling:
-                scaling[name] = value
-
-        # From our scaling capabilities
-        for capability_template in self.capability_templates.itervalues():
-            if capability_template.type.role == 'scaling':
-                extract_properties(capability_template.properties)
-
-        # From service scaling policies
-        for policy_template in self.service_template.policy_templates.itervalues():
-            if policy_template.type.role == 'scaling':
-                if policy_template.is_for_node_template(self.name):
-                    extract_properties(policy_template.properties)
-
-        # Defaults
-        default_property('min_instances', 0)
-        default_property('max_instances', 1)
-        default_property('default_instances', 1)
-
-        # Validate
-        # pylint: disable=too-many-boolean-expressions
-        if ((scaling['min_instances'] < 0) or
-                (scaling['max_instances'] < 0) or
-                (scaling['default_instances'] < 0) or
-                (scaling['max_instances'] < scaling['min_instances']) or
-                (scaling['default_instances'] < scaling['min_instances']) or
-                (scaling['default_instances'] > scaling['max_instances'])):
-            pass
-            # TODO: fix this
-            # context = ConsumptionContext.get_thread_local()
-            # context.validation.report('invalid scaling parameters for node template "{0}": '
-                                      # 'min={1}, max={2}, default={3}'.format(
-                                      #     self.name,
-                                      #     scaling['min_instances'],
-                                      #     scaling['max_instances'],
-                                      #     scaling['default_instances']),
-                                      # level=validation.Issue.BETWEEN_TYPES)
-
-        return scaling
-
     def is_target_node_template_valid(self, target_node_template):
         """
         Checks if ``target_node_template`` matches all our ``target_node_template_constraints``.
@@ -1100,58 +1042,6 @@ class RequirementTemplateBase(TemplateModelMixin):
     :type: [:class:`NodeTemplateConstraint`]
     """)
 
-    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_template_valid(self.target_node_template):
-                # TODO: fix
-                pass
-                # 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,
-                                          #     source_node_template.name),
-                                          # level=validation.Issue.BETWEEN_TYPES)
-            if (self.target_capability_type is not None) \
-                or (self.target_capability_name is not None):
-                target_node_capability = self.find_target_capability(source_node_template,
-                                                                     self.target_node_template)
-                if target_node_capability is None:
-                    return None, None
-            else:
-                target_node_capability = None
-
-            return self.target_node_template, target_node_capability
-
-        # Find first node that matches the type
-        elif self.target_node_type is not None:
-            for target_node_template in \
-                    self.node_template.service_template.node_templates.itervalues():
-                if self.target_node_type.get_descendant(target_node_template.type.name) is None:
-                    continue
-
-                if not source_node_template.is_target_node_template_valid(target_node_template):
-                    continue
-
-                target_node_capability = self.find_target_capability(source_node_template,
-                                                                     target_node_template)
-                if target_node_capability is None:
-                    continue
-
-                return target_node_template, target_node_capability
-
-        return None, None
-
-    def find_target_capability(self, source_node_template, target_node_template):
-        for capability_template in target_node_template.capability_templates.itervalues():
-            if capability_template.satisfies_requirement(source_node_template,
-                                                         self,
-                                                         target_node_template):
-                return capability_template
-        return None
-
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1349,29 +1239,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
     :type: :obj:`int`
     """)
 
-    def satisfies_requirement(self,
-                              source_node_template,
-                              requirement,
-                              target_node_template):
-        # Do we match the required capability type?
-        if requirement.target_capability_type and \
-            requirement.target_capability_type.get_descendant(self.type.name) is None:
-            return False
-
-        # Are we in valid_source_node_types?
-        if self.valid_source_node_types:
-            for valid_source_node_type in self.valid_source_node_types:
-                if valid_source_node_type.get_descendant(source_node_template.type.name) is None:
-                    return False
-
-        # Apply requirement constraints
-        if requirement.target_node_template_constraints:
-            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
-
     @property
     def as_raw(self):
         return collections.OrderedDict((

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4ae0e5f9/aria/orchestrator/execution_plugin/instantiation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/execution_plugin/instantiation.py b/aria/orchestrator/execution_plugin/instantiation.py
index 4390252..0e3a441 100644
--- a/aria/orchestrator/execution_plugin/instantiation.py
+++ b/aria/orchestrator/execution_plugin/instantiation.py
@@ -19,10 +19,7 @@ Instantiation of :class:`~aria.modeling.models.Operation` models.
 
 # TODO: this module will eventually be moved to a new "aria.instantiation" package
 
-from ...utils.type import full_type_name
-from ...utils.formatting import safe_repr
 from ...utils.collections import OrderedDict
-from ...parser import validation
 from ...modeling.functions import Function
 
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4ae0e5f9/aria/orchestrator/topology/__init__.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/__init__.py b/aria/orchestrator/topology/__init__.py
index aa9e306..9003c1e 100644
--- a/aria/orchestrator/topology/__init__.py
+++ b/aria/orchestrator/topology/__init__.py
@@ -83,63 +83,87 @@ class Handler(object):
             if attribute_name.startswith('_'):
                 continue
             attribute = getattr(module_, attribute_name)
-            if isinstance(attribute, type) and issubclass(attribute, (common._TemplateHandler,
-                                                                      common._InstanceHandler)):
+            if isinstance(attribute, type) and issubclass(attribute, common._Handler):
                 handlers[getattr(models, attribute_name)] = attribute
         return handlers
 
-    def instantiate(self, template, **kwargs):
+    def instantiate(self, model, **kwargs):
         """
         all handlers used by instantiate should hold a tuple as value (handler, instnace_cls)
-        :param template:
+        :param model:
         :param kwargs:
         :return:
         """
-        if isinstance(template, dict):
+        if isinstance(model, dict):
             return dict((name, self.instantiate(value, **kwargs))
-                        for name, value in template.iteritems())
-        elif isinstance(template, list):
-            return list(self.instantiate(value, **kwargs) for value in template)
-        elif template is not None:
-            handler = self._handlers.get(template.__class__)
-            instance_cls = self._init_map.get(template.__class__)
-            return handler(self, template).instantiate(instance_cls, **kwargs)
-
-    def validate(self, template, **kwargs):
-        if isinstance(template, dict):
-            return self.validate(template.values())
-        elif isinstance(template, list):
-            return all(self.validate(value) for value in template)
-        elif template is not None:
-            handler = self._handlers.get(template.__class__)
-            return handler(self, template).validate(**kwargs)
-
-    def dump(self, template, context, **kwargs):
+                        for name, value in model.iteritems())
+        elif isinstance(model, list):
+            return list(self.instantiate(value, **kwargs) for value in model)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            instance_cls = self._init_map.get(model.__class__)
+            return handler(self, model).instantiate(instance_cls, **kwargs)
+
+    def validate(self, model, **kwargs):
+        if isinstance(model, dict):
+            return self.validate(model.values())
+        elif isinstance(model, list):
+            return all(self.validate(value) for value in model)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            return handler(self, model).validate(**kwargs)
+
+    def dump(self, model, context, **kwargs):
         if not isinstance(context, self.TopologyStylizer):
             # Wrap the context to contain a stringIO object
             context = self.TopologyStylizer(context)
 
-        if isinstance(template, dict):
-            return self.dump(template.values(), context, **kwargs)
-        elif isinstance(template, list):
-            context.write('%s:' % template)
+        if isinstance(model, dict):
+            return self.dump(model.values(), context, **kwargs)
+        elif isinstance(model, list):
+            context.write('%s:' % model)
             with context.style.indent:
-                for value in template:
+                for value in model:
                     self.dump(value, context, **kwargs)
-        elif template is not None:
-            handler = self._handlers.get(template.__class__)
-            handler(self, template).dump(context, **kwargs)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            handler(self, model).dump(context, **kwargs)
 
         return str(context)
 
-    def coerce(self, template, **kwargs):
-        if isinstance(template, dict):
-            return self.validate(template.values())
-        elif isinstance(template, list):
-            return all(self.validate(value) for value in template)
-        elif template is not None:
-            handler = self._handlers.get(template.__class__)
-            return handler(self, template).coerce(**kwargs)
+    def dump_graph(self, context, service, **kwargs):
+        context = self.TopologyStylizer(context)
+        for node in service.nodes.itervalues():
+            if not node.inbound_relationships:
+                self._dump_graph_node(context, node)
+
+    def _dump_graph_node(self, context, node, capability=None):
+        context.write(context.style.node(node.name))
+        if capability is not None:
+            context.write('{0} ({1})'.format(context.style.property(capability.name),
+                                             context.style.type(capability.type.name)))
+        if node.outbound_relationships:
+            with context.style.indent:
+                for relationship_model in node.outbound_relationships:
+                    relationship_name = context.style.property(relationship_model.name)
+                    if relationship_model.type is not None:
+                        context.write('-> {0} ({1})'.format(
+                            relationship_name, context.style.type(relationship_model.type.name)))
+                    else:
+                        context.write('-> {0}'.format(relationship_name))
+                    # TODO: this needs to be fixed
+                    # with console.indent(3):
+                    #     self._dump_graph_node(relationship_model.target_node,
+                    #                           relationship_model.target_capability)
+
+    def coerce(self, model, **kwargs):
+        if isinstance(model, dict):
+            return self.validate(model.values())
+        elif isinstance(model, list):
+            return all(self.validate(value) for value in model)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            return handler(self, model).coerce(**kwargs)
 
     def dump_types(self, context, service_template):
         self.dump(service_template.node_types, context)
@@ -150,5 +174,55 @@ class Handler(object):
         self.dump(service_template.artifact_types, context)
         self.dump(service_template.interface_types, context)
 
+    def satisfy_requirements(self, model, **kwargs):
+        if isinstance(model, dict):
+            return self.satisfy_requirements(model.values())
+        elif isinstance(model, list):
+            return all(self.satisfy_requirements(value) for value in model)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            return handler(self, model).satisfy_requirements(**kwargs)
+
+    def validate_capabilities(self, model, **kwargs):
+        if isinstance(model, dict):
+            return self.validate_capabilities(model.values())
+        elif isinstance(model, list):
+            return all(self.validate_capabilities(value) for value in model)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            return handler(self, model).validate_capabilities(**kwargs)
+
+    def _find_host(self, node):
+        if node.type.role == 'host':
+            return node
+
+        has_role = lambda rel, role: \
+            rel.target_capability is not None and rel.target_capability.type.role == role
+
+        for relationship in node.outbound_relationships:
+            if has_role(relationship, 'host'):
+                host = self._find_host(relationship.target_node)
+                if host is not None:
+                    return host
+        for relationship in node.inbound_relationships:
+            if has_role(relationship, 'feature'):
+                host = self._find_host(relationship.source_node)
+                if host is not None:
+                    return host
+        return None
+
+    def find_hosts(self, service):
+        for node in service.nodes.values():
+            service.host = self._find_host(node)
+
+    def configure_operations(self, model, **kwargs):
+        if isinstance(model, dict):
+            return self.configure_operations(model.values())
+        elif isinstance(model, list):
+            return all(self.configure_operations(value) for value in model)
+        elif model is not None:
+            handler = self._handlers.get(model.__class__)
+            return handler(self, model).configure_operations(**kwargs)
+
 
 handler = Handler()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4ae0e5f9/aria/orchestrator/topology/common.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/common.py b/aria/orchestrator/topology/common.py
index 9b00ce6..9437d56 100644
--- a/aria/orchestrator/topology/common.py
+++ b/aria/orchestrator/topology/common.py
@@ -17,7 +17,7 @@
 class _Handler(object):
     def __init__(self, topology, template):
         self._topology = topology
-        self._template = template
+        self._model = template
 
     def _coerce(self, *templates, **kwargs):
         for template in templates:
@@ -48,3 +48,8 @@ class _TemplateHandler(_Handler):
 
 class _InstanceHandler(_Handler):
     pass
+
+
+class _OperatorHolderHandler(_Handler):
+    def configure_operations(self):
+        raise NotImplementedError

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4ae0e5f9/aria/orchestrator/topology/instance.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/topology/instance.py b/aria/orchestrator/topology/instance.py
index cb3f747..3040b3b 100644
--- a/aria/orchestrator/topology/instance.py
+++ b/aria/orchestrator/topology/instance.py
@@ -13,6 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from ... modeling import models
+from .. import execution_plugin
+from .. import decorators
 from . import common
 
 # TODO: this should this be here?
@@ -22,101 +25,109 @@ from aria.utils import formatting
 class Artifact(common._InstanceHandler):
 
     def coerce(self, **kwargs):
-        self._topology.coerce(self._template.properties, **kwargs)
+        self._topology.coerce(self._model.properties, **kwargs)
 
     def validate(self, **kwargs):
-        self._topology.validate(self._template.properties)
+        self._topology.validate(self._model.properties)
 
     def dump(self, context):
-        context.write(context.style.node(self._template.name))
-        if self._template.description:
-            context.write(context.style.meta(self._template.description))
+        context.write(context.style.node(self._model.name))
+        if self._model.description:
+            context.write(context.style.meta(self._model.description))
         with context.style.indent:
-            context.write('Artifact type: {0}'.format(context.style.type(self._template.type.name)))
+            context.write('Artifact type: {0}'.format(context.style.type(self._model.type.name)))
             context.write('Source path: {0}'.format(
-                context.style.literal(self._template.source_path)))
-            if self._template.target_path is not None:
+                context.style.literal(self._model.source_path)))
+            if self._model.target_path is not None:
                 context.write('Target path: {0}'.format(
-                    context.style.literal(self._template.target_path)))
-            if self._template.repository_url is not None:
+                    context.style.literal(self._model.target_path)))
+            if self._model.repository_url is not None:
                 context.write('Repository URL: {0}'.format(
-                    context.style.literal(self._template.repository_url)))
-            if self._template.repository_credential:
+                    context.style.literal(self._model.repository_url)))
+            if self._model.repository_credential:
                 context.write('Repository credential: {0}'.format(
-                    context.style.literal(self._template.repository_credential)))
-            self._topology.dump(self._template.properties, context, 'Properties')
+                    context.style.literal(self._model.repository_credential)))
+            self._topology.dump(self._model.properties, context, 'Properties')
             
 
 class Capability(common._InstanceHandler):
     def coerce(self, **kwargs):
-        self._topology.coerce(self._template.properties, **kwargs)
+        self._topology.coerce(self._model.properties, **kwargs)
 
     def validate(self, **kwargs):
-        self._topology.validate(self._template.properties)
+        self._topology.validate(self._model.properties)
 
     def dump(self, context):
-        context.write(context.style.node(self._template.name))
+        context.write(context.style.node(self._model.name))
         with context.style.indent:
-            context.write('Type: {0}'.format(context.style.type(self._template.type.name)))
+            context.write('Type: {0}'.format(context.style.type(self._model.type.name)))
             context.write('Occurrences: {0:d} ({1:d}{2})'.format(
-                self._template.occurrences,
-                self._template.min_occurrences or 0,
-                ' to {0:d}'.format(self._template.max_occurrences)
-                if self._template.max_occurrences is not None
+                self._model.occurrences,
+                self._model.min_occurrences or 0,
+                ' to {0:d}'.format(self._model.max_occurrences)
+                if self._model.max_occurrences is not None
                 else ' or more'))
-            self._topology.dump(self._template.properties, context, 'Properties')
+            self._topology.dump(self._model.properties, context, 'Properties')
 
 
-class Group(common._InstanceHandler):
+class Group(common._OperatorHolderHandler):
+
     def coerce(self, **kwargs):
-        self._coerce(self._template.properties, self._template.interfaces, **kwargs)
+        self._coerce(self._model.properties, self._model.interfaces, **kwargs)
 
     def validate(self, **kwargs):
-        self._validate(self._template.properties,
-                       self._template.interfaces)
+        self._validate(self._model.properties,
+                       self._model.interfaces)
 
     def dump(self, context):
-        context.write('Group: {0}'.format(context.style.node(self._template.name)))
+        context.write('Group: {0}'.format(context.style.node(self._model.name)))
         with context.style.indent:
-            context.write('Type: {0}'.format(context.style.type(self._template.type.name)))
-            self._topology.dump(self._template.properties, context, 'Properties')
-            self._topology.dump(self._template.interfaces, context, 'Interfaces')
-            if self._template.nodes:
+            context.write('Type: {0}'.format(context.style.type(self._model.type.name)))
+            self._topology.dump(self._model.properties, context, 'Properties')
+            self._topology.dump(self._model.interfaces, context, 'Interfaces')
+            if self._model.nodes:
                 context.write('Member nodes:')
                 with context.style.indent:
-                    for node in self._template.nodes:
+                    for node in self._model.nodes:
                         context.write(context.style.node(node.name))
 
+    def configure_operations(self):
+        for interface in self._model.interfaces.values():
+            self._topology.configure_operations(interface)
+
 
-class Interface(common._InstanceHandler):
+class Interface(common._OperatorHolderHandler):
     def coerce(self, **kwargs):
-        self._coerce(self._template.inputs, self._template.operations, **kwargs)
+        self._coerce(self._model.inputs, self._model.operations, **kwargs)
 
     def validate(self, **kwargs):
-        self._validate(self._template.inputs,
-                       self._template.operations)
+        self._validate(self._model.inputs,
+                       self._model.operations)
 
     def dump(self, context):
-        context.write(context.style.node(self._template.name))
-        if self._template.description:
-            context.write(context.style.meta(self._template.description))
+        context.write(context.style.node(self._model.name))
+        if self._model.description:
+            context.write(context.style.meta(self._model.description))
         with context.style.indent:
-            context.write('Interface type: {0}'.format(context.style.type(self._template.type.name)))
-            self._topology.dump(self._template.inputs, context, 'Inputs')
-            self._topology.dump(self._template.operations, context, 'Operations')
+            context.write('Interface type: {0}'.format(context.style.type(self._model.type.name)))
+            self._topology.dump(self._model.inputs, context, 'Inputs')
+            self._topology.dump(self._model.operations, context, 'Operations')
 
+    def configure_operations(self):
+        for operation in self._model.operations.values():
+            self._topology.configure_operations(operation)
 
-class Node(common._InstanceHandler):
+
+class Node(common._OperatorHolderHandler):
     def coerce(self, **kwargs):
-        self._coerce(self._template.properties,
-                     self._template.attributes,
-                     self._template.interfaces,
-                     self._template.artifacts,
-                     self._template.capabilities,
-                     self._template.outbound_relationships,
+        self._coerce(self._model.properties,
+                     self._model.attributes,
+                     self._model.interfaces,
+                     self._model.artifacts,
+                     self._model.capabilities,
+                     self._model.outbound_relationships,
                      **kwargs)
 
-
     def validate(self, **kwargs):
         # TODO: fix the context
         # context = ConsumptionContext.get_thread_local()
@@ -129,180 +140,407 @@ class Node(common._InstanceHandler):
             #                               len(self.name)),
             #                           level=validation.Issue.BETWEEN_INSTANCES)
 
-        self._validate(self._template.properties,
-                       self._template.attributes,
-                       self._template.interfaces,
-                       self._template.artifacts,
-                       self._template.capabilities,
-                       self._template.outbound_relationships)
+        self._validate(self._model.properties,
+                       self._model.attributes,
+                       self._model.interfaces,
+                       self._model.artifacts,
+                       self._model.capabilities,
+                       self._model.outbound_relationships)
 
     def dump(self, context):
-        context.write('Node: {0}'.format(context.style.node(self._template.name)))
+        context.write('Node: {0}'.format(context.style.node(self._model.name)))
         with context.style.indent:
-            context.write('Type: {0}'.format(context.style.type(self._template.type.name)))
-            context.write('Template: {0}'.format(context.style.node(self._template.node_template.name)))
-            self._topology.dump(self._template.properties, context, 'Properties')
-            self._topology.dump(self._template.attributes, context, 'Attributes')
-            self._topology.dump(self._template.interfaces, context, 'Interfaces')
-            self._topology.dump(self._template.artifacts, context, 'Artifacts')
-            self._topology.dump(self._template.capabilities, context, 'Capabilities')
-            self._topology.dump(self._template.outbound_relationships, context, 'Relationships')
-
-
-class Operation(common._InstanceHandler):
+            context.write('Type: {0}'.format(context.style.type(self._model.type.name)))
+            context.write('Template: {0}'.format(context.style.node(self._model.node_template.name)))
+            self._topology.dump(self._model.properties, context, 'Properties')
+            self._topology.dump(self._model.attributes, context, 'Attributes')
+            self._topology.dump(self._model.interfaces, context, 'Interfaces')
+            self._topology.dump(self._model.artifacts, context, 'Artifacts')
+            self._topology.dump(self._model.capabilities, context, 'Capabilities')
+            self._topology.dump(self._model.outbound_relationships, context, 'Relationships')
+
+    def configure_operations(self):
+        for interface in self._model.interfaces.values():
+            self._topology.configure_operations(interface)
+        for relationship in self._model.outbound_relationships:
+            self._topology.configure_operations(relationship)
+
+    def validate_capabilities(self):
+        # TODO: fix
+        # context = ConsumptionContext.get_thread_local()
+        satisfied = False
+        for capability in self._model.capabilities.itervalues():
+            if not capability.has_enough_relationships:
+                # context.validation.report('capability "{0}" of node "{1}" requires at least {2:d} '
+                #                           'relationships but has {3:d}'.format(
+                #                               capability.name,
+                #                               self.name,
+                #                               capability.min_occurrences,
+                #                               capability.occurrences),
+                #                           level=validation.Issue.BETWEEN_INSTANCES)
+                satisfied = False
+        return satisfied
+
+    def satisfy_requirements(self):
+        satisfied = True
+        for requirement_template in self._model.node_template.requirement_templates:
+            # Find target template
+            target_node_template, target_node_capability = self._find_target(requirement_template)
+            if target_node_template is not None:
+                satisfied = self._satisfy_capability(
+                    target_node_capability, target_node_template,
+                                                     requirement_template)
+            else:
+                # TODO: fix
+
+                # context = ConsumptionContext.get_thread_local()
+                # context.validation.report('requirement "{0}" of node "{1}" has no target node '
+                #                           'template'.format(requirement_template.name, self.name),
+                #                           level=validation.Issue.BETWEEN_INSTANCES)
+                satisfied = False
+        return satisfied
+
+    def _satisfy_capability(self, target_node_capability, target_node_template,
+                            requirement_template):
+        # TODO: fix reporting
+        # context = ConsumptionContext.get_thread_local()
+        # Find target nodes
+        target_nodes = target_node_template.nodes
+        if target_nodes:
+            target_node = None
+            target_capability = None
+
+            if target_node_capability is not None:
+                # Relate to the first target node that has capacity
+                for node in target_nodes:
+                    a_target_capability = node.capabilities.get(target_node_capability.name)
+                    if a_target_capability.relate():
+                        target_node = node
+                        target_capability = a_target_capability
+                        break
+            else:
+                # Use first target node
+                target_node = target_nodes[0]
+
+            if target_node is not None:
+                if requirement_template.relationship_template is not None:
+                    from aria.orchestrator import topology
+                    relationship_model = topology.handler.instantiate(
+                        requirement_template.relationship_template)
+                else:
+                    relationship_model = models.Relationship()
+                relationship_model.name = requirement_template.name
+                relationship_model.requirement_template = requirement_template
+                relationship_model.target_node = target_node
+                relationship_model.target_capability = target_capability
+                self._model.outbound_relationships.append(relationship_model)
+                return True
+            else:
+                # context.validation.report('requirement "{0}" of node "{1}" targets node '
+                #                           'template "{2}" but its instantiated nodes do not '
+                #                           'have enough capacity'.format(
+                #                               requirement_template.name,
+                #                               self.name,
+                #                               target_node_template.name),
+                #                           level=validation.Issue.BETWEEN_INSTANCES)
+                return False
+        else:
+            # context.validation.report('requirement "{0}" of node "{1}" targets node template '
+            #                           '"{2}" but it has no instantiated nodes'.format(
+            #                               requirement_template.name,
+            #                               self.name,
+            #                               target_node_template.name),
+            #                           level=validation.Issue.BETWEEN_INSTANCES)
+            return False
+
+    def _find_target(self, requirement_template):
+        # We might already have a specific node template, so we'll just verify it
+        if requirement_template.target_node_template is not None:
+            if not self._model.node_template.is_target_node_template_valid(requirement_template.target_node_template):
+                # TODO: fix
+                pass
+                # 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,
+                                          #     source_node_template.name),
+                                          # level=validation.Issue.BETWEEN_TYPES)
+            if (requirement_template.target_capability_type is not None or
+                requirement_template.target_capability_name is not None):
+                target_node_capability = self._get_capability_from_requirement(requirement_template)
+                if target_node_capability is None:
+                    return None, None
+            else:
+                target_node_capability = None
+
+            return self._model.node_template.target_node_template, target_node_capability
+
+        # Find first node that matches the type
+        elif requirement_template.target_node_type is not None:
+            for target_node_template in \
+                    self._model.node_template.service_template.node_templates.itervalues():
+                if requirement_template.target_node_type.get_descendant(target_node_template.type.name) is None:
+                    continue
+
+                if not self._model.node_template.is_target_node_template_valid(target_node_template):
+                    continue
+
+                if requirement_template.target_node_template:
+                    target_node_capability = self._get_capability_from_requirement(requirement_template)
+                    if target_node_capability is None:
+                        continue
+                    else:
+                        return target_node_template, target_node_capability
+
+        return None, None
+
+    def _get_capability_from_requirement(self, requirement_template):
+        for capability_template in requirement_template.target_node_template.capability_templates.values():
+            if self._satisfies_requirement(capability_template, requirement_template):
+                return capability_template
+        return None
+
+    def _satisfies_requirement(self, capability_template, requirement_template):
+        # Do we match the required capability type?
+        if (requirement_template.target_capability_type and
+            requirement_template.target_capability_type.get_descendant(
+                self._model.type.name) is None):
+            return False
+
+        # Are we in valid_source_node_types?
+        if capability_template.valid_source_node_types:
+            for valid_source_node_type in capability_template.valid_source_node_types:
+                if valid_source_node_type.get_descendant(
+                        self._model.node_template.type.name) is None:
+                    return False
+
+        # Apply requirement constraints
+        if requirement_template.target_node_template_constraints:
+            for node_template_constraint in requirement_template.target_node_template_constraints:
+                if not node_template_constraint.matches(
+                        self._model.node_template, requirement_template.target_node_template):
+                    return False
+
+        return True
+
+
+class Operation(common._OperatorHolderHandler):
     def coerce(self, **kwargs):
-        self._coerce(self._template.inputs,
-                     self._template.configurations,
-                     self._template.arguments,
+        self._coerce(self._model.inputs,
+                     self._model.configurations,
+                     self._model.arguments,
                      **kwargs)
 
     def validate(self, **kwargs):
-        self._validate(self._template.inputs,
-                       self._template.configurations,
-                       self._template.arguments)
+        self._validate(self._model.inputs,
+                       self._model.configurations,
+                       self._model.arguments)
 
     def dump(self, context):
-        context.write(context.style.node(self._template.name))
-        if self._template.description:
-            context.write(context.style.meta(self._template.description))
+        context.write(context.style.node(self._model.name))
+        if self._model.description:
+            context.write(context.style.meta(self._model.description))
         with context.style.indent:
-            if self._template.implementation is not None:
+            if self._model.implementation is not None:
                 context.write('Implementation: {0}'.format(
-                    context.style.literal(self._template.implementation)))
-            if self._template.dependencies:
+                    context.style.literal(self._model.implementation)))
+            if self._model.dependencies:
                 context.write(
                     'Dependencies: {0}'.format(
-                        ', '.join((str(context.style.literal(v)) for v in self._template.dependencies))))
-            self._topology.dump(self._template.inputs, context, 'Inputs')
-            if self._template.executor is not None:
-                context.write('Executor: {0}'.format(context.style.literal(self._template.executor)))
-            if self._template.max_attempts is not None:
-                context.write('Max attempts: {0}'.format(context.style.literal(self._template.max_attempts)))
-            if self._template.retry_interval is not None:
+                        ', '.join((str(context.style.literal(v)) for v in self._model.dependencies))))
+            self._topology.dump(self._model.inputs, context, 'Inputs')
+            if self._model.executor is not None:
+                context.write('Executor: {0}'.format(context.style.literal(self._model.executor)))
+            if self._model.max_attempts is not None:
+                context.write('Max attempts: {0}'.format(context.style.literal(self._model.max_attempts)))
+            if self._model.retry_interval is not None:
                 context.write('Retry interval: {0}'.format(
-                    context.style.literal(self._template.retry_interval)))
-            if self._template.plugin is not None:
+                    context.style.literal(self._model.retry_interval)))
+            if self._model.plugin is not None:
                 context.write('Plugin: {0}'.format(
-                    context.style.literal(self._template.plugin.name)))
-            self._topology.dump(self._template.configurations, context, 'Configuration')
-            if self._template.function is not None:
-                context.write('Function: {0}'.format(context.style.literal(self._template.function)))
-            self._topology.dump(self._template.arguments, context, 'Arguments')
+                    context.style.literal(self._model.plugin.name)))
+            self._topology.dump(self._model.configurations, context, 'Configuration')
+            if self._model.function is not None:
+                context.write('Function: {0}'.format(context.style.literal(self._model.function)))
+            self._topology.dump(self._model.arguments, context, 'Arguments')
+
+    def configure_operations(self):
+        if self._model.implementation is None and self._model.function is None:
+            return
+
+        if (self._model.interface is not None and
+            self._model.plugin is None and
+            self._model.function is None):
+            # ("interface" is None for workflow operations, which do not currently use "plugin")
+            # The default (None) plugin is the execution plugin
+            execution_plugin.instantiation.configure_operation(self._model)
+        else:
+            # In the future plugins may be able to add their own "configure_operation" hook that
+            # can validate the configuration and otherwise create specially derived arguments. For
+            # now, we just send all configuration parameters as arguments without validation.
+            for key, conf in self._model.configurations.items():
+                self._model.arguments[key] = self._topology.instantiate(conf.as_argument())
+
+        if self._model.interface is not None:
+            # Send all interface inputs as extra arguments
+            # ("interface" is None for workflow operations)
+            # Note that they will override existing arguments of the same names
+            for key, input in self._model.interface.inputs.items():
+                self._model.arguments[key] = self._topology.instantiate(input.as_argument())
+
+        # Send all inputs as extra arguments
+        # Note that they will override existing arguments of the same names
+        for key, input in self._model.inputs.items():
+            self._model.arguments[key] = self._topology.instantiate(input.as_argument())
+
+        # Check for reserved arguments
+        used_reserved_names = decorators.OPERATION_DECORATOR_RESERVED_ARGUMENTS.intersection(
+            self._model.arguments.keys())
+        # if used_reserved_names:
+        #     # context = ConsumptionContext.get_thread_local()
+        #     context.validation.report('using reserved arguments in operation "{0}": {1}'
+        #                               .format(
+        #                                   self.name,
+        #                                   formatting.string_list_as_string(used_reserved_names)),
+        #                               level=validation.Issue.EXTERNAL)
 
 
 class Policy(common._InstanceHandler):
     def coerce(self, **kwargs):
-        self._topology.coerce(self._template.properties, **kwargs)
+        self._topology.coerce(self._model.properties, **kwargs)
 
     def validate(self, **kwargs):
-        self._topology.validate(self._template.properties)
+        self._topology.validate(self._model.properties)
 
     def dump(self, context):
-        context.write('Policy: {0}'.format(context.style.node(self._template.name)))
+        context.write('Policy: {0}'.format(context.style.node(self._model.name)))
         with context.style.indent:
-            context.write('Type: {0}'.format(context.style.type(self._template.type.name)))
-            self._topology.dump(self._template.properties, context, 'Properties')
-            if self._template.nodes:
+            context.write('Type: {0}'.format(context.style.type(self._model.type.name)))
+            self._topology.dump(self._model.properties, context, 'Properties')
+            if self._model.nodes:
                 context.write('Target nodes:')
                 with context.style.indent:
-                    for node in self._template.nodes:
+                    for node in self._model.nodes:
                         context.write(context.style.node(node.name))
-            if self._template.groups:
+            if self._model.groups:
                 context.write('Target groups:')
                 with context.style.indent:
-                    for group in self._template.groups:
+                    for group in self._model.groups:
                         context.write(context.style.node(group.name))
 
 
-class Relationship(common._InstanceHandler):
+class Relationship(common._OperatorHolderHandler):
     def coerce(self, **kwargs):
-        self._coerce(self._template.properties,
-                     self._template.interfaces,
+        self._coerce(self._model.properties,
+                     self._model.interfaces,
                      **kwargs)
 
     def validate(self, **kwargs):
-        self._validate(self._template.properties,
-                       self._template.interfaces)
+        self._validate(self._model.properties,
+                       self._model.interfaces)
 
     def dump(self, context):
-        if self._template.name:
-            context.write('{0} ->'.format(context.style.node(self._template.name)))
+        if self._model.name:
+            context.write('{0} ->'.format(context.style.node(self._model.name)))
         else:
             context.write('->')
         with context.style.indent:
-            context.write('Node: {0}'.format(context.style.node(self._template.target_node.name)))
-            if self._template.target_capability:
+            context.write('Node: {0}'.format(context.style.node(self._model.target_node.name)))
+            if self._model.target_capability:
                 context.write('Capability: {0}'.format(context.style.node(
-                    self._template.target_capability.name)))
-            if self._template.type is not None:
+                    self._model.target_capability.name)))
+            if self._model.type is not None:
                 context.write('Relationship type: {0}'.format(
-                    context.style.type(self._template.type.name)))
-            if (self._template.relationship_template is not None and
-                self._template.relationship_template.name):
+                    context.style.type(self._model.type.name)))
+            if (self._model.relationship_template is not None and
+                self._model.relationship_template.name):
                 context.write('Relationship template: {0}'.format(
-                    context.style.node(self._template.relationship_template.name)))
-            self._topology.dump(self._template.properties, context, 'Properties')
-            self._topology.dump(self._template.interfaces, context, 'Interfaces')
+                    context.style.node(self._model.relationship_template.name)))
+            self._topology.dump(self._model.properties, context, 'Properties')
+            self._topology.dump(self._model.interfaces, context, 'Interfaces')
+
+    def configure_operations(self):
+        for interface in self._model.interfaces.values():
+            self._topology.configure_operations(interface)
 
 
-class Service(common._InstanceHandler):
+class Service(common._OperatorHolderHandler):
     def coerce(self, **kwargs):
-        self._coerce(self._template.meta_data,
-                     self._template.nodes,
-                     self._template.groups,
-                     self._template.policies,
-                     self._template.substitution,
-                     self._template.inputs,
-                     self._template.outputs,
-                     self._template.workflows,
+        self._coerce(self._model.meta_data,
+                     self._model.nodes,
+                     self._model.groups,
+                     self._model.policies,
+                     self._model.substitution,
+                     self._model.inputs,
+                     self._model.outputs,
+                     self._model.workflows,
                      **kwargs)
 
     def validate(self, **kwargs):
-        self._validate(self._template.meta_data,
-                       self._template.nodes,
-                       self._template.groups,
-                       self._template.policies,
-                       self._template.substitution,
-                       self._template.inputs,
-                       self._template.outputs,
-                       self._template.workflows)
+        self._validate(self._model.meta_data,
+                       self._model.nodes,
+                       self._model.groups,
+                       self._model.policies,
+                       self._model.substitution,
+                       self._model.inputs,
+                       self._model.outputs,
+                       self._model.workflows)
 
     def dump(self, context):
-        if self._template.description is not None:
-            context.write(context.style.meta(self._template.description))
-        self._topology.dump(self._template.meta_data, context, 'Metadata')
-        for node in self._template.nodes.itervalues():
+        if self._model.description is not None:
+            context.write(context.style.meta(self._model.description))
+        self._topology.dump(self._model.meta_data, context, 'Metadata')
+        for node in self._model.nodes.itervalues():
             node.dump()
-        for group in self._template.groups.itervalues():
+        for group in self._model.groups.itervalues():
             group.dump()
-        for policy in self._template.policies.itervalues():
+        for policy in self._model.policies.itervalues():
             policy.dump()
-        if self._template.substitution is not None:
-            self._template.substitution.dump()
-        self._topology.dump(self._template.inputs, context, 'Inputs')
-        self._topology.dump(self._template.outputs, context, 'Outputs')
-        self._topology.dump(self._template.workflows, context, 'Workflows')
+        if self._model.substitution is not None:
+            self._model.substitution.dump()
+        self._topology.dump(self._model.inputs, context, 'Inputs')
+        self._topology.dump(self._model.outputs, context, 'Outputs')
+        self._topology.dump(self._model.workflows, context, 'Workflows')
+
+    def configure_operations(self):
+        for node in self._model.nodes.itervalues():
+            self._topology.configure_operations(node)
+        for group in self._model.groups.itervalues():
+            self._topology.configure_operations(group)
+        for operation in self._model.workflows.itervalues():
+            self._topology.configure_operations(operation)
+
+    def validate_capabilities(self):
+        satisfied = True
+        for node in self._model.nodes.values():
+            if not self._topology.validate_capabilities(node):
+                satisfied = False
+        return satisfied
+
+    def satisfy_requirements(self):
+        return all(self._topology.satisfy_requirements(node)
+                   for node in self._model.nodes.values())
 
 
 class Substitution(common._InstanceHandler):
     def coerce(self, **kwargs):
-        self._topology.coerce(self._template.mappings, **kwargs)
+        self._topology.coerce(self._model.mappings, **kwargs)
 
     def validate(self, **kwargs):
-        self._topology.validate(self._template.mappings)
+        self._topology.validate(self._model.mappings)
 
     def dump(self, context):
         context.write('Substitution:')
         with context.style.indent:
-            context.write('Node type: {0}'.format(context.style.type(self._template.node_type.name)))
-            self._topology.dump(self._template.mappings, context, 'Mappings')
+            context.write('Node type: {0}'.format(context.style.type(self._model.node_type.name)))
+            self._topology.dump(self._model.mappings, context, 'Mappings')
 
 
 class SubstitutionMapping(common._InstanceHandler):
 
     def validate(self, **kwargs):
         # context = ConsumptionContext.get_thread_local()
-        if (self._template.capability is None) and (self._template.requirement_template is None):
+        if (self._model.capability is None) and (self._model.requirement_template is None):
             pass
             # TODO: handler reports
             # context.validation.report('mapping "{0}" refers to neither capability nor a requirement'
@@ -312,16 +550,17 @@ class SubstitutionMapping(common._InstanceHandler):
             #                           level=validation.Issue.BETWEEN_TYPES)
 
     def dump(self, context):
-        if self._template.capability is not None:
+        if self._model.capability is not None:
             context.write('{0} -> {1}.{2}'.format(
-                context.style.node(self._template.name),
-                context.style.node(self._template.capability.node.name),
-                context.style.node(self._template.capability.name)))
+                context.style.node(self._model.name),
+                context.style.node(self._model.capability.node.name),
+                context.style.node(self._model.capability.name)))
         else:
             context.write('{0} -> {1}.{2}'.format(
-                context.style.node(self._template.name),
-                context.style.node(self._template.node.name),
-                context.style.node(self._template.requirement_template.name)))
+                context.style.node(self._model.name),
+                context.style.node(self._model.node.name),
+                context.style.node(self._model.requirement_template.name)))
+
 
 class Metadata(common._InstanceHandler):
 
@@ -334,7 +573,7 @@ class Metadata(common._InstanceHandler):
         pass
 
     def instantiate(self, instance_cls, **kwargs):
-        return instance_cls(name=self._template.name, value=self._template.value)
+        return instance_cls(name=self._model.name, value=self._model.value)
 
     def validate(self):
         pass
@@ -343,24 +582,24 @@ class Metadata(common._InstanceHandler):
 class _Parameter(common._InstanceHandler):
 
     def dump(self, context):
-        if self._template.type_name is not None:
+        if self._model.type_name is not None:
             context.write('{0}: {1} ({2})'.format(
-                context.style.property(self._template.name),
-                context.style.literal(formatting.as_raw(self._template.value)),
-                context.style.type(self._template.type_name)))
+                context.style.property(self._model.name),
+                context.style.literal(formatting.as_raw(self._model.value)),
+                context.style.type(self._model.type_name)))
         else:
             context.write('{0}: {1}'.format(
-                context.style.property(self._template.name),
-                context.style.literal(formatting.as_raw(self._template.value))))
-        if self._template.description:
-            context.write(context.style.meta(self._template.description))
+                context.style.property(self._model.name),
+                context.style.literal(formatting.as_raw(self._model.value))))
+        if self._model.description:
+            context.write(context.style.meta(self._model.description))
 
     def instantiate(self, instance_cls, **kwargs):
         return instance_cls(
-            name=self._template.name,  # pylint: disable=unexpected-keyword-arg
-            type_name=self._template.type_name,
-            _value=self._template._value,
-            description=self._template.description
+            name=self._model.name,  # pylint: disable=unexpected-keyword-arg
+            type_name=self._model.type_name,
+            _value=self._model._value,
+            description=self._model.description
         )
 
     def validate(self):
@@ -396,8 +635,8 @@ class Type(common._InstanceHandler):
         pass
 
     def dump(self, context):
-        if self._template.name:
-            context.write(context.style.type(self._template.name))
+        if self._model.name:
+            context.write(context.style.type(self._model.name))
         with context.style.indent:
-            for child in self._template.children:
+            for child in self._model.children:
                 self._topology.dump(context, child)


Mime
View raw message