ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mxm...@apache.org
Subject incubator-ariatosca git commit: ARIA-52-Support-order-management-in-relationships
Date Sun, 08 Jan 2017 13:57:12 GMT
Repository: incubator-ariatosca
Updated Branches:
  refs/heads/master 3caf17717 -> 17d07ed97


ARIA-52-Support-order-management-in-relationships


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

Branch: refs/heads/master
Commit: 17d07ed972341dd2780067316732f4d789e846ed
Parents: 3caf177
Author: mxmrlv <mxmrlv@gmail.com>
Authored: Tue Dec 27 16:42:57 2016 +0200
Committer: mxmrlv <mxmrlv@gmail.com>
Committed: Sun Jan 8 15:34:46 2017 +0200

----------------------------------------------------------------------
 aria/storage/base_model.py          |  73 ++++++++++++++----
 aria/storage/sql_mapi.py            |   2 +-
 aria/storage/structure.py           |  10 ++-
 tests/storage/test_model_storage.py | 128 ++++++++++++++++++++++++++++++-
 4 files changed, 194 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/17d07ed9/aria/storage/base_model.py
----------------------------------------------------------------------
diff --git a/aria/storage/base_model.py b/aria/storage/base_model.py
index 418d3b6..a2bbb60 100644
--- a/aria/storage/base_model.py
+++ b/aria/storage/base_model.py
@@ -51,6 +51,7 @@ from sqlalchemy import (
     Float,
     orm,
 )
+from sqlalchemy.ext.orderinglist import ordering_list
 
 from ..orchestrator.exceptions import TaskAbortException, TaskRetryException
 from .structure import ModelMixin
@@ -415,7 +416,14 @@ class RelationshipBase(ModelMixin):
     """
     __tablename__ = 'relationships'
 
-    _private_fields = ['source_node_fk', 'target_node_fk']
+    _private_fields = ['source_node_fk', 'target_node_fk', 'source_position', 'target_position']
+
+    source_position = Column(Integer)
+    target_position = Column(Integer)
+
+    @declared_attr
+    def deployment_id(self):
+        return association_proxy('source_node', 'deployment_id')
 
     @declared_attr
     def source_node_fk(cls):
@@ -423,8 +431,14 @@ class RelationshipBase(ModelMixin):
 
     @declared_attr
     def source_node(cls):
-        return cls.one_to_many_relationship('source_node_fk',
-                                            backreference='outbound_relationships')
+        return cls.one_to_many_relationship(
+            'source_node_fk',
+            backreference='outbound_relationships',
+            backref_kwargs=dict(
+                order_by=cls.source_position,
+                collection_class=ordering_list('source_position', count_from=0)
+            )
+        )
 
     @declared_attr
     def source_name(cls):
@@ -432,11 +446,18 @@ class RelationshipBase(ModelMixin):
 
     @declared_attr
     def target_node_fk(cls):
-        return cls.foreign_key(NodeBase)
+        return cls.foreign_key(NodeBase, nullable=True)
 
     @declared_attr
     def target_node(cls):
-        return cls.one_to_many_relationship('target_node_fk', backreference='inbound_relationships')
+        return cls.one_to_many_relationship(
+            'target_node_fk',
+            backreference='inbound_relationships',
+            backref_kwargs=dict(
+                order_by=cls.target_position,
+                collection_class=ordering_list('target_position', count_from=0)
+            )
+        )
 
     @declared_attr
     def target_name(cls):
@@ -515,35 +536,60 @@ class RelationshipInstanceBase(ModelMixin):
     __tablename__ = 'relationship_instances'
     _private_fields = ['relationship_storage_fk',
                        'source_node_instance_fk',
-                       'target_node_instance_fk']
+                       'target_node_instance_fk',
+                       'source_position',
+                       'target_position']
+
+    source_position = Column(Integer)
+    target_position = Column(Integer)
 
     @declared_attr
     def source_node_instance_fk(cls):
-        return cls.foreign_key(NodeInstanceBase)
+        return cls.foreign_key(NodeInstanceBase, nullable=True)
 
     @declared_attr
     def source_node_instance(cls):
-        return cls.one_to_many_relationship('source_node_instance_fk',
-                                            backreference='outbound_relationship_instances')
+        return cls.one_to_many_relationship(
+            'source_node_instance_fk',
+            backreference='outbound_relationship_instances',
+            backref_kwargs=dict(
+                order_by=cls.source_position,
+                collection_class=ordering_list('source_position', count_from=0)
+            )
+        )
 
     @declared_attr
     def source_node_instance_name(cls):
+        return association_proxy('source_node_instance', 'node_{0}'.format(cls.name_column_name()))
+
+    @declared_attr
+    def source_node_name(cls):
         return association_proxy('source_node_instance', cls.name_column_name())
 
     @declared_attr
     def target_node_instance_fk(cls):
-        return cls.foreign_key(NodeInstanceBase)
+        return cls.foreign_key(NodeInstanceBase, nullable=True)
 
     @declared_attr
     def target_node_instance(cls):
-        return cls.one_to_many_relationship('target_node_instance_fk',
-                                            backreference='inbound_relationship_instances')
+        return cls.one_to_many_relationship(
+            'target_node_instance_fk',
+            backreference='inbound_relationship_instances',
+            backref_kwargs=dict(
+                order_by=cls.target_position,
+                collection_class=ordering_list('target_position', count_from=0)
+            )
+        )
 
     @declared_attr
     def target_node_instance_name(cls):
         return association_proxy('target_node_instance', cls.name_column_name())
 
     @declared_attr
+    def target_node_name(cls):
+        return association_proxy('target_node_instance', 'node_{0}'.format(cls.name_column_name()))
+
+    @declared_attr
     def relationship_fk(cls):
         return cls.foreign_key(RelationshipBase)
 
@@ -556,6 +602,7 @@ class RelationshipInstanceBase(ModelMixin):
         return association_proxy('relationship', cls.name_column_name())
 
 
+
 class PluginBase(ModelMixin):
     """
     Plugin model representation.
@@ -658,7 +705,7 @@ class TaskBase(ModelMixin):
 
     INFINITE_RETRIES = -1
 
-    status = Column(Enum(*STATES), name='status', default=PENDING)
+    status = Column(Enum(*STATES, name='status'), default=PENDING)
 
     due_at = Column(DateTime, default=datetime.utcnow)
     started_at = Column(DateTime, default=None)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/17d07ed9/aria/storage/sql_mapi.py
----------------------------------------------------------------------
diff --git a/aria/storage/sql_mapi.py b/aria/storage/sql_mapi.py
index cde40c2..809f677 100644
--- a/aria/storage/sql_mapi.py
+++ b/aria/storage/sql_mapi.py
@@ -46,7 +46,7 @@ class SQLAlchemyModelAPI(api.ModelAPI):
 
         if not result:
             raise exceptions.StorageError(
-                'Requested {0} with ID `{1}` was not found'
+                'Requested `{0}` with ID `{1}` was not found'
                 .format(self.model_cls.__name__, entry_id)
             )
         return result

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/17d07ed9/aria/storage/structure.py
----------------------------------------------------------------------
diff --git a/aria/storage/structure.py b/aria/storage/structure.py
index 431633b..fa592ac 100644
--- a/aria/storage/structure.py
+++ b/aria/storage/structure.py
@@ -80,7 +80,9 @@ class ModelMixin(object):
     @classmethod
     def one_to_many_relationship(cls,
                                  foreign_key_column,
-                                 backreference=None):
+                                 backreference=None,
+                                 backref_kwargs=None,
+                                 **kwargs):
         """Return a one-to-many SQL relationship object
         Meant to be used from inside the *child* object
 
@@ -89,6 +91,7 @@ class ModelMixin(object):
         :param foreign_key_column: The column of the foreign key (from the child table)
         :param backreference: The name to give to the reference to the child (on the parent
table)
         """
+        backref_kwargs = backref_kwargs or {}
         parent_table = cls._get_cls_by_tablename(
             getattr(cls, foreign_key_column).__remote_table_name)
         primaryjoin_str = '{parent_class_name}.{parent_unique_id} == ' \
@@ -105,7 +108,8 @@ class ModelMixin(object):
             foreign_keys=[getattr(cls, foreign_key_column)],
             # The following line make sure that when the *parent* is
             # deleted, all its connected children are deleted as well
-            backref=backref(backreference or cls.__tablename__, cascade='all'),
+            backref=backref(backreference or cls.__tablename__, cascade='all', **backref_kwargs),
+            **kwargs
         )
 
     @classmethod
@@ -145,6 +149,8 @@ class ModelMixin(object):
                 field_value = list(field_value)
             elif isinstance(field_value, dict):
                 field_value = dict(field_value)
+            elif isinstance(field_value, ModelMixin):
+                field_value = field_value.to_dict()
             res[field] = field_value
 
         return res

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/17d07ed9/tests/storage/test_model_storage.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_model_storage.py b/tests/storage/test_model_storage.py
index 6f9527e..0e8d1a0 100644
--- a/tests/storage/test_model_storage.py
+++ b/tests/storage/test_model_storage.py
@@ -27,7 +27,11 @@ from aria.storage import (
 )
 from aria import application_model_storage
 from ..storage import get_sqlite_api_kwargs, release_sqlite_storage
-from ..mock import context as mock_context
+from ..mock import (
+    context as mock_context,
+    models,
+    operations
+)
 
 
 class MockModel(model.DeclarativeBase, structure.ModelMixin): #pylint: disable=abstract-method
@@ -46,6 +50,11 @@ def storage():
     release_sqlite_storage(base_storage)
 
 
+@pytest.fixture
+def context():
+    return mock_context.simple(get_sqlite_api_kwargs())
+
+
 @pytest.fixture(scope='module', autouse=True)
 def module_cleanup():
     model.DeclarativeBase.metadata.remove(MockModel.__table__)  #pylint: disable=no-member
@@ -104,8 +113,7 @@ def test_inner_list_update(storage):
     assert storage_mm.model_list[0] == 'new_value'
 
 
-def test_model_to_dict():
-    context = mock_context.simple(get_sqlite_api_kwargs())
+def test_model_to_dict(context):
     deployment = context.deployment
     deployment_dict = deployment.to_dict()
 
@@ -144,3 +152,117 @@ def test_application_storage_factory():
     assert storage.execution
 
     release_sqlite_storage(storage)
+
+
+def test_relationship_model_ordering(context):
+    deployment = context.model.deployment.get_by_name(models.DEPLOYMENT_NAME)
+    source_node = context.model.node.get_by_name(models.DEPENDENT_NODE_NAME)
+    source_node_instance = context.model.node_instance.get_by_name(
+        models.DEPENDENT_NODE_INSTANCE_NAME)
+    target_node = context.model.node.get_by_name(models.DEPENDENCY_NODE_NAME)
+    target_node_instance = context.model.node_instance.get_by_name(
+        models.DEPENDENCY_NODE_INSTANCE_NAME)
+    new_node = model.Node(
+        name='new_node',
+        type='test_node_type',
+        type_hierarchy=[],
+        number_of_instances=1,
+        planned_number_of_instances=1,
+        deploy_number_of_instances=1,
+        properties={},
+        operations=dict((key, {}) for key in operations.NODE_OPERATIONS),
+        min_number_of_instances=1,
+        max_number_of_instances=1,
+        deployment=deployment
+    )
+    source_to_new_relationship = model.Relationship(
+        source_node=source_node,
+        target_node=new_node,
+        source_interfaces={},
+        source_operations=dict((key, {}) for key in operations.RELATIONSHIP_OPERATIONS),
+        target_interfaces={},
+        target_operations=dict((key, {}) for key in operations.RELATIONSHIP_OPERATIONS),
+        type='rel_type',
+        type_hierarchy=[],
+        properties={},
+    )
+    new_node_instance = model.NodeInstance(
+        name='new_node_instance',
+        runtime_properties={},
+        version=None,
+        node=new_node,
+        state='',
+        scaling_groups=[]
+    )
+    source_to_new_relationship_instance = model.RelationshipInstance(
+        relationship=source_to_new_relationship,
+        source_node_instance=source_node_instance,
+        target_node_instance=new_node_instance,
+    )
+
+    new_to_target_relationship = model.Relationship(
+        source_node=new_node,
+        target_node=target_node,
+        source_interfaces={},
+        source_operations=dict((key, {}) for key in operations.RELATIONSHIP_OPERATIONS),
+        target_interfaces={},
+        target_operations=dict((key, {}) for key in operations.RELATIONSHIP_OPERATIONS),
+        type='rel_type',
+        type_hierarchy=[],
+        properties={},
+    )
+    new_to_target_relationship_instance = model.RelationshipInstance(
+        relationship=new_to_target_relationship,
+        source_node_instance=new_node_instance,
+        target_node_instance=target_node_instance,
+    )
+
+
+    context.model.node.put(new_node)
+    context.model.node_instance.put(new_node_instance)
+    context.model.relationship.put(source_to_new_relationship)
+    context.model.relationship.put(new_to_target_relationship)
+    context.model.relationship_instance.put(source_to_new_relationship_instance)
+    context.model.relationship_instance.put(new_to_target_relationship_instance)
+
+    def flip_and_assert(node_instance, direction):
+        """
+        Reversed the order of relationships and assert effects took place.
+        :param node_instance: the node instance to operatate on
+        :param direction: the type of relationships to flip (inbound/outbount)
+        :return:
+        """
+        assert direction in ('inbound', 'outbound')
+
+        relationships = getattr(node_instance.node, direction + '_relationships')
+        relationship_instances = getattr(node_instance, direction + '_relationship_instances')
+        assert len(relationships) == 2
+        assert len(relationship_instances) == 2
+
+        first_rel, second_rel = relationships
+        first_rel_instance, second_rel_instance = relationship_instances
+        assert getattr(first_rel, relationships.ordering_attr) == 0
+        assert getattr(second_rel, relationships.ordering_attr) == 1
+        assert getattr(first_rel_instance, relationship_instances.ordering_attr) == 0
+        assert getattr(second_rel_instance, relationship_instances.ordering_attr) == 1
+
+        reversed_relationships = list(reversed(relationships))
+        reversed_relationship_instances = list(reversed(relationship_instances))
+
+        assert relationships != reversed_relationships
+        assert relationship_instances != reversed_relationship_instances
+
+        relationships[:] = reversed_relationships
+        relationship_instances[:] = reversed_relationship_instances
+        context.model.node_instance.update(node_instance)
+
+        assert relationships == reversed_relationships
+        assert relationship_instances == reversed_relationship_instances
+
+        assert getattr(first_rel, relationships.ordering_attr) == 1
+        assert getattr(second_rel, relationships.ordering_attr) == 0
+        assert getattr(first_rel_instance, relationship_instances.ordering_attr) == 1
+        assert getattr(second_rel_instance, relationship_instances.ordering_attr) == 0
+
+    flip_and_assert(source_node_instance, 'outbound')
+    flip_and_assert(target_node_instance, 'inbound')


Mime
View raw message