You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by mx...@apache.org on 2017/03/30 14:39:37 UTC

[1/5] incubator-ariatosca git commit: ARIA-132-Models-cascading-deletion-raises-constraint-errors [Forced Update!]

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-86-Create-a-basic-Hello-World-blueprint-example 83fcf7273 -> 1f7084848 (forced update)


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 8b619bf..8355521 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -41,7 +41,7 @@ from . import (
 )
 
 
-class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public-methods
+class ServiceTemplateBase(TemplateModelMixin):
     """
     A service template is a source for creating :class:`Service` instances.
 
@@ -90,7 +90,6 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
     :vartype created_at: :class:`datetime.datetime`
     :ivar updated_at: Update timestamp
     :vartype updated_at: :class:`datetime.datetime`
-
     :ivar services: Instantiated services
     :vartype services: [:class:`Service`]
     """
@@ -108,121 +107,151 @@ class ServiceTemplateBase(TemplateModelMixin): # pylint: disable=too-many-public
 
     description = Column(Text)
     main_file_name = Column(Text)
+    created_at = Column(DateTime, nullable=False, index=True)
+    updated_at = Column(DateTime)
+
+    # region foreign keys
 
     @declared_attr
-    def meta_data(cls):
-        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
-        return relationship.many_to_many(cls, 'metadata', dict_key='name')
+    def substitution_template_fk(cls):
+        """For ServiceTemplate one-to-one to SubstitutionTemplate"""
+        return relationship.foreign_key('substitution_template', nullable=True)
 
     @declared_attr
-    def node_templates(cls):
-        return relationship.one_to_many(cls, 'node_template', dict_key='name')
+    def node_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def group_templates(cls):
-        return relationship.one_to_many(cls, 'group_template', dict_key='name')
+    def group_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def policy_templates(cls):
-        return relationship.one_to_many(cls, 'policy_template', dict_key='name')
+    def policy_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def substitution_template(cls):
-        return relationship.one_to_one(cls, 'substitution_template')
+    def relationship_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+    def capability_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def outputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
+    def interface_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def workflow_templates(cls):
-        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
+    def artifact_type_fk(cls):
+        """For ServiceTemplate one-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
 
     @declared_attr
-    def plugin_specifications(cls):
-        return relationship.one_to_many(cls, 'plugin_specification', dict_key='name')
+    def substitution_template(cls):
+        return relationship.one_to_one(
+            cls, 'substitution_template', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def node_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='node_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='node_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def group_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='group_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='group_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def policy_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='policy_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='policy_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def relationship_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='relationship_type_fk',
-                                       other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='relationship_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def capability_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='capability_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='capability_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def interface_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='interface_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='interface_type_fk', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
     def artifact_types(cls):
-        return relationship.one_to_one(cls, 'type', fk='artifact_type_fk', other_property=False)
+        return relationship.one_to_one(
+            cls, 'type', fk='artifact_type_fk', back_populates=relationship.NO_BACK_POP)
 
-    # region orchestration
+    # endregion
 
-    created_at = Column(DateTime, nullable=False, index=True)
-    updated_at = Column(DateTime)
+    # region one_to_many relationships
 
-    # endregion
+    @declared_attr
+    def services(cls):
+        return relationship.one_to_many(cls, 'service')
 
-    # region foreign keys
+    @declared_attr
+    def operation_templates(cls):
+        return relationship.one_to_many(cls, 'operation_template')
 
     @declared_attr
-    def substitution_template_fk(cls):
-        """For ServiceTemplate one-to-one to SubstitutionTemplate"""
-        return relationship.foreign_key('substitution_template', nullable=True)
+    def node_templates(cls):
+        return relationship.one_to_many(cls, 'node_template', dict_key='name')
 
     @declared_attr
-    def node_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def group_templates(cls):
+        return relationship.one_to_many(cls, 'group_template', dict_key='name')
 
     @declared_attr
-    def group_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def policy_templates(cls):
+        return relationship.one_to_many(cls, 'policy_template', dict_key='name')
 
     @declared_attr
-    def policy_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def workflow_templates(cls):
+        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
 
     @declared_attr
-    def relationship_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def plugin_specifications(cls):
+        return relationship.one_to_many(cls, 'plugin_specification', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
-    def capability_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def meta_data(cls):
+        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
+        return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
-    def interface_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
 
     @declared_attr
-    def artifact_type_fk(cls):
-        """For ServiceTemplate one-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def outputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     # endregion
 
@@ -394,7 +423,6 @@ class NodeTemplateBase(TemplateModelMixin):
     :vartype requirement_templates: [:class:`RequirementTemplate`]
     :ivar target_node_template_constraints: Constraints for filtering relationship targets
     :vartype target_node_template_constraints: [:class:`FunctionType`]
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar group_templates: We are a member of these groups
@@ -413,14 +441,54 @@ class NodeTemplateBase(TemplateModelMixin):
                           'service_template_fk',
                           'service_template_name']
 
+    # region foreign_keys
+
+    @declared_attr
+    def type_fk(cls):
+        """For NodeTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
+
+    @declared_attr
+    def service_template_fk(cls):
+        """For ServiceTemplate one-to-many to NodeTemplate"""
+        return relationship.foreign_key('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_template_name(cls):
+        """Required for use by SQLAlchemy queries"""
+        return association_proxy('service_template', 'name')
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def nodes(cls):
+        return relationship.one_to_many(cls, 'node')
+
+    # endregion
+
+    # region many_to_one relationships
+
     @declared_attr
     def type(cls):
-        return relationship.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
-    description = Column(Text)
-    default_instances = Column(Integer, default=1)
-    min_instances = Column(Integer, default=0)
-    max_instances = Column(Integer, default=None)
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
     def properties(cls):
@@ -440,33 +508,15 @@ class NodeTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def requirement_templates(cls):
-        return relationship.one_to_many(cls, 'requirement_template', child_fk='node_template_fk',
-                                        child_property='node_template')
-
-    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
-
-    # region foreign_keys
-
-    @declared_attr
-    def type_fk(cls):
-        """For NodeTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
-
-    @declared_attr
-    def service_template_fk(cls):
-        """For ServiceTemplate one-to-many to NodeTemplate"""
-        return relationship.foreign_key('service_template')
+        return relationship.one_to_many(cls, 'requirement_template', child_fk='node_template_fk')
 
     # endregion
 
-    # region association proxies
-
-    @declared_attr
-    def service_template_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service_template', 'name')
-
-    # endregion
+    description = Column(Text)
+    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))
 
     def is_target_node_valid(self, target_node_template):
         if self.target_node_template_constraints:
@@ -557,7 +607,6 @@ class GroupTemplateBase(TemplateModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar policy_templates: Policy templates enacted on this group
@@ -571,38 +620,66 @@ class GroupTemplateBase(TemplateModelMixin):
     __private_fields__ = ['type_fk',
                           'service_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    # region foreign keys
 
-    description = Column(Text)
+    @declared_attr
+    def type_fk(cls):
+        """For GroupTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def node_templates(cls):
-        return relationship.many_to_many(cls, 'node_template')
+    def service_template_fk(cls):
+        """For ServiceTemplate one-to-many to GroupTemplate"""
+        return relationship.foreign_key('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def groups(cls):
+        return relationship.one_to_many(cls, 'group')
 
     @declared_attr
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
-    # region foreign keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For GroupTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
 
     @declared_attr
-    def service_template_fk(cls):
-        """For ServiceTemplate one-to-many to GroupTemplate"""
-        return relationship.foreign_key('service_template')
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
     # endregion
 
+    # region many_to_many relationships
+
+    @declared_attr
+    def node_templates(cls):
+        return relationship.many_to_many(cls, 'node_template')
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -622,7 +699,7 @@ class GroupTemplateBase(TemplateModelMixin):
         utils.instantiate_dict(self, group.interfaces, self.interface_templates)
         if self.node_templates:
             for node_template in self.node_templates:
-                group.nodes += node_template.nodes.all()
+                group.nodes += node_template.nodes
         return group
 
     def validate(self):
@@ -664,7 +741,6 @@ class PolicyTemplateBase(TemplateModelMixin):
     :vartype group_templates: [:class:`GroupTemplate`]
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar policies: Instantiated policies
@@ -673,14 +749,51 @@ class PolicyTemplateBase(TemplateModelMixin):
 
     __tablename__ = 'policy_template'
 
-    __private_fields__ = ['type_fk',
-                          'service_template_fk']
+    __private_fields__ = ['type_fk', 'service_template_fk']
+
+    # region foreign keys
+
+    @declared_attr
+    def type_fk(cls):
+        """For PolicyTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
+
+    @declared_attr
+    def service_template_fk(cls):
+        """For ServiceTemplate one-to-many to PolicyTemplate"""
+        return relationship.foreign_key('service_template')
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def policies(cls):
+        return relationship.one_to_many(cls, 'policy')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
 
     @declared_attr
     def type(cls):
-        return relationship.many_to_one(cls, 'type')
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
-    description = Column(Text)
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
     def node_templates(cls):
@@ -694,20 +807,10 @@ class PolicyTemplateBase(TemplateModelMixin):
     def properties(cls):
         return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
-    # region foreign keys
-
-    @declared_attr
-    def type_fk(cls):
-        """For PolicyTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
-
-    @declared_attr
-    def service_template_fk(cls):
-        """For ServiceTemplate one-to-many to PolicyTemplate"""
-        return relationship.foreign_key('service_template')
-
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -725,10 +828,10 @@ class PolicyTemplateBase(TemplateModelMixin):
         utils.instantiate_dict(self, policy.properties, self.properties)
         if self.node_templates:
             for node_template in self.node_templates:
-                policy.nodes += node_template.nodes.all()
+                policy.nodes += node_template.nodes
         if self.group_templates:
             for group_template in self.group_templates:
-                policy.groups += group_template.groups.all()
+                policy.groups += group_template.groups
         return policy
 
     def validate(self):
@@ -761,7 +864,6 @@ class SubstitutionTemplateBase(TemplateModelMixin):
     :vartype node_type: :class:`Type`
     :ivar mappings: Requirement and capability mappings
     :vartype mappings: {basestring: :class:`SubstitutionTemplateMapping`}
-
     :ivar service_template: Containing service template
     :vartype service_template: :class:`ServiceTemplate`
     :ivar substitutions: Instantiated substitutions
@@ -772,20 +874,44 @@ class SubstitutionTemplateBase(TemplateModelMixin):
 
     __private_fields__ = ['node_type_fk']
 
+    # region foreign keys
+
     @declared_attr
-    def node_type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def node_type_fk(cls):
+        """For SubstitutionTemplate many-to-one to Type"""
+        return relationship.foreign_key('type')
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def substitutions(cls):
+        return relationship.one_to_many(cls, 'substitution')
 
     @declared_attr
     def mappings(cls):
         return relationship.one_to_many(cls, 'substitution_template_mapping', dict_key='name')
 
-    # region foreign keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def node_type_fk(cls):
-        """For SubstitutionTemplate many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def node_type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
 
     # endregion
 
@@ -830,7 +956,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
     :vartype capability_template: :class:`CapabilityTemplate`
     :ivar requirement_template: Requirement template in the node template
     :vartype requirement_template: :class:`RequirementTemplate`
-
     :ivar substitution_template: Containing substitution template
     :vartype substitution_template: :class:`SubstitutionTemplate`
     """
@@ -842,18 +967,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
                           'capability_template_fk',
                           'requirement_template_fk']
 
-    @declared_attr
-    def node_template(cls):
-        return relationship.one_to_one(cls, 'node_template')
-
-    @declared_attr
-    def capability_template(cls):
-        return relationship.one_to_one(cls, 'capability_template')
-
-    @declared_attr
-    def requirement_template(cls):
-        return relationship.one_to_one(cls, 'requirement_template')
-
     # region foreign keys
 
     @declared_attr
@@ -878,6 +991,45 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.one_to_one(
+            cls, 'node_template', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def capability_template(cls):
+        return relationship.one_to_one(
+            cls, 'capability_template', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def requirement_template(cls):
+        return relationship.one_to_one(
+            cls, 'requirement_template', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def substitution_template(cls):
+        return relationship.many_to_one(cls, 'substitution_template', back_populates='mappings')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -889,7 +1041,7 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin):
     def instantiate(self, container):
         from . import models
         context = ConsumptionContext.get_thread_local()
-        nodes = self.node_template.nodes.all()
+        nodes = self.node_template.nodes
         if len(nodes) == 0:
             context.validation.report(
                 'mapping "{0}" refers to node template "{1}" but there are no '
@@ -950,7 +1102,6 @@ class RequirementTemplateBase(TemplateModelMixin):
     :vartype target_node_template_constraints: [:class:`FunctionType`]
     :ivar relationship_template: Template for relationships (optional)
     :vartype relationship_template: :class:`RelationshipTemplate`
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar substitution_template_mapping: Our contribution to service substitution
@@ -967,28 +1118,6 @@ class RequirementTemplateBase(TemplateModelMixin):
                           'node_template_fk',
                           'relationship_template_fk']
 
-    @declared_attr
-    def target_node_type(cls):
-        return relationship.many_to_one(cls, 'type', fk='target_node_type_fk',
-                                        parent_property=False)
-
-    @declared_attr
-    def target_node_template(cls):
-        return relationship.one_to_one(cls, 'node_template', fk='target_node_template_fk',
-                                       other_property=False)
-
-    @declared_attr
-    def target_capability_type(cls):
-        return relationship.one_to_one(cls, 'type', fk='target_capability_type_fk',
-                                       other_property=False)
-
-    target_capability_name = Column(Text)
-    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
-
-    @declared_attr
-    def relationship_template(cls):
-        return relationship.one_to_one(cls, 'relationship_template')
-
     # region foreign keys
 
     @declared_attr
@@ -1007,17 +1136,73 @@ class RequirementTemplateBase(TemplateModelMixin):
         return relationship.foreign_key('type', nullable=True)
 
     @declared_attr
-    def node_template_fk(cls):
-        """For NodeTemplate one-to-many to RequirementTemplate"""
-        return relationship.foreign_key('node_template')
+    def node_template_fk(cls):
+        """For NodeTemplate one-to-many to RequirementTemplate"""
+        return relationship.foreign_key('node_template')
+
+    @declared_attr
+    def relationship_template_fk(cls):
+        """For RequirementTemplate one-to-one to RelationshipTemplate"""
+        return relationship.foreign_key('relationship_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def target_node_template(cls):
+        return relationship.one_to_one(cls,
+                                       'node_template',
+                                       fk='target_node_template_fk',
+                                       back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def target_capability_type(cls):
+        return relationship.one_to_one(cls,
+                                       'type',
+                                       fk='target_capability_type_fk',
+                                       back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.one_to_one(cls,
+                                       'relationship_template',
+                                       back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def relationships(cls):
+        return relationship.one_to_many(cls, 'relationship')
+
+    @declared_attr
+    def target_node_type(cls):
+        return relationship.many_to_one(
+            cls, 'type', fk='target_node_type_fk', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def relationship_template_fk(cls):
-        """For RequirementTemplate one-to-one to RelationshipTemplate"""
-        return relationship.foreign_key('relationship_template', nullable=True)
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template', fk='node_template_fk')
+
+    # endregion
+
+    # region many_to_many relationships
 
     # endregion
 
+    target_capability_name = Column(Text)
+    target_node_template_constraints = Column(modeling_types.StrictList(FunctionType))
+
     def find_target(self, source_node_template):
         context = ConsumptionContext.get_thread_local()
 
@@ -1137,7 +1322,6 @@ class RelationshipTemplateBase(TemplateModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interface_templates: Bundles of operations
     :vartype interface_templates: {basestring: :class:`InterfaceTemplate`}
-
     :ivar requirement_template: Containing requirement template
     :vartype requirement_template: :class:`RequirementTemplate`
     :ivar relationships: Instantiated relationships
@@ -1148,29 +1332,53 @@ class RelationshipTemplateBase(TemplateModelMixin):
 
     __private_fields__ = ['type_fk']
 
+    # region foreign keys
+
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def type_fk(cls):
+        """For RelationshipTemplate many-to-one to Type"""
+        return relationship.foreign_key('type', nullable=True)
 
-    description = Column(Text)
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def relationships(cls):
+        return relationship.one_to_many(cls, 'relationship')
 
     @declared_attr
     def interface_templates(cls):
         return relationship.one_to_many(cls, 'interface_template', dict_key='name')
 
-    # region foreign keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For RelationshipTemplate many-to-one to Type"""
-        return relationship.foreign_key('type', nullable=True)
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1231,7 +1439,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
     :vartype min_occurrences: int
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar substitution_template_mapping: Our contribution to service substitution
@@ -1245,22 +1452,6 @@ class CapabilityTemplateBase(TemplateModelMixin):
     __private_fields__ = ['type_fk',
                           'node_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-    min_occurrences = Column(Integer, default=None)  # optional
-    max_occurrences = Column(Integer, default=None)  # optional
-
-    @declared_attr
-    def valid_source_node_types(cls):
-        return relationship.many_to_many(cls, 'type', prefix='valid_sources')
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign keys
 
     @declared_attr
@@ -1275,6 +1466,51 @@ class CapabilityTemplateBase(TemplateModelMixin):
 
     # endregion
 
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def capabilities(cls):
+        return relationship.one_to_many(cls, 'capability')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def valid_source_node_types(cls):
+        return relationship.many_to_many(cls, 'type', prefix='valid_sources')
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+    min_occurrences = Column(Integer, default=None)  # optional
+    max_occurrences = Column(Integer, default=None)  # optional
+
     def satisfies_requirement(self,
                               source_node_template,
                               requirement,
@@ -1360,7 +1596,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
     :vartype inputs: {basestring: :class:`Parameter`}
     :ivar operation_templates: Operations
     :vartype operation_templates: {basestring: :class:`OperationTemplate`}
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar group_template: Containing group template
@@ -1378,19 +1613,6 @@ class InterfaceTemplateBase(TemplateModelMixin):
                           'group_template_fk',
                           'relationship_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def operation_templates(cls):
-        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
 
     # region foreign keys
 
@@ -1416,6 +1638,57 @@ class InterfaceTemplateBase(TemplateModelMixin):
 
     # endregion
 
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def interfaces(cls):
+        return relationship.one_to_many(cls, 'interface')
+
+    @declared_attr
+    def operation_templates(cls):
+        return relationship.one_to_many(cls, 'operation_template', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.many_to_one(cls, 'relationship_template')
+
+    @declared_attr
+    def group_template(cls):
+        return relationship.many_to_one(cls, 'group_template')
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1479,7 +1752,6 @@ class OperationTemplateBase(TemplateModelMixin):
     :vartype max_retries: int
     :ivar retry_interval: Interval between retries (in seconds)
     :vartype retry_interval: int
-
     :ivar interface_template: Containing interface template
     :vartype interface_template: :class:`InterfaceTemplate`
     :ivar service_template: Containing service template
@@ -1496,21 +1768,6 @@ class OperationTemplateBase(TemplateModelMixin):
 
     description = Column(Text)
 
-    @declared_attr
-    def plugin_specification(cls):
-        return relationship.one_to_one(cls, 'plugin_specification')
-
-    implementation = Column(Text)
-    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    executor = Column(Text)
-    max_retries = Column(Integer)
-    retry_interval = Column(Integer)
-
     # region foreign keys
 
     @declared_attr
@@ -1530,6 +1787,53 @@ class OperationTemplateBase(TemplateModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def plugin_specification(cls):
+        return relationship.one_to_one(
+            cls, 'plugin_specification', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def operations(cls):
+        return relationship.one_to_many(cls, 'operation')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
+    @declared_attr
+    def interface_template(cls):
+        return relationship.many_to_one(cls, 'interface_template')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    implementation = Column(Text)
+    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
+    executor = Column(Text)
+    max_retries = Column(Integer)
+    retry_interval = Column(Integer)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1604,7 +1908,6 @@ class ArtifactTemplateBase(TemplateModelMixin):
     :vartype repository_credential: {basestring: basestring}
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node_template: Containing node template
     :vartype node_template: :class:`NodeTemplate`
     :ivar artifacts: Instantiated artifacts
@@ -1616,20 +1919,6 @@ class ArtifactTemplateBase(TemplateModelMixin):
     __private_fields__ = ['type_fk',
                           'node_template_fk']
 
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-    source_path = Column(Text)
-    target_path = Column(Text)
-    repository_url = Column(Text)
-    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign keys
 
     @declared_attr
@@ -1644,6 +1933,48 @@ class ArtifactTemplateBase(TemplateModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def artifacts(cls):
+        return relationship.one_to_many(cls, 'artifact')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+    source_path = Column(Text)
+    target_path = Column(Text)
+    repository_url = Column(Text)
+    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
+
     @property
     def as_raw(self):
         return collections.OrderedDict((

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/tests/orchestrator/context/test_operation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_operation.py b/tests/orchestrator/context/test_operation.py
index 6721b29..f55b83e 100644
--- a/tests/orchestrator/context/test_operation.py
+++ b/tests/orchestrator/context/test_operation.py
@@ -353,10 +353,10 @@ def _assert_loggins(ctx, inputs):
     tasks = ctx.model.task.list()
     assert len(tasks) == 1
     task = tasks[0]
-    assert task.logs.count() == 4
+    assert len(task.logs) == 4
 
     logs = ctx.model.log.list()
-    assert len(logs) == execution.logs.count() == 6
+    assert len(logs) == len(execution.logs) == 6
     assert set(logs) == set(execution.logs)
 
     assert all(l.execution == execution for l in logs)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
----------------------------------------------------------------------
diff --git a/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml b/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
index b950fa4..3b4f371 100644
--- a/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
+++ b/tests/resources/service-templates/tosca-simple-1.0/node-cellar/node-cellar.yaml
@@ -33,7 +33,6 @@ imports:
   - types/mongodb.yaml
   - types/nginx.yaml
   - aria-1.0
-
 dsl_definitions:
 
   default_openstack_credential: &DEFAULT_OPENSTACK_CREDENTIAL



[4/5] incubator-ariatosca git commit: ARIA-135-Add-plugin-field-to-MockTask

Posted by mx...@apache.org.
ARIA-135-Add-plugin-field-to-MockTask


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

Branch: refs/heads/ARIA-86-Create-a-basic-Hello-World-blueprint-example
Commit: 4400e302311f51da48fd0c66a58dfa1b7e66a80e
Parents: 941d85c
Author: max-orlov <ma...@gigaspaces.com>
Authored: Thu Mar 30 13:56:36 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Thu Mar 30 14:09:29 2017 +0300

----------------------------------------------------------------------
 tests/orchestrator/workflows/executor/test_executor.py       | 7 +++----
 .../orchestrator/workflows/executor/test_process_executor.py | 8 ++++----
 2 files changed, 7 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4400e302/tests/orchestrator/workflows/executor/test_executor.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/executor/test_executor.py b/tests/orchestrator/workflows/executor/test_executor.py
index 9dde1ce..d84d1ec 100644
--- a/tests/orchestrator/workflows/executor/test_executor.py
+++ b/tests/orchestrator/workflows/executor/test_executor.py
@@ -85,12 +85,11 @@ class MockContext(object):
 
     def __init__(self, *args, **kwargs):
         self.logger = logging.getLogger()
+        self.task = type('SubprocessMockTask', (object, ), {'plugin': None})
+        self.serialization_dict = {'context_cls': self.__class__, 'context': {}}
 
     def __getattr__(self, item):
-        if item == 'serialization_dict':
-            return {'context_cls': self.__class__, 'context': {}}
-        else:
-            return None
+        return None
 
     @classmethod
     def deserialize_from_dict(cls, **kwargs):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/4400e302/tests/orchestrator/workflows/executor/test_process_executor.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/executor/test_process_executor.py b/tests/orchestrator/workflows/executor/test_process_executor.py
index 0edd0a5..436e7b6 100644
--- a/tests/orchestrator/workflows/executor/test_process_executor.py
+++ b/tests/orchestrator/workflows/executor/test_process_executor.py
@@ -113,17 +113,17 @@ class MockContext(object):
 
     def __init__(self, *args, **kwargs):
         self.logger = logging.getLogger('mock_logger')
+        self.task = type('SubprocessMockTask', (object, ), {'plugin': None})
+        self.serialization_dict = {'context_cls': self.__class__, 'context': {}}
 
     def __getattr__(self, item):
-        if item == 'serialization_dict':
-            return {'context_cls': self.__class__, 'context': {}}
-        else:
-            return None
+        return None
 
     @classmethod
     def deserialize_from_dict(cls, **kwargs):
         return cls()
 
+
 class MockTask(object):
 
     INFINITE_RETRIES = aria_models.Task.INFINITE_RETRIES


[3/5] incubator-ariatosca git commit: ARIA-133 Add status-related properties to the Execution, Task and Node models

Posted by mx...@apache.org.
ARIA-133 Add status-related properties to the Execution, Task and Node models

We are adding these properties so it will be easier to filter those models
from storage according to their status, and to not make use of the their
`status` constants outside of the models themselves.

It should be noted, since we currently have the concept of `StubTasks`
(that are not part of the model), we had to implement the same logic for
them, although they don't direct access to the state constants of the
task model. We did this since they are treated as 'regular' model tasks
in some parts of the code.


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

Branch: refs/heads/ARIA-86-Create-a-basic-Hello-World-blueprint-example
Commit: 941d85c0ed622b6b233f38f853145c6a55120dec
Parents: 2de0497
Author: Avia Efrat <av...@gigaspaces.com>
Authored: Tue Mar 28 12:51:42 2017 +0300
Committer: Avia Efrat <av...@gigaspaces.com>
Committed: Tue Mar 28 18:41:19 2017 +0300

----------------------------------------------------------------------
 aria/modeling/orchestration.py             | 20 ++++++++++++++++----
 aria/modeling/service_instance.py          |  4 ++++
 aria/orchestrator/workflows/core/engine.py |  6 +++---
 aria/orchestrator/workflows/core/task.py   |  8 ++++++++
 4 files changed, 31 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/941d85c0/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index a13ae87..f0bd4b2 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -69,7 +69,6 @@ class ExecutionBase(ModelMixin):
 
     STATES = [TERMINATED, FAILED, CANCELLED, PENDING, STARTED, CANCELLING, FORCE_CANCELLING]
     END_STATES = [TERMINATED, FAILED, CANCELLED]
-    ACTIVE_STATES = [state for state in STATES if state not in END_STATES]
 
     VALID_TRANSITIONS = {
         PENDING: [STARTED, CANCELLED],
@@ -102,6 +101,14 @@ class ExecutionBase(ModelMixin):
     status = Column(Enum(*STATES, name='execution_status'), default=PENDING)
     workflow_name = Column(Text)
 
+    @property
+    def has_ended(self):
+        return self.status in self.END_STATES
+
+    @property
+    def is_active(self):
+        return not self.has_ended
+
     @declared_attr
     def logs(cls):
         return relationship.one_to_many(cls, 'log')
@@ -240,9 +247,6 @@ class TaskBase(ModelMixin):
         FAILED,
     )
 
-    WAIT_STATES = [PENDING, RETRYING]
-    END_STATES = [SUCCESS, FAILED]
-
     RUNS_ON_SOURCE = 'source'
     RUNS_ON_TARGET = 'target'
     RUNS_ON_NODE = 'node'
@@ -289,6 +293,14 @@ class TaskBase(ModelMixin):
     _runs_on = Column(Enum(*RUNS_ON, name='runs_on'), name='runs_on')
 
     @property
+    def has_ended(self):
+        return self.status in [self.SUCCESS, self.FAILED]
+
+    @property
+    def is_waiting(self):
+        return self.status in [self.PENDING, self.RETRYING]
+
+    @property
     def runs_on(self):
         if self._runs_on == self.RUNS_ON_NODE:
             return self.node

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/941d85c0/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index e2e5ae0..e6c2b12 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -417,6 +417,10 @@ class NodeBase(InstanceModelMixin):
         except KeyError:
             return None
 
+    @property
+    def is_available(self):
+        return self.state not in [self.INITIAL, self.DELETED, self.ERROR]
+
     # region foreign_keys
 
     @declared_attr

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/941d85c0/aria/orchestrator/workflows/core/engine.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/engine.py b/aria/orchestrator/workflows/core/engine.py
index fa4550d..d32abb8 100644
--- a/aria/orchestrator/workflows/core/engine.py
+++ b/aria/orchestrator/workflows/core/engine.py
@@ -88,12 +88,12 @@ class Engine(logger.LoggerMixin):
     def _executable_tasks(self):
         now = datetime.utcnow()
         return (task for task in self._tasks_iter()
-                if task.status in models.Task.WAIT_STATES and
+                if task.is_waiting and
                 task.due_at <= now and
                 not self._task_has_dependencies(task))
 
     def _ended_tasks(self):
-        return (task for task in self._tasks_iter() if task.status in models.Task.END_STATES)
+        return (task for task in self._tasks_iter() if task.has_ended)
 
     def _task_has_dependencies(self, task):
         return len(self._execution_graph.pred.get(task.id, {})) > 0
@@ -105,7 +105,7 @@ class Engine(logger.LoggerMixin):
         for _, data in self._execution_graph.nodes_iter(data=True):
             task = data['task']
             if isinstance(task, engine_task.OperationTask):
-                if task.model_task.status not in models.Task.END_STATES:
+                if not task.model_task.has_ended:
                     self._workflow_context.model.task.refresh(task.model_task)
             yield task
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/941d85c0/aria/orchestrator/workflows/core/task.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/workflows/core/task.py b/aria/orchestrator/workflows/core/task.py
index 1e13588..aa8963f 100644
--- a/aria/orchestrator/workflows/core/task.py
+++ b/aria/orchestrator/workflows/core/task.py
@@ -69,6 +69,14 @@ class StubTask(BaseTask):
         self.status = models.Task.PENDING
         self.due_at = datetime.utcnow()
 
+    @property
+    def has_ended(self):
+        return self.status in [models.Task.SUCCESS, models.Task.FAILED]
+
+    @property
+    def is_waiting(self):
+        return self.status in [models.Task.PENDING, models.Task.RETRYING]
+
 
 class StartWorkflowTask(StubTask):
     """


[2/5] incubator-ariatosca git commit: ARIA-132-Models-cascading-deletion-raises-constraint-errors

Posted by mx...@apache.org.
ARIA-132-Models-cascading-deletion-raises-constraint-errors

Additional fixes:
- The relationships are now defined on both sides. we no longer use backref, but back_populates.


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

Branch: refs/heads/ARIA-86-Create-a-basic-Hello-World-blueprint-example
Commit: 2de049729f5d0fff50297d25a88f5eecdcf266f9
Parents: 07cbfcd
Author: max-orlov <ma...@gigaspaces.com>
Authored: Sun Mar 26 14:13:47 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Tue Mar 28 15:01:15 2017 +0300

----------------------------------------------------------------------
 aria/.pylintrc                                  |   2 +-
 aria/modeling/orchestration.py                  |  16 +
 aria/modeling/relationship.py                   | 222 +++--
 aria/modeling/service_changes.py                |  86 +-
 aria/modeling/service_common.py                 |   4 +
 aria/modeling/service_instance.py               | 813 +++++++++++-------
 aria/modeling/service_template.py               | 823 +++++++++++++------
 tests/orchestrator/context/test_operation.py    |   4 +-
 .../node-cellar/node-cellar.yaml                |   1 -
 9 files changed, 1299 insertions(+), 672 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/.pylintrc
----------------------------------------------------------------------
diff --git a/aria/.pylintrc b/aria/.pylintrc
index 589402f..7222605 100644
--- a/aria/.pylintrc
+++ b/aria/.pylintrc
@@ -375,7 +375,7 @@ max-attributes=20
 min-public-methods=0
 
 # Maximum number of public methods for a class (see R0904).
-max-public-methods=20
+max-public-methods=50
 
 # Maximum number of boolean expressions in a if statement
 max-bool-expr=5

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/orchestration.py
----------------------------------------------------------------------
diff --git a/aria/modeling/orchestration.py b/aria/modeling/orchestration.py
index 2d58671..a13ae87 100644
--- a/aria/modeling/orchestration.py
+++ b/aria/modeling/orchestration.py
@@ -103,9 +103,17 @@ class ExecutionBase(ModelMixin):
     workflow_name = Column(Text)
 
     @declared_attr
+    def logs(cls):
+        return relationship.one_to_many(cls, 'log')
+
+    @declared_attr
     def service(cls):
         return relationship.many_to_one(cls, 'service')
 
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
+
     # region foreign keys
 
     @declared_attr
@@ -185,6 +193,10 @@ class PluginBase(ModelMixin):
 
     __tablename__ = 'plugin'
 
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
+
     archive_name = Column(Text, nullable=False, index=True)
     distribution = Column(Text)
     distribution_release = Column(Text)
@@ -239,6 +251,10 @@ class TaskBase(ModelMixin):
     INFINITE_RETRIES = -1
 
     @declared_attr
+    def logs(cls):
+        return relationship.one_to_many(cls, 'log')
+
+    @declared_attr
     def node(cls):
         return relationship.many_to_one(cls, 'node')
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
index 70691b3..ac1de28 100644
--- a/aria/modeling/relationship.py
+++ b/aria/modeling/relationship.py
@@ -26,9 +26,10 @@ from sqlalchemy import (
 
 from ..utils import formatting
 
+NO_BACK_POP = 'NO_BACK_POP'
 
-def foreign_key(other_table,
-                nullable=False):
+
+def foreign_key(other_table, nullable=False):
     """
     Declare a foreign key property, which will also create a foreign key column in the table with
     the name of the property. By convention the property name should end in "_fk".
@@ -54,9 +55,7 @@ def foreign_key(other_table,
                   nullable=nullable)
 
 
-def one_to_one_self(model_class,
-                    fk,
-                    relationship_kwargs=None):
+def one_to_one_self(model_class, fk):
     """
     Declare a one-to-one relationship property. The property value would be an instance of the same
     model.
@@ -69,12 +68,8 @@ def one_to_one_self(model_class,
     :type model_class: type
     :param fk: Foreign key name
     :type fk: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
     """
 
-    relationship_kwargs = relationship_kwargs or {}
-
     remote_side = '{model_class}.{remote_column}'.format(
         model_class=model_class.__name__,
         remote_column=model_class.id_column_name()
@@ -85,20 +80,18 @@ def one_to_one_self(model_class,
         model_class=model_class.__name__,
         column=fk
     )
-
-    return relationship(
-        _get_class_for_table(model_class, model_class.__tablename__).__name__,
-        primaryjoin=primaryjoin,
-        remote_side=remote_side,
-        post_update=True,
-        **relationship_kwargs
+    return _relationship(
+        model_class,
+        model_class.__tablename__,
+        relationship_kwargs={
+            'primaryjoin': primaryjoin,
+            'remote_side': remote_side,
+            'post_update': True
+        }
     )
 
 
-def one_to_many_self(model_class,
-                     fk,
-                     dict_key=None,
-                     relationship_kwargs=None):
+def one_to_many_self(model_class, fk, dict_key=None):
     """
     Declare a one-to-many relationship property. The property value would be a list or dict of
     instances of the same model.
@@ -114,28 +107,24 @@ def one_to_many_self(model_class,
     :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
                      be a list
     :type dict_key: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
     """
-
-    relationship_kwargs = relationship_kwargs or {}
-
-    relationship_kwargs.setdefault('remote_side', '{model_class}.{remote_column}'.format(
-        model_class=model_class.__name__,
-        remote_column=fk
-    ))
-
-    return _relationship(model_class, model_class.__tablename__, None, relationship_kwargs,
-                         other_property=False, dict_key=dict_key)
+    return _relationship(
+        model_class,
+        model_class.__tablename__,
+        relationship_kwargs={
+            'remote_side': '{model_class}.{remote_column}'.format(
+                model_class=model_class.__name__, remote_column=fk)
+        },
+        back_populates=False,
+        dict_key=dict_key
+    )
 
 
 def one_to_one(model_class,
                other_table,
                fk=None,
                other_fk=None,
-               other_property=None,
-               relationship_kwargs=None,
-               backref_kwargs=None):
+               back_populates=None):
     """
     Declare a one-to-one relationship property. The property value would be an instance of the other
     table's model.
@@ -154,26 +143,25 @@ def one_to_one(model_class,
     :type fk: basestring
     :param other_fk: Foreign key name at the other table (no need specify if there's no ambiguity)
     :type other_fk: basestring
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
+    :param back_populates: Override name of matching many-to-many property at other table; set to
+                       false to disable
+    :type back_populates: basestring|bool
     """
+    if back_populates is None:
+        back_populates = model_class.__tablename__
 
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', False)
-
-    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
-                         other_property, fk=fk, other_fk=other_fk)
+    return _relationship(model_class,
+                         other_table,
+                         fk=fk,
+                         back_populates=back_populates,
+                         other_fk=other_fk)
 
 
 def one_to_many(model_class,
                 child_table,
                 child_fk=None,
                 dict_key=None,
-                child_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
+                back_populates=None):
     """
     Declare a one-to-many relationship property. The property value would be a list or dict of
     instances of the child table's model.
@@ -194,29 +182,25 @@ def one_to_many(model_class,
     :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
                      be a list
     :type dict_key: basestring
-    :param child_property: Override name of matching many-to-one property at child table; set to
+    :param back_populates: Override name of matching many-to-one property at child table; set to
                            false to disable
-    :type child_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
+    :type back_populates: basestring|bool
     """
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', False)
-
-    return _relationship(model_class, child_table, backref_kwargs, relationship_kwargs,
-                         child_property, other_fk=child_fk, dict_key=dict_key)
+    if back_populates is None:
+        back_populates = model_class.__tablename__
+    return _relationship(
+        model_class,
+        child_table,
+        back_populates=back_populates,
+        other_fk=child_fk,
+        dict_key=dict_key)
 
 
 def many_to_one(model_class,
                 parent_table,
                 fk=None,
                 parent_fk=None,
-                parent_property=None,
-                relationship_kwargs=None,
-                backref_kwargs=None):
+                back_populates=None):
     """
     Declare a many-to-one relationship property. The property value would be an instance of the
     parent table's model.
@@ -236,34 +220,25 @@ def many_to_one(model_class,
     :type parent_table: basestring
     :param fk: Foreign key name at our table (no need specify if there's no ambiguity)
     :type fk: basestring
-    :param parent_property: Override name of matching one-to-many property at parent table; set to
+    :param back_populates: Override name of matching one-to-many property at parent table; set to
                             false to disable
-    :type parent_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
+    :type back_populates: basestring|bool
     """
+    if back_populates is None:
+        back_populates = formatting.pluralize(model_class.__tablename__)
 
-    if parent_property is None:
-        parent_property = formatting.pluralize(model_class.__tablename__)
-
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', True)
-    backref_kwargs.setdefault('lazy', 'dynamic')
-    backref_kwargs.setdefault('cascade', 'all') # delete children when parent is deleted
-
-    return _relationship(model_class, parent_table, backref_kwargs, relationship_kwargs,
-                         parent_property, fk=fk, other_fk=parent_fk)
+    return _relationship(model_class,
+                         parent_table,
+                         back_populates=back_populates,
+                         fk=fk,
+                         other_fk=parent_fk)
 
 
 def many_to_many(model_class,
                  other_table,
                  prefix=None,
                  dict_key=None,
-                 other_property=None,
-                 relationship_kwargs=None,
-                 backref_kwargs=None):
+                 other_property=None):
     """
     Declare a many-to-many relationship property. The property value would be a list or dict of
     instances of the other table's model.
@@ -280,8 +255,8 @@ def many_to_many(model_class,
 
     :param model_class: The class in which this relationship will be declared
     :type model_class: type
-    :param parent_table: Parent table name
-    :type parent_table: basestring
+    :param other_table: Parent table name
+    :type other_table: basestring
     :param prefix: Optional prefix for extra table name as well as for ``other_property``
     :type prefix: basestring
     :param dict_key: If set the value will be a dict with this key as the dict key; otherwise will
@@ -290,10 +265,6 @@ def many_to_many(model_class,
     :param other_property: Override name of matching many-to-many property at other table; set to
                            false to disable
     :type other_property: basestring|bool
-    :param relationship_kwargs: Extra kwargs for SQLAlchemy ``relationship``
-    :type relationship_kwargs: {}
-    :param backref_kwargs: Extra kwargs for SQLAlchemy ``backref``
-    :type backref_kwargs: {}
     """
 
     this_table = model_class.__tablename__
@@ -303,69 +274,68 @@ def many_to_many(model_class,
     other_column_name = '{0}_id'.format(other_table)
     other_foreign_key = '{0}.id'.format(other_table)
 
-    secondary_table = '{0}_{1}'.format(this_table, other_table)
+    secondary_table_name = '{0}_{1}'.format(this_table, other_table)
 
     if prefix is not None:
-        secondary_table = '{0}_{1}'.format(prefix, secondary_table)
+        secondary_table_name = '{0}_{1}'.format(prefix, secondary_table_name)
         if other_property is None:
             other_property = '{0}_{1}'.format(prefix, formatting.pluralize(this_table))
 
-    backref_kwargs = backref_kwargs or {}
-    backref_kwargs.setdefault('uselist', True)
-
-    relationship_kwargs = relationship_kwargs or {}
-    relationship_kwargs.setdefault('secondary', _get_secondary_table(
+    secondary_table = _get_secondary_table(
         model_class.metadata,
-        secondary_table,
+        secondary_table_name,
         this_column_name,
         other_column_name,
         this_foreign_key,
         other_foreign_key
-    ))
+    )
 
-    return _relationship(model_class, other_table, backref_kwargs, relationship_kwargs,
-                         other_property, dict_key=dict_key)
+    return _relationship(
+        model_class,
+        other_table,
+        relationship_kwargs={'secondary': secondary_table},
+        backref_kwargs={'name': other_property, 'uselist': True} if other_property else None,
+        dict_key=dict_key
+    )
 
 
-def _relationship(model_class, other_table, backref_kwargs, relationship_kwargs, other_property,
-                  fk=None, other_fk=None, dict_key=None):
+def _relationship(model_class,
+                  other_table_name,
+                  back_populates=None,
+                  backref_kwargs=None,
+                  relationship_kwargs=None,
+                  fk=None,
+                  other_fk=None,
+                  dict_key=None):
     relationship_kwargs = relationship_kwargs or {}
 
     if fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(
-                                               model_class,
-                                               model_class.__tablename__),
-                                           fk))
+        relationship_kwargs.setdefault(
+            'foreign_keys',
+            lambda: getattr(_get_class_for_table(model_class, model_class.__tablename__), fk)
+        )
 
     elif other_fk:
-        relationship_kwargs.setdefault('foreign_keys',
-                                       lambda: getattr(
-                                           _get_class_for_table(
-                                               model_class,
-                                               other_table),
-                                           other_fk))
+        relationship_kwargs.setdefault(
+            'foreign_keys',
+            lambda: getattr(_get_class_for_table(model_class, other_table_name), other_fk)
+        )
 
     if dict_key:
         relationship_kwargs.setdefault('collection_class',
                                        attribute_mapped_collection(dict_key))
 
-    if other_property is False:
-        # No backref
-        return relationship(
-            lambda: _get_class_for_table(model_class, other_table),
-            **relationship_kwargs
-        )
+    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
+                           )
     else:
-        if other_property is None:
-            other_property = model_class.__tablename__
-        backref_kwargs = backref_kwargs or {}
-        return relationship(
-            lambda: _get_class_for_table(model_class, other_table),
-            backref=backref(other_property, **backref_kwargs),
-            **relationship_kwargs
-        )
+        if back_populates is not NO_BACK_POP:
+            relationship_kwargs['back_populates'] = back_populates
+        return relationship(lambda: _get_class_for_table(model_class, other_table_name),
+                            **relationship_kwargs)
 
 
 def _get_class_for_table(model_class, tablename):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_changes.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_changes.py b/aria/modeling/service_changes.py
index a33e6ae..b1a75a2 100644
--- a/aria/modeling/service_changes.py
+++ b/aria/modeling/service_changes.py
@@ -42,9 +42,6 @@ class ServiceUpdateBase(ModelMixin):
     """
     Deployment update model representation.
     """
-
-    steps = None
-
     __tablename__ = 'service_update'
 
     __private_fields__ = ['service_fk',
@@ -60,14 +57,6 @@ class ServiceUpdateBase(ModelMixin):
     modified_entity_ids = Column(Dict)
     state = Column(Text)
 
-    @declared_attr
-    def execution(cls):
-        return relationship.many_to_one(cls, 'execution')
-
-    @declared_attr
-    def service(cls):
-        return relationship.many_to_one(cls, 'service', parent_property='updates')
-
     # region foreign keys
 
     @declared_attr
@@ -94,6 +83,34 @@ class ServiceUpdateBase(ModelMixin):
 
     # endregion
 
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def steps(cls):
+        return relationship.one_to_many(cls, 'service_update_step')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def execution(cls):
+        return relationship.one_to_one(cls, 'execution', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service', back_populates='updates')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     def to_dict(self, suppress_error=False, **kwargs):
         dep_update_dict = super(ServiceUpdateBase, self).to_dict(suppress_error)     #pylint: disable=no-member
         # Taking care of the fact the DeploymentSteps are _BaseModels
@@ -133,10 +150,6 @@ class ServiceUpdateStepBase(ModelMixin):
     entity_id = Column(Text, nullable=False)
     entity_type = Column(Enum(*ENTITY_TYPES, name='entity_type'), nullable=False)
 
-    @declared_attr
-    def service_update(cls):
-        return relationship.many_to_one(cls, 'service_update', parent_property='steps')
-
     # region foreign keys
 
     @declared_attr
@@ -154,6 +167,26 @@ class ServiceUpdateStepBase(ModelMixin):
 
     # endregion
 
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_update(cls):
+        return relationship.many_to_one(cls, 'service_update', back_populates='steps')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     def __hash__(self):
         return hash((getattr(self, self.id_column_name()), self.entity_id))
 
@@ -206,10 +239,6 @@ class ServiceModificationBase(ModelMixin):
     nodes = Column(Dict)
     status = Column(Enum(*STATES, name='service_modification_status'))
 
-    @declared_attr
-    def service(cls):
-        return relationship.many_to_one(cls, 'service', parent_property='modifications')
-
     # region foreign keys
 
     @declared_attr
@@ -226,3 +255,22 @@ class ServiceModificationBase(ModelMixin):
         return association_proxy('service', cls.name_column_name())
 
     # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service', back_populates='modifications')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index d6b1f33..48c3170 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -275,6 +275,10 @@ class PluginSpecificationBase(TemplateModelMixin):
 
     # endregion
 
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
     @property
     def as_raw(self):
         return collections.OrderedDict((

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2de04972/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 1e18db0..e2e5ae0 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -36,7 +36,7 @@ from . import (
 )
 
 
-class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
+class ServiceBase(InstanceModelMixin):
     """
     A service is usually an instance of a :class:`ServiceTemplate`.
 
@@ -71,12 +71,10 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :vartype created_at: :class:`datetime.datetime`
     :ivar updated_at: Update timestamp
     :vartype updated_at: :class:`datetime.datetime`
-
     :ivar permalink: ??
     :vartype permalink: basestring
     :ivar scaling_groups: ??
     :vartype scaling_groups: {}
-
     :ivar modifications: Modifications of this service
     :vartype modifications: [:class:`ServiceModification`]
     :ivar updates: Updates of this service
@@ -91,16 +89,53 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
                           'service_template_fk',
                           'service_template_name']
 
+    # region foreign keys
+
     @declared_attr
-    def service_template(cls):
-        return relationship.many_to_one(cls, 'service_template')
+    def substitution_fk(cls):
+        """Service one-to-one to Substitution"""
+        return relationship.foreign_key('substitution', nullable=True)
 
-    description = Column(Text)
+    @declared_attr
+    def service_template_fk(cls):
+        """For Service many-to-one to ServiceTemplate"""
+        return relationship.foreign_key('service_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
 
     @declared_attr
-    def meta_data(cls):
-        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
-        return relationship.many_to_many(cls, 'metadata', dict_key='name')
+    def service_template_name(cls):
+        """Required for use by SQLAlchemy queries"""
+        return association_proxy('service_template', 'name')
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def substitution(cls):
+        return relationship.one_to_one(cls, 'substitution', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+    @declared_attr
+    def updates(cls):
+        return relationship.one_to_many(cls, 'service_update')
+
+    @declared_attr
+    def modifications(cls):
+        return relationship.one_to_many(cls, 'service_modification')
+
+    @declared_attr
+    def executions(cls):
+        return relationship.one_to_many(cls, 'execution')
+
+    @declared_attr
+    def operations(cls):
+        return relationship.one_to_many(cls, 'operation')
 
     @declared_attr
     def nodes(cls):
@@ -115,8 +150,24 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         return relationship.one_to_many(cls, 'policy', dict_key='name')
 
     @declared_attr
-    def substitution(cls):
-        return relationship.one_to_one(cls, 'substitution')
+    def workflows(cls):
+        return relationship.one_to_many(cls, 'operation', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service_template(cls):
+        return relationship.many_to_one(cls, 'service_template')
+
+    # endregion
+
+    # region many_to_many relationships
+    @declared_attr
+    def meta_data(cls):
+        # Warning! We cannot use the attr name "metadata" because it's used by SQLAlchemy!
+        return relationship.many_to_many(cls, 'metadata', dict_key='name')
 
     @declared_attr
     def inputs(cls):
@@ -127,13 +178,13 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
 
     @declared_attr
-    def workflows(cls):
-        return relationship.one_to_many(cls, 'operation', dict_key='name')
-
-    @declared_attr
     def plugin_specifications(cls):
         return relationship.many_to_many(cls, 'plugin_specification', dict_key='name')
 
+    # endregion
+
+    description = Column(Text)
+
     created_at = Column(DateTime, nullable=False, index=True)
     updated_at = Column(DateTime)
 
@@ -144,29 +195,6 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     # endregion
 
-    # region foreign keys
-
-    @declared_attr
-    def substitution_fk(cls):
-        """Service one-to-one to Substitution"""
-        return relationship.foreign_key('substitution', nullable=True)
-
-    @declared_attr
-    def service_template_fk(cls):
-        """For Service many-to-one to ServiceTemplate"""
-        return relationship.foreign_key('service_template', nullable=True)
-
-    # endregion
-
-    # region association proxies
-
-    @declared_attr
-    def service_template_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service_template', 'name')
-
-    # endregion
-
     def satisfy_requirements(self):
         satisfied = True
         for node in self.nodes.itervalues():
@@ -290,7 +318,7 @@ class ServiceBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
                         self._dump_graph_node(target_node)
 
 
-class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
+class NodeBase(InstanceModelMixin):
     """
     Usually an instance of a :class:`NodeTemplate`.
 
@@ -318,7 +346,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :vartype inbound_relationships: [:class:`Relationship`]
     :ivar host: Host node (can be self)
     :vartype host: :class:`Node`
-
     :ivar runtime_properties: TODO: should be replaced with attributes
     :vartype runtime_properties: {}
     :ivar scaling_groups: ??
@@ -327,7 +354,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
     :vartype state: string
     :ivar version: Used by `aria.storage.instrumentation`
     :vartype version: int
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     :ivar groups: We are a member of these groups
@@ -391,19 +417,52 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         except KeyError:
             return None
 
+    # region foreign_keys
+
     @declared_attr
-    def node_template(cls):
-        return relationship.many_to_one(cls, 'node_template')
+    def type_fk(cls):
+        """For Node many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def host_fk(cls):
+        """For Node one-to-one to Node"""
+        return relationship.foreign_key('node', nullable=True)
 
-    description = Column(Text)
+    @declared_attr
+    def service_fk(cls):
+        """For Service one-to-many to Node"""
+        return relationship.foreign_key('service')
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def node_template_fk(cls):
+        """For Node many-to-one to NodeTemplate"""
+        return relationship.foreign_key('node_template')
+
+    # endregion
+
+    # region association proxies
+
+    @declared_attr
+    def service_name(cls):
+        """Required for use by SQLAlchemy queries"""
+        return association_proxy('service', 'name')
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def host(cls):
+        return relationship.one_to_one_self(cls, 'host_fk')
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
 
     @declared_attr
     def interfaces(cls):
@@ -419,20 +478,40 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
 
     @declared_attr
     def outbound_relationships(cls):
-        return relationship.one_to_many(cls, 'relationship', child_fk='source_node_fk',
-                                        child_property='source_node')
+        return relationship.one_to_many(
+            cls, 'relationship', child_fk='source_node_fk', back_populates='source_node')
 
     @declared_attr
     def inbound_relationships(cls):
-        return relationship.one_to_many(cls, 'relationship', child_fk='target_node_fk',
-                                        child_property='target_node')
+        return relationship.one_to_many(
+            cls, 'relationship', child_fk='target_node_fk', back_populates='target_node')
+
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def host(cls):
-        return relationship.one_to_one_self(cls, 'host_fk')
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
-    # region orchestration
+    @declared_attr
+    def node_template(cls):
+        return relationship.many_to_one(cls, 'node_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
 
+    # endregion
+
+    # region many_to_many relationships
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
     runtime_properties = Column(modeling_types.Dict)
     scaling_groups = Column(modeling_types.List)
     state = Column(Enum(*STATES, name='node_state'), nullable=False, default=INITIAL)
@@ -454,41 +533,6 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
             return host_ip_property.value
         return None
 
-    # endregion
-
-    # region foreign_keys
-
-    @declared_attr
-    def type_fk(cls):
-        """For Node many-to-one to Type"""
-        return relationship.foreign_key('type')
-
-    @declared_attr
-    def host_fk(cls):
-        """For Node one-to-one to Node"""
-        return relationship.foreign_key('node', nullable=True)
-
-    @declared_attr
-    def service_fk(cls):
-        """For Service one-to-many to Node"""
-        return relationship.foreign_key('service')
-
-    @declared_attr
-    def node_template_fk(cls):
-        """For Node many-to-one to NodeTemplate"""
-        return relationship.foreign_key('node_template', nullable=True)
-
-    # endregion
-
-    # region association proxies
-
-    @declared_attr
-    def service_name(cls):
-        """Required for use by SQLAlchemy queries"""
-        return association_proxy('service', 'name')
-
-    # endregion
-
     def satisfy_requirements(self):
         node_template = self.node_template
         satisfied = True
@@ -513,7 +557,7 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
         from . import models
         context = ConsumptionContext.get_thread_local()
         # Find target nodes
-        target_nodes = target_node_template.nodes.all()
+        target_nodes = target_node_template.nodes
         if target_nodes:
             target_node = None
             target_capability = None
@@ -621,6 +665,7 @@ class NodeBase(InstanceModelMixin): # pylint: disable=too-many-public-methods
             utils.dump_dict_values(self.capabilities, 'Capabilities')
             utils.dump_list_values(self.outbound_relationships, 'Relationships')
 
+
 class GroupBase(InstanceModelMixin):
     """
     Usually an instance of a :class:`GroupTemplate`.
@@ -639,7 +684,6 @@ class GroupBase(InstanceModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interface`}
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     :ivar policies: Policies enacted on this group
@@ -648,51 +692,73 @@ class GroupBase(InstanceModelMixin):
 
     __tablename__ = 'group'
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'group_template_fk']
+    __private_fields__ = ['type_fk', 'service_fk', 'group_template_fk']
 
-    @declared_attr
-    def group_template(cls):
-        return relationship.many_to_one(cls, 'group_template')
+    # region foreign_keys
 
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
+    def type_fk(cls):
+        """For Group many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def nodes(cls):
-        return relationship.many_to_many(cls, 'node')
+    def service_fk(cls):
+        """For Service one-to-many to Group"""
+        return relationship.foreign_key('service')
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def group_template_fk(cls):
+        """For Group many-to-one to GroupTemplate"""
+        return relationship.foreign_key('group_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
     def interfaces(cls):
         return relationship.one_to_many(cls, 'interface', dict_key='name')
 
-    # region foreign_keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For Group many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
     @declared_attr
-    def service_fk(cls):
-        """For Service one-to-many to Group"""
-        return relationship.foreign_key('service')
+    def group_template(cls):
+        return relationship.many_to_one(cls, 'group_template')
 
     @declared_attr
-    def group_template_fk(cls):
-        """For Group many-to-one to GroupTemplate"""
-        return relationship.foreign_key('group_template', nullable=True)
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def nodes(cls):
+        return relationship.many_to_many(cls, 'node')
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -740,58 +806,79 @@ class PolicyBase(InstanceModelMixin):
     :vartype groups: [:class:`Group`]
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     """
 
     __tablename__ = 'policy'
 
-    __private_fields__ = ['type_fk',
-                          'service_fk',
-                          'policy_template_fk']
+    __private_fields__ = ['type_fk', 'service_fk', 'policy_template_fk']
 
-    @declared_attr
-    def policy_template(cls):
-        return relationship.many_to_one(cls, 'policy_template')
+    # region foreign_keys
 
     @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def type_fk(cls):
+        """For Policy many-to-one to Type"""
+        return relationship.foreign_key('type')
 
-    description = Column(Text)
+    @declared_attr
+    def service_fk(cls):
+        """For Service one-to-many to Policy"""
+        return relationship.foreign_key('service')
 
     @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    def policy_template_fk(cls):
+        """For Policy many-to-one to PolicyTemplate"""
+        return relationship.foreign_key('policy_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def nodes(cls):
-        return relationship.many_to_many(cls, 'node')
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
 
     @declared_attr
-    def groups(cls):
-        return relationship.many_to_many(cls, 'group')
+    def policy_template(cls):
+        return relationship.many_to_one(cls, 'policy_template')
 
-    # region foreign_keys
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
 
     @declared_attr
-    def type_fk(cls):
-        """For Policy many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
 
     @declared_attr
-    def service_fk(cls):
-        """For Service one-to-many to Policy"""
-        return relationship.foreign_key('service')
+    def nodes(cls):
+        return relationship.many_to_many(cls, 'node')
 
     @declared_attr
-    def policy_template_fk(cls):
-        """For Policy many-to-one to PolicyTemplate"""
-        return relationship.foreign_key('policy_template', nullable=True)
+    def groups(cls):
+        return relationship.many_to_many(cls, 'group')
 
     # endregion
 
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -835,7 +922,6 @@ class SubstitutionBase(InstanceModelMixin):
     :vartype node_type: :class:`Type`
     :ivar mappings: Requirement and capability mappings
     :vartype mappings: {basestring: :class:`SubstitutionTemplate`}
-
     :ivar service: Containing service
     :vartype service: :class:`Service`
     """
@@ -845,29 +931,53 @@ class SubstitutionBase(InstanceModelMixin):
     __private_fields__ = ['node_type_fk',
                           'substitution_template_fk']
 
+    # region foreign_keys
+
     @declared_attr
-    def substitution_template(cls):
-        return relationship.many_to_one(cls, 'substitution_template')
+    def node_type_fk(cls):
+        """For Substitution many-to-one to Type"""
+        return relationship.foreign_key('type')
 
     @declared_attr
-    def node_type(cls):
-        return relationship.many_to_one(cls, 'type')
+    def substitution_template_fk(cls):
+        """For Substitution many-to-one to SubstitutionTemplate"""
+        return relationship.foreign_key('substitution_template', nullable=True)
+
+    # endregion
+
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
 
     @declared_attr
     def mappings(cls):
         return relationship.one_to_many(cls, 'substitution_mapping', dict_key='name')
 
-    # region foreign_keys
+    # endregion
+
+    # region many_to_one relationships
 
     @declared_attr
-    def node_type_fk(cls):
-        """For Substitution many-to-one to Type"""
-        return relationship.foreign_key('type')
+    def service(cls):
+        return relationship.one_to_one(cls, 'service', back_populates=relationship.NO_BACK_POP)
 
     @declared_attr
-    def substitution_template_fk(cls):
-        """For Substitution many-to-one to SubstitutionTemplate"""
-        return relationship.foreign_key('substitution_template', nullable=True)
+    def substitution_template(cls):
+        return relationship.many_to_one(cls, 'substitution_template')
+
+    @declared_attr
+    def node_type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
 
     # endregion
 
@@ -907,7 +1017,6 @@ class SubstitutionMappingBase(InstanceModelMixin):
     :vartype capability: :class:`Capability`
     :ivar requirement_template: Requirement template in the node template
     :vartype requirement_template: :class:`RequirementTemplate`
-
     :ivar substitution: Containing substitution
     :vartype substitution: :class:`Substitution`
     """
@@ -919,18 +1028,6 @@ class SubstitutionMappingBase(InstanceModelMixin):
                           'capability_fk',
                           'requirement_template_fk']
 
-    @declared_attr
-    def node(cls):
-        return relationship.one_to_one(cls, 'node')
-
-    @declared_attr
-    def capability(cls):
-        return relationship.one_to_one(cls, 'capability')
-
-    @declared_attr
-    def requirement_template(cls):
-        return relationship.one_to_one(cls, 'requirement_template')
-
     # region foreign keys
 
     @declared_attr
@@ -955,6 +1052,43 @@ class SubstitutionMappingBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def substitution(cls):
+        return relationship.many_to_one(cls, 'substitution', back_populates='mappings')
+
+    @declared_attr
+    def node(cls):
+        return relationship.one_to_one(cls, 'node', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def capability(cls):
+        return relationship.one_to_one(cls, 'capability', back_populates=relationship.NO_BACK_POP)
+
+    @declared_attr
+    def requirement_template(cls):
+        return relationship.one_to_one(
+            cls, 'requirement_template', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    # endregion
+
+    # region many_to_many relationships
+
+    # endregion
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1002,12 +1136,10 @@ class RelationshipBase(InstanceModelMixin):
     :vartype properties: {basestring: :class:`Parameter`}
     :ivar interfaces: Bundles of operations
     :vartype interfaces: {basestring: :class:`Interfaces`}
-
     :ivar source_position: ??
     :vartype source_position: int
     :ivar target_position: ??
     :vartype target_position: int
-
     :ivar source_node: Source node
     :vartype source_node: :class:`Node`
     :ivar target_node: Target node
@@ -1027,37 +1159,6 @@ class RelationshipBase(InstanceModelMixin):
                           'source_node_name',
                           'target_node_name']
 
-    @declared_attr
-    def relationship_template(cls):
-        return relationship.many_to_one(cls, 'relationship_template')
-
-    @declared_attr
-    def requirement_template(cls):
-        return relationship.many_to_one(cls, 'requirement_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    @declared_attr
-    def target_capability(cls):
-        return relationship.one_to_one(cls, 'capability')
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
-    @declared_attr
-    def interfaces(cls):
-        return relationship.one_to_many(cls, 'interface', dict_key='name')
-
-    # region orchestration
-
-    source_position = Column(Integer) # ???
-    target_position = Column(Integer) # ???
-
-    # endregion
-
     # region foreign keys
 
     @declared_attr
@@ -1106,6 +1207,63 @@ class RelationshipBase(InstanceModelMixin):
 
     # endregion
 
+    # region one_to_one relationships
+
+    @declared_attr
+    def target_capability(cls):
+        return relationship.one_to_one(cls, 'capability', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def tasks(cls):
+        return relationship.one_to_many(cls, 'task')
+
+    @declared_attr
+    def interfaces(cls):
+        return relationship.one_to_many(cls, 'interface', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def source_node(cls):
+        return relationship.many_to_one(
+            cls, 'node', fk='source_node_fk', back_populates='outbound_relationships')
+
+    @declared_attr
+    def target_node(cls):
+        return relationship.many_to_one(
+            cls, 'node', fk='target_node_fk', back_populates='inbound_relationships')
+
+    @declared_attr
+    def relationship_template(cls):
+        return relationship.many_to_one(cls, 'relationship_template')
+
+    @declared_attr
+    def requirement_template(cls):
+        return relationship.many_to_one(cls, 'requirement_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    source_position = Column(Integer) # ???
+    target_position = Column(Integer) # ???
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1166,7 +1324,6 @@ class CapabilityBase(InstanceModelMixin):
     :vartype occurrences: int
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node: Containing node
     :vartype node: :class:`Node`
     :ivar relationship: Available when we are the target of a relationship
@@ -1181,22 +1338,6 @@ class CapabilityBase(InstanceModelMixin):
                           'node_fk',
                           'capability_template_fk']
 
-    @declared_attr
-    def capability_template(cls):
-        return relationship.many_to_one(cls, 'capability_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    min_occurrences = Column(Integer, default=None)
-    max_occurrences = Column(Integer, default=None)
-    occurrences = Column(Integer, default=0)
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign_keys
 
     @declared_attr
@@ -1216,6 +1357,46 @@ class CapabilityBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def capability_template(cls):
+        return relationship.many_to_one(cls, 'capability_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+
+    # endregion
+
+    min_occurrences = Column(Integer, default=None)
+    max_occurrences = Column(Integer, default=None)
+    occurrences = Column(Integer, default=0)
+
     @property
     def has_enough_relationships(self):
         if self.min_occurrences is not None:
@@ -1274,7 +1455,6 @@ class InterfaceBase(InstanceModelMixin):
     :vartype inputs: {basestring: :class:`Parameter`}
     :ivar operations: Operations
     :vartype operations: {basestring: :class:`Operation`}
-
     :ivar node: Containing node
     :vartype node: :class:`Node`
     :ivar group: Containing group
@@ -1291,24 +1471,6 @@ class InterfaceBase(InstanceModelMixin):
                           'relationship_fk',
                           'interface_template_fk']
 
-    @declared_attr
-    def interface_template(cls):
-        return relationship.many_to_one(cls, 'interface_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    @declared_attr
-    def operations(cls):
-        return relationship.one_to_many(cls, 'operation', dict_key='name')
-
     # region foreign_keys
 
     @declared_attr
@@ -1338,6 +1500,56 @@ class InterfaceBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    @declared_attr
+    def operations(cls):
+        return relationship.one_to_many(cls, 'operation', dict_key='name')
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def relationship(cls):
+        return relationship.many_to_one(cls, 'relationship')
+
+    @declared_attr
+    def group(cls):
+        return relationship.many_to_one(cls, 'group')
+
+    @declared_attr
+    def interface_template(cls):
+        return relationship.many_to_one(cls, 'interface_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1392,7 +1604,6 @@ class OperationBase(InstanceModelMixin):
     :vartype max_retries: int
     :ivar retry_interval: Interval between retries (in seconds)
     :vartype retry_interval: int
-
     :ivar interface: Containing interface
     :vartype interface: :class:`Interface`
     :ivar service: Containing service
@@ -1406,27 +1617,6 @@ class OperationBase(InstanceModelMixin):
                           'plugin_fk',
                           'operation_template_fk']
 
-    @declared_attr
-    def operation_template(cls):
-        return relationship.many_to_one(cls, 'operation_template')
-
-    description = Column(Text)
-
-    @declared_attr
-    def plugin_specification(cls):
-        return relationship.one_to_one(cls, 'plugin_specification')
-
-    implementation = Column(Text)
-    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
-
-    @declared_attr
-    def inputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
-
-    executor = Column(Text)
-    max_retries = Column(Integer)
-    retry_interval = Column(Integer)
-
     # region foreign_keys
 
     @declared_attr
@@ -1451,6 +1641,56 @@ class OperationBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    @declared_attr
+    def plugin_specification(cls):
+        return relationship.one_to_one(
+            cls, 'plugin_specification', back_populates=relationship.NO_BACK_POP)
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+
+    @declared_attr
+    def service(cls):
+        return relationship.many_to_one(cls, 'service')
+
+    @declared_attr
+    def interface(cls):
+        return relationship.many_to_one(cls, 'interface')
+
+    @declared_attr
+    def operation_template(cls):
+        return relationship.many_to_one(cls, 'operation_template')
+
+    # endregion
+
+    # region many_to_many relationships
+
+    @declared_attr
+    def inputs(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='inputs', dict_key='name')
+
+    # endregion
+
+    description = Column(Text)
+    implementation = Column(Text)
+    dependencies = Column(modeling_types.StrictList(item_cls=basestring))
+    executor = Column(Text)
+    max_retries = Column(Integer)
+    retry_interval = Column(Integer)
+
+
+
     @property
     def as_raw(self):
         return collections.OrderedDict((
@@ -1517,7 +1757,6 @@ class ArtifactBase(InstanceModelMixin):
     :vartype repository_credential: {basestring: basestring}
     :ivar properties: Associated parameters
     :vartype properties: {basestring: :class:`Parameter`}
-
     :ivar node: Containing node
     :vartype node: :class:`Node`
     """
@@ -1528,24 +1767,6 @@ class ArtifactBase(InstanceModelMixin):
                           'node_fk',
                           'artifact_template_fk']
 
-    @declared_attr
-    def artifact_template(cls):
-        return relationship.many_to_one(cls, 'artifact_template')
-
-    @declared_attr
-    def type(cls):
-        return relationship.many_to_one(cls, 'type')
-
-    description = Column(Text)
-    source_path = Column(Text)
-    target_path = Column(Text)
-    repository_url = Column(Text)
-    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
-
-    @declared_attr
-    def properties(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
-
     # region foreign_keys
 
     @declared_attr
@@ -1565,6 +1786,44 @@ class ArtifactBase(InstanceModelMixin):
 
     # endregion
 
+    # region association proxies
+
+    # endregion
+
+    # region one_to_one relationships
+
+    # endregion
+
+    # region one_to_many relationships
+
+    # endregion
+
+    # region many_to_one relationships
+    @declared_attr
+    def node(cls):
+        return relationship.many_to_one(cls, 'node')
+
+    @declared_attr
+    def artifact_template(cls):
+        return relationship.many_to_one(cls, 'artifact_template')
+
+    @declared_attr
+    def type(cls):
+        return relationship.many_to_one(cls, 'type', back_populates=relationship.NO_BACK_POP)
+    # endregion
+
+    # region many_to_many relationships
+    @declared_attr
+    def properties(cls):
+        return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name')
+    # endregion
+
+    description = Column(Text)
+    source_path = Column(Text)
+    target_path = Column(Text)
+    repository_url = Column(Text)
+    repository_credential = Column(modeling_types.StrictDict(basestring, basestring))
+
     @property
     def as_raw(self):
         return collections.OrderedDict((


[5/5] incubator-ariatosca git commit: ARIA-86-Create-a-basic-Hello-World-blueprint-example

Posted by mx...@apache.org.
ARIA-86-Create-a-basic-Hello-World-blueprint-example


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

Branch: refs/heads/ARIA-86-Create-a-basic-Hello-World-blueprint-example
Commit: 1f7084848d2b903fa02827f6834eac51c05cb34e
Parents: 4400e30
Author: max-orlov <ma...@gigaspaces.com>
Authored: Thu Mar 30 17:29:17 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Thu Mar 30 17:37:45 2017 +0300

----------------------------------------------------------------------
 examples/hello-world/helloworld.yaml      |  33 ++++++++++++++++
 examples/hello-world/images/aria-logo.png | Bin 0 -> 23601 bytes
 examples/hello-world/index.html           |  14 +++++++
 examples/hello-world/scripts/configure.sh |  23 +++++++++++
 examples/hello-world/scripts/start.sh     |  52 +++++++++++++++++++++++++
 examples/hello-world/scripts/stop.sh      |  15 +++++++
 6 files changed, 137 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1f708484/examples/hello-world/helloworld.yaml
----------------------------------------------------------------------
diff --git a/examples/hello-world/helloworld.yaml b/examples/hello-world/helloworld.yaml
new file mode 100644
index 0000000..73b6bc0
--- /dev/null
+++ b/examples/hello-world/helloworld.yaml
@@ -0,0 +1,33 @@
+tosca_definitions_version: tosca_simple_profile_for_nfv_1_0
+
+node_types:
+  web_app:
+    derived_from: tosca.nodes.WebApplication
+    properties:
+      port:
+        type: integer
+        default: 8080
+    interfaces:
+      Standard:
+        configure: {}
+        start: {}
+        stop: {}
+
+topology_template:
+
+  node_templates:
+    web_server:
+      type: tosca.nodes.WebServer
+
+    web_app:
+      type: web_app
+      properties:
+        port: 9090
+      requirements:
+        - host: web_server
+      interfaces:
+        Standard:
+          configure: scripts/configure.sh
+          start: scripts/start.sh
+          stop: scripts/stop.sh
+

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1f708484/examples/hello-world/images/aria-logo.png
----------------------------------------------------------------------
diff --git a/examples/hello-world/images/aria-logo.png b/examples/hello-world/images/aria-logo.png
new file mode 100644
index 0000000..3505844
Binary files /dev/null and b/examples/hello-world/images/aria-logo.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1f708484/examples/hello-world/index.html
----------------------------------------------------------------------
diff --git a/examples/hello-world/index.html b/examples/hello-world/index.html
new file mode 100644
index 0000000..dd3dd58
--- /dev/null
+++ b/examples/hello-world/index.html
@@ -0,0 +1,14 @@
+<html>
+    <header>
+        <title>Cloudify Hello World</title>
+    </header>
+<body>
+    <h1>Hello, World!</h1>
+    <p>
+        blueprint_id = {{ ctx.service_template.name }}<br/>
+        deployment_id = {{ ctx.service.name }}<br/>
+        node_id = {{ ctx.node.name }}
+    </p>
+    <img src="aria-logo.png">
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1f708484/examples/hello-world/scripts/configure.sh
----------------------------------------------------------------------
diff --git a/examples/hello-world/scripts/configure.sh b/examples/hello-world/scripts/configure.sh
new file mode 100755
index 0000000..b55ec17
--- /dev/null
+++ b/examples/hello-world/scripts/configure.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+TEMP_DIR="/tmp"
+PYTHON_FILE_SERVER_ROOT=${TEMP_DIR}/python-simple-http-webserver
+if [ -d ${PYTHON_FILE_SERVER_ROOT} ]; then
+	echo "Removing file server root folder ${PYTHON_FILE_SERVER_ROOT}"
+	rm -rf ${PYTHON_FILE_SERVER_ROOT}
+fi
+ctx logger info "Creating HTTP server root directory at ${PYTHON_FILE_SERVER_ROOT}"
+
+mkdir -p ${PYTHON_FILE_SERVER_ROOT}
+
+cd ${PYTHON_FILE_SERVER_ROOT}
+
+index_path="index.html"
+image_path="images/aria-logo.png"
+
+ctx logger info "Downloading blueprint resources..."
+ctx download-resource-and-render ${PYTHON_FILE_SERVER_ROOT}/index.html ${index_path}
+ctx download-resource ${PYTHON_FILE_SERVER_ROOT}/aria-logo.png ${image_path}
+

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1f708484/examples/hello-world/scripts/start.sh
----------------------------------------------------------------------
diff --git a/examples/hello-world/scripts/start.sh b/examples/hello-world/scripts/start.sh
new file mode 100755
index 0000000..96298c5
--- /dev/null
+++ b/examples/hello-world/scripts/start.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+set -e
+
+TEMP_DIR="/tmp"
+PYTHON_FILE_SERVER_ROOT=${TEMP_DIR}/python-simple-http-webserver
+PID_FILE="server.pid"
+
+ctx logger info "Starting HTTP server from ${PYTHON_FILE_SERVER_ROOT}"
+
+port=$(ctx node properties port)
+
+cd ${PYTHON_FILE_SERVER_ROOT}
+ctx logger info "Starting SimpleHTTPServer"
+nohup python -m SimpleHTTPServer ${port} > /dev/null 2>&1 &
+echo $! > ${PID_FILE}
+
+ctx logger info "Waiting for server to launch on port ${port}"
+url="http://localhost:${port}"
+
+server_is_up() {
+	if which wget >/dev/null; then
+		if wget $url >/dev/null; then
+			return 0
+		fi
+	elif which curl >/dev/null; then
+		if curl $url >/dev/null; then
+			return 0
+		fi
+	else
+		ctx logger error "Both curl, wget were not found in path"
+		exit 1
+	fi
+	return 1
+}
+
+STARTED=false
+for i in $(seq 1 15)
+do
+	if server_is_up; then
+		ctx logger info "Server is up."
+		STARTED=true
+    	break
+	else
+		ctx logger info "Server not up. waiting 1 second."
+		sleep 1
+	fi
+done
+if [ ${STARTED} = false ]; then
+	ctx logger error "Failed starting web server in 15 seconds."
+	exit 1
+fi

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/1f708484/examples/hello-world/scripts/stop.sh
----------------------------------------------------------------------
diff --git a/examples/hello-world/scripts/stop.sh b/examples/hello-world/scripts/stop.sh
new file mode 100755
index 0000000..5461caf
--- /dev/null
+++ b/examples/hello-world/scripts/stop.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+TEMP_DIR="/tmp"
+PYTHON_FILE_SERVER_ROOT=${TEMP_DIR}/python-simple-http-webserver
+PID_FILE="server.pid"
+
+PID=`cat ${PYTHON_FILE_SERVER_ROOT}/${PID_FILE}`
+
+ctx logger info "Shutting down file server. pid = ${PID}"
+kill -9 ${PID} || exit $?
+
+ctx logger info "Deleting file server root directory (${PYTHON_FILE_SERVER_ROOT})"
+rm -rf ${PYTHON_FILE_SERVER_ROOT}