http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/aria/storage/base_model.py
----------------------------------------------------------------------
diff --git a/aria/storage/base_model.py b/aria/storage/base_model.py
index 65344a6..d041a38 100644
--- a/aria/storage/base_model.py
+++ b/aria/storage/base_model.py
@@ -1,743 +1,743 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Aria's storage.models module
-Path: aria.storage.models
-
-models module holds aria's models.
-
-classes:
-    * Field - represents a single field.
-    * IterField - represents an iterable field.
-    * Model - abstract model implementation.
-    * Snapshot - snapshots implementation model.
-    * Deployment - deployment implementation model.
-    * DeploymentUpdateStep - deployment update step implementation model.
-    * DeploymentUpdate - deployment update implementation model.
-    * DeploymentModification - deployment modification implementation model.
-    * Execution - execution implementation model.
-    * Node - node implementation model.
-    * Relationship - relationship implementation model.
-    * NodeInstance - node instance implementation model.
-    * RelationshipInstance - relationship instance implementation model.
-    * Plugin - plugin implementation model.
-"""
-from collections import namedtuple
-from datetime import datetime
-
-from sqlalchemy.ext.associationproxy import association_proxy
-from sqlalchemy.ext.declarative import declared_attr
-from sqlalchemy import (
-    Column,
-    Integer,
-    Text,
-    DateTime,
-    Boolean,
-    Enum,
-    String,
-    Float,
-    orm,
-)
-from sqlalchemy.ext.orderinglist import ordering_list
-
-from ..orchestrator.exceptions import TaskAbortException, TaskRetryException
-from .structure import ModelMixin
-from .type import (
-    List,
-    Dict
-)
-
-__all__ = (
-    'BlueprintBase',
-    'DeploymentBase',
-    'DeploymentUpdateStepBase',
-    'DeploymentUpdateBase',
-    'DeploymentModificationBase',
-    'ExecutionBase',
-    'NodeBase',
-    'RelationshipBase',
-    'NodeInstanceBase',
-    'RelationshipInstanceBase',
-    'PluginBase',
-    'TaskBase'
-)
-
-#pylint: disable=no-self-argument, abstract-method
-
-
-class BlueprintBase(ModelMixin):
-    """
-    Blueprint model representation.
-    """
-    __tablename__ = 'blueprints'
-
-    created_at = Column(DateTime, nullable=False, index=True)
-    main_file_name = Column(Text, nullable=False)
-    plan = Column(Dict, nullable=False)
-    updated_at = Column(DateTime)
-    description = Column(Text)
-
-
-class DeploymentBase(ModelMixin):
-    """
-    Deployment model representation.
-    """
-    __tablename__ = 'deployments'
-
-    _private_fields = ['blueprint_fk']
-
-    created_at = Column(DateTime, nullable=False, index=True)
-    description = Column(Text)
-    inputs = Column(Dict)
-    groups = Column(Dict)
-    permalink = Column(Text)
-    policy_triggers = Column(Dict)
-    policy_types = Column(Dict)
-    outputs = Column(Dict)
-    scaling_groups = Column(Dict)
-    updated_at = Column(DateTime)
-    workflows = Column(Dict)
-
-    @declared_attr
-    def blueprint_fk(cls):
-        return cls.foreign_key(BlueprintBase, nullable=False)
-
-    @declared_attr
-    def blueprint(cls):
-        return cls.many_to_one_relationship('blueprint_fk')
-
-    @declared_attr
-    def blueprint_name(cls):
-        return association_proxy('blueprint', cls.name_column_name())
-
-
-class ExecutionBase(ModelMixin):
-    """
-    Execution model representation.
-    """
-    # Needed only for pylint. the id will be populated by sqlalcehmy and the 
proper column.
-    __tablename__ = 'executions'
-    _private_fields = ['deployment_fk']
-
-    TERMINATED = 'terminated'
-    FAILED = 'failed'
-    CANCELLED = 'cancelled'
-    PENDING = 'pending'
-    STARTED = 'started'
-    CANCELLING = 'cancelling'
-    FORCE_CANCELLING = 'force_cancelling'
-
-    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],
-        STARTED: END_STATES + [CANCELLING],
-        CANCELLING: END_STATES + [FORCE_CANCELLING]
-    }
-
-    @orm.validates('status')
-    def validate_status(self, key, value):
-        """Validation function that verifies execution status transitions are 
OK"""
-        try:
-            current_status = getattr(self, key)
-        except AttributeError:
-            return
-        valid_transitions = self.VALID_TRANSITIONS.get(current_status, [])
-        if all([current_status is not None,
-                current_status != value,
-                value not in valid_transitions]):
-            raise ValueError('Cannot change execution status from {current} to 
{new}'.format(
-                current=current_status,
-                new=value))
-        return value
-
-    created_at = Column(DateTime, index=True)
-    started_at = Column(DateTime, nullable=True, index=True)
-    ended_at = Column(DateTime, nullable=True, index=True)
-    error = Column(Text, nullable=True)
-    is_system_workflow = Column(Boolean, nullable=False, default=False)
-    parameters = Column(Dict)
-    status = Column(Enum(*STATES, name='execution_status'), default=PENDING)
-    workflow_name = Column(Text)
-
-    @declared_attr
-    def blueprint(cls):
-        return association_proxy('deployment', 'blueprint')
-
-    @declared_attr
-    def deployment_fk(cls):
-        return cls.foreign_key(DeploymentBase, nullable=True)
-
-    @declared_attr
-    def deployment(cls):
-        return cls.many_to_one_relationship('deployment_fk')
-
-    @declared_attr
-    def deployment_name(cls):
-        return association_proxy('deployment', cls.name_column_name())
-
-    @declared_attr
-    def blueprint_name(cls):
-        return association_proxy('deployment', 'blueprint_name')
-
-    def __str__(self):
-        return '<{0} id=`{1}` (status={2})>'.format(
-            self.__class__.__name__,
-            getattr(self, self.name_column_name()),
-            self.status
-        )
-
-
-class DeploymentUpdateBase(ModelMixin):
-    """
-    Deployment update model representation.
-    """
-    # Needed only for pylint. the id will be populated by sqlalcehmy and the 
proper column.
-    steps = None
-
-    __tablename__ = 'deployment_updates'
-
-    _private_fields = ['execution_fk', 'deployment_fk']
-
-    created_at = Column(DateTime, nullable=False, index=True)
-    deployment_plan = Column(Dict, nullable=False)
-    deployment_update_node_instances = Column(Dict)
-    deployment_update_deployment = Column(Dict)
-    deployment_update_nodes = Column(List)
-    modified_entity_ids = Column(Dict)
-    state = Column(Text)
-
-    @declared_attr
-    def execution_fk(cls):
-        return cls.foreign_key(ExecutionBase, nullable=True)
-
-    @declared_attr
-    def execution(cls):
-        return cls.many_to_one_relationship('execution_fk')
-
-    @declared_attr
-    def execution_name(cls):
-        return association_proxy('execution', cls.name_column_name())
-
-    @declared_attr
-    def deployment_fk(cls):
-        return cls.foreign_key(DeploymentBase)
-
-    @declared_attr
-    def deployment(cls):
-        return cls.many_to_one_relationship('deployment_fk')
-
-    @declared_attr
-    def deployment_name(cls):
-        return association_proxy('deployment', cls.name_column_name())
-
-    def to_dict(self, suppress_error=False, **kwargs):
-        dep_update_dict = super(DeploymentUpdateBase, 
self).to_dict(suppress_error)     #pylint: disable=no-member
-        # Taking care of the fact the DeploymentSteps are _BaseModels
-        dep_update_dict['steps'] = [step.to_dict() for step in self.steps]
-        return dep_update_dict
-
-
-class DeploymentUpdateStepBase(ModelMixin):
-    """
-    Deployment update step model representation.
-    """
-    # Needed only for pylint. the id will be populated by sqlalcehmy and the 
proper column.
-    __tablename__ = 'deployment_update_steps'
-    _private_fields = ['deployment_update_fk']
-
-    _action_types = namedtuple('ACTION_TYPES', 'ADD, REMOVE, MODIFY')
-    ACTION_TYPES = _action_types(ADD='add', REMOVE='remove', MODIFY='modify')
-    _entity_types = namedtuple(
-        'ENTITY_TYPES',
-        'NODE, RELATIONSHIP, PROPERTY, OPERATION, WORKFLOW, OUTPUT, 
DESCRIPTION, GROUP, '
-        'POLICY_TYPE, POLICY_TRIGGER, PLUGIN')
-    ENTITY_TYPES = _entity_types(
-        NODE='node',
-        RELATIONSHIP='relationship',
-        PROPERTY='property',
-        OPERATION='operation',
-        WORKFLOW='workflow',
-        OUTPUT='output',
-        DESCRIPTION='description',
-        GROUP='group',
-        POLICY_TYPE='policy_type',
-        POLICY_TRIGGER='policy_trigger',
-        PLUGIN='plugin'
-    )
-
-    action = Column(Enum(*ACTION_TYPES, name='action_type'), nullable=False)
-    entity_id = Column(Text, nullable=False)
-    entity_type = Column(Enum(*ENTITY_TYPES, name='entity_type'), 
nullable=False)
-
-    @declared_attr
-    def deployment_update_fk(cls):
-        return cls.foreign_key(DeploymentUpdateBase)
-
-    @declared_attr
-    def deployment_update(cls):
-        return cls.many_to_one_relationship('deployment_update_fk', 
backreference='steps')
-
-    @declared_attr
-    def deployment_update_name(cls):
-        return association_proxy('deployment_update', cls.name_column_name())
-
-    def __hash__(self):
-        return hash((getattr(self, self.id_column_name()), self.entity_id))
-
-    def __lt__(self, other):
-        """
-        the order is 'remove' < 'modify' < 'add'
-        :param other:
-        :return:
-        """
-        if not isinstance(other, self.__class__):
-            return not self >= other
-
-        if self.action != other.action:
-            if self.action == 'remove':
-                return_value = True
-            elif self.action == 'add':
-                return_value = False
-            else:
-                return_value = other.action == 'add'
-            return return_value
-
-        if self.action == 'add':
-            return self.entity_type == 'node' and other.entity_type == 
'relationship'
-        if self.action == 'remove':
-            return self.entity_type == 'relationship' and other.entity_type == 
'node'
-        return False
-
-
-class DeploymentModificationBase(ModelMixin):
-    """
-    Deployment modification model representation.
-    """
-    __tablename__ = 'deployment_modifications'
-    _private_fields = ['deployment_fk']
-
-    STARTED = 'started'
-    FINISHED = 'finished'
-    ROLLEDBACK = 'rolledback'
-
-    STATES = [STARTED, FINISHED, ROLLEDBACK]
-    END_STATES = [FINISHED, ROLLEDBACK]
-
-    context = Column(Dict)
-    created_at = Column(DateTime, nullable=False, index=True)
-    ended_at = Column(DateTime, index=True)
-    modified_nodes = Column(Dict)
-    node_instances = Column(Dict)
-    status = Column(Enum(*STATES, name='deployment_modification_status'))
-
-    @declared_attr
-    def deployment_fk(cls):
-        return cls.foreign_key(DeploymentBase)
-
-    @declared_attr
-    def deployment(cls):
-        return cls.many_to_one_relationship('deployment_fk', 
backreference='modifications')
-
-    @declared_attr
-    def deployment_name(cls):
-        return association_proxy('deployment', cls.name_column_name())
-
-
-class NodeBase(ModelMixin):
-    """
-    Node model representation.
-    """
-    __tablename__ = 'nodes'
-
-    # See base class for an explanation on these properties
-    is_id_unique = False
-
-    _private_fields = ['blueprint_fk', 'host_fk']
-
-    @declared_attr
-    def host_fk(cls):
-        return cls.foreign_key(NodeBase, nullable=True)
-
-    @declared_attr
-    def host(cls):
-        return cls.relationship_to_self('host_fk')
-
-    @declared_attr
-    def host_name(cls):
-        return association_proxy('host', cls.name_column_name())
-
-    @declared_attr
-    def deployment_fk(cls):
-        return cls.foreign_key(DeploymentBase)
-
-    @declared_attr
-    def deployment(cls):
-        return cls.many_to_one_relationship('deployment_fk')
-
-    @declared_attr
-    def deployment_name(cls):
-        return association_proxy('deployment', cls.name_column_name())
-
-    @declared_attr
-    def blueprint_name(cls):
-        return association_proxy('deployment', 
'blueprint_{0}'.format(cls.name_column_name()))
-
-    deploy_number_of_instances = Column(Integer, nullable=False)
-    max_number_of_instances = Column(Integer, nullable=False)
-    min_number_of_instances = Column(Integer, nullable=False)
-    number_of_instances = Column(Integer, nullable=False)
-    planned_number_of_instances = Column(Integer, nullable=False)
-    plugins = Column(List)
-    properties = Column(Dict)
-    operations = Column(Dict)
-    type = Column(Text, nullable=False, index=True)
-    type_hierarchy = Column(List)
-
-
-class RelationshipBase(ModelMixin):
-    """
-    Relationship model representation.
-    """
-    __tablename__ = 'relationships'
-
-    _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):
-        return cls.foreign_key(NodeBase)
-
-    @declared_attr
-    def source_node(cls):
-        return cls.many_to_one_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):
-        return association_proxy('source_node', cls.name_column_name())
-
-    @declared_attr
-    def target_node_fk(cls):
-        return cls.foreign_key(NodeBase, nullable=True)
-
-    @declared_attr
-    def target_node(cls):
-        return cls.many_to_one_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):
-        return association_proxy('target_node', cls.name_column_name())
-
-    source_interfaces = Column(Dict)
-    source_operations = Column(Dict, nullable=False)
-    target_interfaces = Column(Dict)
-    target_operations = Column(Dict, nullable=False)
-    type = Column(String, nullable=False)
-    type_hierarchy = Column(List)
-    properties = Column(Dict)
-
-
-class NodeInstanceBase(ModelMixin):
-    """
-    Node instance model representation.
-    """
-    __tablename__ = 'node_instances'
-    _private_fields = ['node_fk', 'host_fk']
-
-    runtime_properties = Column(Dict)
-    scaling_groups = Column(List)
-    state = Column(Text, nullable=False)
-    version = Column(Integer, default=1)
-
-    @declared_attr
-    def host_fk(cls):
-        return cls.foreign_key(NodeInstanceBase, nullable=True)
-
-    @declared_attr
-    def host(cls):
-        return cls.relationship_to_self('host_fk')
-
-    @declared_attr
-    def host_name(cls):
-        return association_proxy('host', cls.name_column_name())
-
-    @declared_attr
-    def deployment(cls):
-        return association_proxy('node', 'deployment')
-
-    @declared_attr
-    def deployment_name(cls):
-        return association_proxy('node', 'deployment_name')
-
-    @declared_attr
-    def node_fk(cls):
-        return cls.foreign_key(NodeBase, nullable=True)
-
-    @declared_attr
-    def node(cls):
-        return cls.many_to_one_relationship('node_fk')
-
-    @declared_attr
-    def node_name(cls):
-        return association_proxy('node', cls.name_column_name())
-
-    @property
-    def ip(self):
-        if not self.host_fk:
-            return None
-        host_node_instance = self.host
-        if 'ip' in host_node_instance.runtime_properties:  # pylint: 
disable=no-member
-            return host_node_instance.runtime_properties['ip']  # pylint: 
disable=no-member
-        host_node = host_node_instance.node  # pylint: disable=no-member
-        if 'ip' in host_node.properties:
-            return host_node.properties['ip']
-        return None
-
-
-class RelationshipInstanceBase(ModelMixin):
-    """
-    Relationship instance model representation.
-    """
-    __tablename__ = 'relationship_instances'
-    _private_fields = ['relationship_storage_fk',
-                       'source_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, nullable=True)
-
-    @declared_attr
-    def source_node_instance(cls):
-        return cls.many_to_one_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, nullable=True)
-
-    @declared_attr
-    def target_node_instance(cls):
-        return cls.many_to_one_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)
-
-    @declared_attr
-    def relationship(cls):
-        return cls.many_to_one_relationship('relationship_fk')
-
-    @declared_attr
-    def relationship_name(cls):
-        return association_proxy('relationship', cls.name_column_name())
-
-
-class PluginBase(ModelMixin):
-    """
-    Plugin model representation.
-    """
-    __tablename__ = 'plugins'
-
-    archive_name = Column(Text, nullable=False, index=True)
-    distribution = Column(Text)
-    distribution_release = Column(Text)
-    distribution_version = Column(Text)
-    package_name = Column(Text, nullable=False, index=True)
-    package_source = Column(Text)
-    package_version = Column(Text)
-    supported_platform = Column(Text)
-    supported_py_versions = Column(List)
-    uploaded_at = Column(DateTime, nullable=False, index=True)
-    wheels = Column(List, nullable=False)
-
-
-class TaskBase(ModelMixin):
-    """
-    A Model which represents an task
-    """
-    __tablename__ = 'tasks'
-    _private_fields = ['node_instance_fk', 'relationship_instance_fk', 
'execution_fk']
-
-    @declared_attr
-    def node_instance_fk(cls):
-        return cls.foreign_key(NodeInstanceBase, nullable=True)
-
-    @declared_attr
-    def node_instance_name(cls):
-        return association_proxy('node_instance', cls.name_column_name())
-
-    @declared_attr
-    def node_instance(cls):
-        return cls.many_to_one_relationship('node_instance_fk')
-
-    @declared_attr
-    def relationship_instance_fk(cls):
-        return cls.foreign_key(RelationshipInstanceBase, nullable=True)
-
-    @declared_attr
-    def relationship_instance_name(cls):
-        return association_proxy('relationship_instance', 
cls.name_column_name())
-
-    @declared_attr
-    def relationship_instance(cls):
-        return cls.many_to_one_relationship('relationship_instance_fk')
-
-    @declared_attr
-    def plugin_fk(cls):
-        return cls.foreign_key(PluginBase, nullable=True)
-
-    @declared_attr
-    def plugin(cls):
-        return cls.many_to_one_relationship('plugin_fk')
-
-    @declared_attr
-    def plugin_name(cls):
-        return association_proxy('plugin', 'name')
-
-    @declared_attr
-    def execution_fk(cls):
-        return cls.foreign_key(ExecutionBase, nullable=True)
-
-    @declared_attr
-    def execution(cls):
-        return cls.many_to_one_relationship('execution_fk')
-
-    @declared_attr
-    def execution_name(cls):
-        return association_proxy('execution', cls.name_column_name())
-
-    PENDING = 'pending'
-    RETRYING = 'retrying'
-    SENT = 'sent'
-    STARTED = 'started'
-    SUCCESS = 'success'
-    FAILED = 'failed'
-    STATES = (
-        PENDING,
-        RETRYING,
-        SENT,
-        STARTED,
-        SUCCESS,
-        FAILED,
-    )
-
-    WAIT_STATES = [PENDING, RETRYING]
-    END_STATES = [SUCCESS, FAILED]
-
-    @orm.validates('max_attempts')
-    def validate_max_attempts(self, _, value):                                 
 # pylint: disable=no-self-use
-        """Validates that max attempts is either -1 or a positive number"""
-        if value < 1 and value != TaskBase.INFINITE_RETRIES:
-            raise ValueError('Max attempts can be either -1 (infinite) or any 
positive number. '
-                             'Got {value}'.format(value=value))
-        return value
-
-    INFINITE_RETRIES = -1
-
-    status = Column(Enum(*STATES, name='status'), default=PENDING)
-
-    due_at = Column(DateTime, default=datetime.utcnow)
-    started_at = Column(DateTime, default=None)
-    ended_at = Column(DateTime, default=None)
-    max_attempts = Column(Integer, default=1)
-    retry_count = Column(Integer, default=0)
-    retry_interval = Column(Float, default=0)
-    ignore_failure = Column(Boolean, default=False)
-
-    # Operation specific fields
-    operation_mapping = Column(String)
-    inputs = Column(Dict)
-
-    @property
-    def actor(self):
-        """
-        Return the actor of the task
-        :return:
-        """
-        return self.node_instance or self.relationship_instance
-
-    @classmethod
-    def as_node_instance(cls, instance, **kwargs):
-        return cls(node_instance=instance, **kwargs)
-
-    @classmethod
-    def as_relationship_instance(cls, instance, **kwargs):
-        return cls(relationship_instance=instance, **kwargs)
-
-    @staticmethod
-    def abort(message=None):
-        raise TaskAbortException(message)
-
-    @staticmethod
-    def retry(message=None, retry_interval=None):
-        raise TaskRetryException(message, retry_interval=retry_interval)
+# # Licensed to the Apache Software Foundation (ASF) under one or more
+# # contributor license agreements.  See the NOTICE file distributed with
+# # this work for additional information regarding copyright ownership.
+# # The ASF licenses this file to You under the Apache License, Version 2.0
+# # (the "License"); you may not use this file except in compliance with
+# # the License.  You may obtain a copy of the License at
+# #
+# #     http://www.apache.org/licenses/LICENSE-2.0
+# #
+# # Unless required by applicable law or agreed to in writing, software
+# # distributed under the License is distributed on an "AS IS" BASIS,
+# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# # See the License for the specific language governing permissions and
+# # limitations under the License.
+#
+# """
+# Aria's storage.models module
+# Path: aria.storage.models
+#
+# models module holds aria's models.
+#
+# classes:
+#     * Field - represents a single field.
+#     * IterField - represents an iterable field.
+#     * Model - abstract model implementation.
+#     * Snapshot - snapshots implementation model.
+#     * Deployment - deployment implementation model.
+#     * DeploymentUpdateStep - deployment update step implementation model.
+#     * DeploymentUpdate - deployment update implementation model.
+#     * DeploymentModification - deployment modification implementation model.
+#     * Execution - execution implementation model.
+#     * Node - node implementation model.
+#     * Relationship - relationship implementation model.
+#     * NodeInstance - node instance implementation model.
+#     * RelationshipInstance - relationship instance implementation model.
+#     * Plugin - plugin implementation model.
+# """
+# from collections import namedtuple
+# from datetime import datetime
+#
+# from sqlalchemy.ext.associationproxy import association_proxy
+# from sqlalchemy.ext.declarative import declared_attr
+# from sqlalchemy import (
+#     Column,
+#     Integer,
+#     Text,
+#     DateTime,
+#     Boolean,
+#     Enum,
+#     String,
+#     Float,
+#     orm,
+# )
+# from sqlalchemy.ext.orderinglist import ordering_list
+#
+# from ..orchestrator.exceptions import TaskAbortException, TaskRetryException
+# from .structure import ModelMixin
+# from .type import (
+#     List,
+#     Dict
+# )
+#
+# __all__ = (
+#     'BlueprintBase',
+#     'DeploymentBase',
+#     'DeploymentUpdateStepBase',
+#     'DeploymentUpdateBase',
+#     'DeploymentModificationBase',
+#     'ExecutionBase',
+#     'NodeBase',
+#     'RelationshipBase',
+#     'NodeInstanceBase',
+#     'RelationshipInstanceBase',
+#     'PluginBase',
+#     'TaskBase'
+# )
+#
+# #pylint: disable=no-self-argument, abstract-method
+#
+#
+# class BlueprintBase(ModelMixin):
+#     """
+#     Blueprint model representation.
+#     """
+#     __tablename__ = 'blueprints'
+#
+#     created_at = Column(DateTime, nullable=False, index=True)
+#     main_file_name = Column(Text, nullable=False)
+#     plan = Column(Dict, nullable=False)
+#     updated_at = Column(DateTime)
+#     description = Column(Text)
+#
+#
+# class DeploymentBase(ModelMixin):
+#     """
+#     Deployment model representation.
+#     """
+#     __tablename__ = 'deployments'
+#
+#     _private_fields = ['blueprint_fk']
+#
+#     created_at = Column(DateTime, nullable=False, index=True)
+#     description = Column(Text)
+#     inputs = Column(Dict)
+#     groups = Column(Dict)
+#     permalink = Column(Text)
+#     policy_triggers = Column(Dict)
+#     policy_types = Column(Dict)
+#     outputs = Column(Dict)
+#     scaling_groups = Column(Dict)
+#     updated_at = Column(DateTime)
+#     workflows = Column(Dict)
+#
+#     @declared_attr
+#     def blueprint_fk(cls):
+#         return cls.foreign_key(BlueprintBase, nullable=False)
+#
+#     @declared_attr
+#     def blueprint(cls):
+#         return cls.many_to_one_relationship('blueprint_fk')
+#
+#     @declared_attr
+#     def blueprint_name(cls):
+#         return association_proxy('blueprint', cls.name_column_name())
+#
+#
+# class ExecutionBase(ModelMixin):
+#     """
+#     Execution model representation.
+#     """
+#     # Needed only for pylint. the id will be populated by sqlalcehmy and the 
proper column.
+#     __tablename__ = 'executions'
+#     _private_fields = ['deployment_fk']
+#
+#     TERMINATED = 'terminated'
+#     FAILED = 'failed'
+#     CANCELLED = 'cancelled'
+#     PENDING = 'pending'
+#     STARTED = 'started'
+#     CANCELLING = 'cancelling'
+#     FORCE_CANCELLING = 'force_cancelling'
+#
+#     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],
+#         STARTED: END_STATES + [CANCELLING],
+#         CANCELLING: END_STATES + [FORCE_CANCELLING]
+#     }
+#
+#     @orm.validates('status')
+#     def validate_status(self, key, value):
+#         """Validation function that verifies execution status transitions 
are OK"""
+#         try:
+#             current_status = getattr(self, key)
+#         except AttributeError:
+#             return
+#         valid_transitions = self.VALID_TRANSITIONS.get(current_status, [])
+#         if all([current_status is not None,
+#                 current_status != value,
+#                 value not in valid_transitions]):
+#             raise ValueError('Cannot change execution status from {current} 
to {new}'.format(
+#                 current=current_status,
+#                 new=value))
+#         return value
+#
+#     created_at = Column(DateTime, index=True)
+#     started_at = Column(DateTime, nullable=True, index=True)
+#     ended_at = Column(DateTime, nullable=True, index=True)
+#     error = Column(Text, nullable=True)
+#     is_system_workflow = Column(Boolean, nullable=False, default=False)
+#     parameters = Column(Dict)
+#     status = Column(Enum(*STATES, name='execution_status'), default=PENDING)
+#     workflow_name = Column(Text)
+#
+#     @declared_attr
+#     def blueprint(cls):
+#         return association_proxy('deployment', 'blueprint')
+#
+#     @declared_attr
+#     def deployment_fk(cls):
+#         return cls.foreign_key(DeploymentBase, nullable=True)
+#
+#     @declared_attr
+#     def deployment(cls):
+#         return cls.many_to_one_relationship('deployment_fk')
+#
+#     @declared_attr
+#     def deployment_name(cls):
+#         return association_proxy('deployment', cls.name_column_name())
+#
+#     @declared_attr
+#     def blueprint_name(cls):
+#         return association_proxy('deployment', 'blueprint_name')
+#
+#     def __str__(self):
+#         return '<{0} id=`{1}` (status={2})>'.format(
+#             self.__class__.__name__,
+#             getattr(self, self.name_column_name()),
+#             self.status
+#         )
+#
+#
+# class DeploymentUpdateBase(ModelMixin):
+#     """
+#     Deployment update model representation.
+#     """
+#     # Needed only for pylint. the id will be populated by sqlalcehmy and the 
proper column.
+#     steps = None
+#
+#     __tablename__ = 'deployment_updates'
+#
+#     _private_fields = ['execution_fk', 'deployment_fk']
+#
+#     created_at = Column(DateTime, nullable=False, index=True)
+#     deployment_plan = Column(Dict, nullable=False)
+#     deployment_update_node_instances = Column(Dict)
+#     deployment_update_deployment = Column(Dict)
+#     deployment_update_nodes = Column(List)
+#     modified_entity_ids = Column(Dict)
+#     state = Column(Text)
+#
+#     @declared_attr
+#     def execution_fk(cls):
+#         return cls.foreign_key(ExecutionBase, nullable=True)
+#
+#     @declared_attr
+#     def execution(cls):
+#         return cls.many_to_one_relationship('execution_fk')
+#
+#     @declared_attr
+#     def execution_name(cls):
+#         return association_proxy('execution', cls.name_column_name())
+#
+#     @declared_attr
+#     def deployment_fk(cls):
+#         return cls.foreign_key(DeploymentBase)
+#
+#     @declared_attr
+#     def deployment(cls):
+#         return cls.many_to_one_relationship('deployment_fk')
+#
+#     @declared_attr
+#     def deployment_name(cls):
+#         return association_proxy('deployment', cls.name_column_name())
+#
+#     def to_dict(self, suppress_error=False, **kwargs):
+#         dep_update_dict = super(DeploymentUpdateBase, 
self).to_dict(suppress_error)     #pylint: disable=no-member
+#         # Taking care of the fact the DeploymentSteps are _BaseModels
+#         dep_update_dict['steps'] = [step.to_dict() for step in self.steps]
+#         return dep_update_dict
+#
+#
+# class DeploymentUpdateStepBase(ModelMixin):
+#     """
+#     Deployment update step model representation.
+#     """
+#     # Needed only for pylint. the id will be populated by sqlalcehmy and the 
proper column.
+#     __tablename__ = 'deployment_update_steps'
+#     _private_fields = ['deployment_update_fk']
+#
+#     _action_types = namedtuple('ACTION_TYPES', 'ADD, REMOVE, MODIFY')
+#     ACTION_TYPES = _action_types(ADD='add', REMOVE='remove', MODIFY='modify')
+#     _entity_types = namedtuple(
+#         'ENTITY_TYPES',
+#         'NODE, RELATIONSHIP, PROPERTY, OPERATION, WORKFLOW, OUTPUT, 
DESCRIPTION, GROUP, '
+#         'POLICY_TYPE, POLICY_TRIGGER, PLUGIN')
+#     ENTITY_TYPES = _entity_types(
+#         NODE='node',
+#         RELATIONSHIP='relationship',
+#         PROPERTY='property',
+#         OPERATION='operation',
+#         WORKFLOW='workflow',
+#         OUTPUT='output',
+#         DESCRIPTION='description',
+#         GROUP='group',
+#         POLICY_TYPE='policy_type',
+#         POLICY_TRIGGER='policy_trigger',
+#         PLUGIN='plugin'
+#     )
+#
+#     action = Column(Enum(*ACTION_TYPES, name='action_type'), nullable=False)
+#     entity_id = Column(Text, nullable=False)
+#     entity_type = Column(Enum(*ENTITY_TYPES, name='entity_type'), 
nullable=False)
+#
+#     @declared_attr
+#     def deployment_update_fk(cls):
+#         return cls.foreign_key(DeploymentUpdateBase)
+#
+#     @declared_attr
+#     def deployment_update(cls):
+#         return cls.many_to_one_relationship('deployment_update_fk', 
backreference='steps')
+#
+#     @declared_attr
+#     def deployment_update_name(cls):
+#         return association_proxy('deployment_update', cls.name_column_name())
+#
+#     def __hash__(self):
+#         return hash((getattr(self, self.id_column_name()), self.entity_id))
+#
+#     def __lt__(self, other):
+#         """
+#         the order is 'remove' < 'modify' < 'add'
+#         :param other:
+#         :return:
+#         """
+#         if not isinstance(other, self.__class__):
+#             return not self >= other
+#
+#         if self.action != other.action:
+#             if self.action == 'remove':
+#                 return_value = True
+#             elif self.action == 'add':
+#                 return_value = False
+#             else:
+#                 return_value = other.action == 'add'
+#             return return_value
+#
+#         if self.action == 'add':
+#             return self.entity_type == 'node' and other.entity_type == 
'relationship'
+#         if self.action == 'remove':
+#             return self.entity_type == 'relationship' and other.entity_type 
== 'node'
+#         return False
+#
+#
+# class DeploymentModificationBase(ModelMixin):
+#     """
+#     Deployment modification model representation.
+#     """
+#     __tablename__ = 'deployment_modifications'
+#     _private_fields = ['deployment_fk']
+#
+#     STARTED = 'started'
+#     FINISHED = 'finished'
+#     ROLLEDBACK = 'rolledback'
+#
+#     STATES = [STARTED, FINISHED, ROLLEDBACK]
+#     END_STATES = [FINISHED, ROLLEDBACK]
+#
+#     context = Column(Dict)
+#     created_at = Column(DateTime, nullable=False, index=True)
+#     ended_at = Column(DateTime, index=True)
+#     modified_nodes = Column(Dict)
+#     node_instances = Column(Dict)
+#     status = Column(Enum(*STATES, name='deployment_modification_status'))
+#
+#     @declared_attr
+#     def deployment_fk(cls):
+#         return cls.foreign_key(DeploymentBase)
+#
+#     @declared_attr
+#     def deployment(cls):
+#         return cls.many_to_one_relationship('deployment_fk', 
backreference='modifications')
+#
+#     @declared_attr
+#     def deployment_name(cls):
+#         return association_proxy('deployment', cls.name_column_name())
+#
+#
+# class NodeBase(ModelMixin):
+#     """
+#     Node model representation.
+#     """
+#     __tablename__ = 'nodes'
+#
+#     # See base class for an explanation on these properties
+#     is_id_unique = False
+#
+#     _private_fields = ['blueprint_fk', 'host_fk']
+#
+#     @declared_attr
+#     def host_fk(cls):
+#         return cls.foreign_key(NodeBase, nullable=True)
+#
+#     @declared_attr
+#     def host(cls):
+#         return cls.relationship_to_self('host_fk')
+#
+#     @declared_attr
+#     def host_name(cls):
+#         return association_proxy('host', cls.name_column_name())
+#
+#     @declared_attr
+#     def deployment_fk(cls):
+#         return cls.foreign_key(DeploymentBase)
+#
+#     @declared_attr
+#     def deployment(cls):
+#         return cls.many_to_one_relationship('deployment_fk')
+#
+#     @declared_attr
+#     def deployment_name(cls):
+#         return association_proxy('deployment', cls.name_column_name())
+#
+#     @declared_attr
+#     def blueprint_name(cls):
+#         return association_proxy('deployment', 
'blueprint_{0}'.format(cls.name_column_name()))
+#
+#     deploy_number_of_instances = Column(Integer, nullable=False)
+#     max_number_of_instances = Column(Integer, nullable=False)
+#     min_number_of_instances = Column(Integer, nullable=False)
+#     number_of_instances = Column(Integer, nullable=False)
+#     planned_number_of_instances = Column(Integer, nullable=False)
+#     plugins = Column(List)
+#     properties = Column(Dict)
+#     operations = Column(Dict)
+#     type = Column(Text, nullable=False, index=True)
+#     type_hierarchy = Column(List)
+#
+#
+# class RelationshipBase(ModelMixin):
+#     """
+#     Relationship model representation.
+#     """
+#     __tablename__ = 'relationships'
+#
+#     _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):
+#         return cls.foreign_key(NodeBase)
+#
+#     @declared_attr
+#     def source_node(cls):
+#         return cls.many_to_one_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):
+#         return association_proxy('source_node', cls.name_column_name())
+#
+#     @declared_attr
+#     def target_node_fk(cls):
+#         return cls.foreign_key(NodeBase, nullable=True)
+#
+#     @declared_attr
+#     def target_node(cls):
+#         return cls.many_to_one_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):
+#         return association_proxy('target_node', cls.name_column_name())
+#
+#     source_interfaces = Column(Dict)
+#     source_operations = Column(Dict, nullable=False)
+#     target_interfaces = Column(Dict)
+#     target_operations = Column(Dict, nullable=False)
+#     type = Column(String, nullable=False)
+#     type_hierarchy = Column(List)
+#     properties = Column(Dict)
+#
+#
+# class NodeInstanceBase(ModelMixin):
+#     """
+#     Node instance model representation.
+#     """
+#     __tablename__ = 'node_instances'
+#     _private_fields = ['node_fk', 'host_fk']
+#
+#     runtime_properties = Column(Dict)
+#     scaling_groups = Column(List)
+#     state = Column(Text, nullable=False)
+#     version = Column(Integer, default=1)
+#
+#     @declared_attr
+#     def host_fk(cls):
+#         return cls.foreign_key(NodeInstanceBase, nullable=True)
+#
+#     @declared_attr
+#     def host(cls):
+#         return cls.relationship_to_self('host_fk')
+#
+#     @declared_attr
+#     def host_name(cls):
+#         return association_proxy('host', cls.name_column_name())
+#
+#     @declared_attr
+#     def deployment(cls):
+#         return association_proxy('node', 'deployment')
+#
+#     @declared_attr
+#     def deployment_name(cls):
+#         return association_proxy('node', 'deployment_name')
+#
+#     @declared_attr
+#     def node_fk(cls):
+#         return cls.foreign_key(NodeBase, nullable=True)
+#
+#     @declared_attr
+#     def node(cls):
+#         return cls.many_to_one_relationship('node_fk')
+#
+#     @declared_attr
+#     def node_name(cls):
+#         return association_proxy('node', cls.name_column_name())
+#
+#     @property
+#     def ip(self):
+#         if not self.host_fk:
+#             return None
+#         host_node_instance = self.host
+#         if 'ip' in host_node_instance.runtime_properties:  # pylint: 
disable=no-member
+#             return host_node_instance.runtime_properties['ip']  # pylint: 
disable=no-member
+#         host_node = host_node_instance.node  # pylint: disable=no-member
+#         if 'ip' in host_node.properties:
+#             return host_node.properties['ip']
+#         return None
+#
+#
+# class RelationshipInstanceBase(ModelMixin):
+#     """
+#     Relationship instance model representation.
+#     """
+#     __tablename__ = 'relationship_instances'
+#     _private_fields = ['relationship_storage_fk',
+#                        'source_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, nullable=True)
+#
+#     @declared_attr
+#     def source_node_instance(cls):
+#         return cls.many_to_one_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, nullable=True)
+#
+#     @declared_attr
+#     def target_node_instance(cls):
+#         return cls.many_to_one_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)
+#
+#     @declared_attr
+#     def relationship(cls):
+#         return cls.many_to_one_relationship('relationship_fk')
+#
+#     @declared_attr
+#     def relationship_name(cls):
+#         return association_proxy('relationship', cls.name_column_name())
+#
+#
+# class PluginBase(ModelMixin):
+#     """
+#     Plugin model representation.
+#     """
+#     __tablename__ = 'plugins'
+#
+#     archive_name = Column(Text, nullable=False, index=True)
+#     distribution = Column(Text)
+#     distribution_release = Column(Text)
+#     distribution_version = Column(Text)
+#     package_name = Column(Text, nullable=False, index=True)
+#     package_source = Column(Text)
+#     package_version = Column(Text)
+#     supported_platform = Column(Text)
+#     supported_py_versions = Column(List)
+#     uploaded_at = Column(DateTime, nullable=False, index=True)
+#     wheels = Column(List, nullable=False)
+#
+#
+# class TaskBase(ModelMixin):
+#     """
+#     A Model which represents an task
+#     """
+#     __tablename__ = 'tasks'
+#     _private_fields = ['node_instance_fk', 'relationship_instance_fk', 
'execution_fk']
+#
+#     @declared_attr
+#     def node_instance_fk(cls):
+#         return cls.foreign_key(NodeInstanceBase, nullable=True)
+#
+#     @declared_attr
+#     def node_instance_name(cls):
+#         return association_proxy('node_instance', cls.name_column_name())
+#
+#     @declared_attr
+#     def node_instance(cls):
+#         return cls.many_to_one_relationship('node_instance_fk')
+#
+#     @declared_attr
+#     def relationship_instance_fk(cls):
+#         return cls.foreign_key(RelationshipInstanceBase, nullable=True)
+#
+#     @declared_attr
+#     def relationship_instance_name(cls):
+#         return association_proxy('relationship_instance', 
cls.name_column_name())
+#
+#     @declared_attr
+#     def relationship_instance(cls):
+#         return cls.many_to_one_relationship('relationship_instance_fk')
+#
+#     @declared_attr
+#     def plugin_fk(cls):
+#         return cls.foreign_key(PluginBase, nullable=True)
+#
+#     @declared_attr
+#     def plugin(cls):
+#         return cls.many_to_one_relationship('plugin_fk')
+#
+#     @declared_attr
+#     def plugin_name(cls):
+#         return association_proxy('plugin', 'name')
+#
+#     @declared_attr
+#     def execution_fk(cls):
+#         return cls.foreign_key(ExecutionBase, nullable=True)
+#
+#     @declared_attr
+#     def execution(cls):
+#         return cls.many_to_one_relationship('execution_fk')
+#
+#     @declared_attr
+#     def execution_name(cls):
+#         return association_proxy('execution', cls.name_column_name())
+#
+#     PENDING = 'pending'
+#     RETRYING = 'retrying'
+#     SENT = 'sent'
+#     STARTED = 'started'
+#     SUCCESS = 'success'
+#     FAILED = 'failed'
+#     STATES = (
+#         PENDING,
+#         RETRYING,
+#         SENT,
+#         STARTED,
+#         SUCCESS,
+#         FAILED,
+#     )
+#
+#     WAIT_STATES = [PENDING, RETRYING]
+#     END_STATES = [SUCCESS, FAILED]
+#
+#     @orm.validates('max_attempts')
+#     def validate_max_attempts(self, _, value):                               
   # pylint: disable=no-self-use
+#         """Validates that max attempts is either -1 or a positive number"""
+#         if value < 1 and value != TaskBase.INFINITE_RETRIES:
+#             raise ValueError('Max attempts can be either -1 (infinite) or 
any positive number. '
+#                              'Got {value}'.format(value=value))
+#         return value
+#
+#     INFINITE_RETRIES = -1
+#
+#     status = Column(Enum(*STATES, name='status'), default=PENDING)
+#
+#     due_at = Column(DateTime, default=datetime.utcnow)
+#     started_at = Column(DateTime, default=None)
+#     ended_at = Column(DateTime, default=None)
+#     max_attempts = Column(Integer, default=1)
+#     retry_count = Column(Integer, default=0)
+#     retry_interval = Column(Float, default=0)
+#     ignore_failure = Column(Boolean, default=False)
+#
+#     # Operation specific fields
+#     operation_mapping = Column(String)
+#     inputs = Column(Dict)
+#
+#     @property
+#     def actor(self):
+#         """
+#         Return the actor of the task
+#         :return:
+#         """
+#         return self.node_instance or self.relationship_instance
+#
+#     @classmethod
+#     def as_node_instance(cls, instance, **kwargs):
+#         return cls(node_instance=instance, **kwargs)
+#
+#     @classmethod
+#     def as_relationship_instance(cls, instance, **kwargs):
+#         return cls(relationship_instance=instance, **kwargs)
+#
+#     @staticmethod
+#     def abort(message=None):
+#         raise TaskAbortException(message)
+#
+#     @staticmethod
+#     def retry(message=None, retry_interval=None):
+#         raise TaskRetryException(message, retry_interval=retry_interval)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/aria/storage/model.py
----------------------------------------------------------------------
diff --git a/aria/storage/model.py b/aria/storage/model.py
index afca3e4..6533b7f 100644
--- a/aria/storage/model.py
+++ b/aria/storage/model.py
@@ -1,110 +1,110 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Aria's storage.models module
-Path: aria.storage.models
-
-models module holds aria's models.
-
-classes:
-    * Field - represents a single field.
-    * IterField - represents an iterable field.
-    * Model - abstract model implementation.
-    * Snapshot - snapshots implementation model.
-    * Deployment - deployment implementation model.
-    * DeploymentUpdateStep - deployment update step implementation model.
-    * DeploymentUpdate - deployment update implementation model.
-    * DeploymentModification - deployment modification implementation model.
-    * Execution - execution implementation model.
-    * Node - node implementation model.
-    * Relationship - relationship implementation model.
-    * NodeInstance - node instance implementation model.
-    * RelationshipInstance - relationship instance implementation model.
-    * ProviderContext - provider context implementation model.
-    * Plugin - plugin implementation model.
-"""
-from sqlalchemy.ext.declarative import declarative_base
-
-from . import structure
-from . import base_model as base
-
-__all__ = (
-    'Blueprint',
-    'Deployment',
-    'DeploymentUpdateStep',
-    'DeploymentUpdate',
-    'DeploymentModification',
-    'Execution',
-    'Node',
-    'Relationship',
-    'NodeInstance',
-    'RelationshipInstance',
-    'Plugin',
-)
-
-
-#pylint: disable=abstract-method
-# The required abstract method implementation are implemented in the 
ModelIDMixin, which is used as
-# a base to the DeclerativeBase.
-DeclarativeBase = declarative_base(cls=structure.ModelIDMixin)
-
-
-class Blueprint(DeclarativeBase, base.BlueprintBase):
-    pass
-
-
-class Deployment(DeclarativeBase, base.DeploymentBase):
-    pass
-
-
-class Execution(DeclarativeBase, base.ExecutionBase):
-    pass
-
-
-class DeploymentUpdate(DeclarativeBase, base.DeploymentUpdateBase):
-    pass
-
-
-class DeploymentUpdateStep(DeclarativeBase, base.DeploymentUpdateStepBase):
-    pass
-
-
-class DeploymentModification(DeclarativeBase, base.DeploymentModificationBase):
-    pass
-
-
-class Node(DeclarativeBase, base.NodeBase):
-    pass
-
-
-class Relationship(DeclarativeBase, base.RelationshipBase):
-    pass
-
-
-class NodeInstance(DeclarativeBase, base.NodeInstanceBase):
-    pass
-
-
-class RelationshipInstance(DeclarativeBase, base.RelationshipInstanceBase):
-    pass
-
-
-class Plugin(DeclarativeBase, base.PluginBase):
-    pass
-
-
-class Task(DeclarativeBase, base.TaskBase):
-    pass
+# # Licensed to the Apache Software Foundation (ASF) under one or more
+# # contributor license agreements.  See the NOTICE file distributed with
+# # this work for additional information regarding copyright ownership.
+# # The ASF licenses this file to You under the Apache License, Version 2.0
+# # (the "License"); you may not use this file except in compliance with
+# # the License.  You may obtain a copy of the License at
+# #
+# #     http://www.apache.org/licenses/LICENSE-2.0
+# #
+# # Unless required by applicable law or agreed to in writing, software
+# # distributed under the License is distributed on an "AS IS" BASIS,
+# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# # See the License for the specific language governing permissions and
+# # limitations under the License.
+#
+# """
+# Aria's storage.models module
+# Path: aria.storage.models
+#
+# models module holds aria's models.
+#
+# classes:
+#     * Field - represents a single field.
+#     * IterField - represents an iterable field.
+#     * Model - abstract model implementation.
+#     * Snapshot - snapshots implementation model.
+#     * Deployment - deployment implementation model.
+#     * DeploymentUpdateStep - deployment update step implementation model.
+#     * DeploymentUpdate - deployment update implementation model.
+#     * DeploymentModification - deployment modification implementation model.
+#     * Execution - execution implementation model.
+#     * Node - node implementation model.
+#     * Relationship - relationship implementation model.
+#     * NodeInstance - node instance implementation model.
+#     * RelationshipInstance - relationship instance implementation model.
+#     * ProviderContext - provider context implementation model.
+#     * Plugin - plugin implementation model.
+# """
+# from sqlalchemy.ext.declarative import declarative_base
+#
+# from . import structure
+# from . import base_model as base
+#
+# __all__ = (
+#     'Blueprint',
+#     'Deployment',
+#     'DeploymentUpdateStep',
+#     'DeploymentUpdate',
+#     'DeploymentModification',
+#     'Execution',
+#     'Node',
+#     'Relationship',
+#     'NodeInstance',
+#     'RelationshipInstance',
+#     'Plugin',
+# )
+#
+#
+# #pylint: disable=abstract-method
+# # The required abstract method implementation are implemented in the 
ModelIDMixin, which is used as
+# # a base to the DeclerativeBase.
+# DeclarativeBase = declarative_base(cls=structure.ModelIDMixin)
+#
+#
+# class Blueprint(DeclarativeBase, base.BlueprintBase):
+#     pass
+#
+#
+# class Deployment(DeclarativeBase, base.DeploymentBase):
+#     pass
+#
+#
+# class Execution(DeclarativeBase, base.ExecutionBase):
+#     pass
+#
+#
+# class DeploymentUpdate(DeclarativeBase, base.DeploymentUpdateBase):
+#     pass
+#
+#
+# class DeploymentUpdateStep(DeclarativeBase, base.DeploymentUpdateStepBase):
+#     pass
+#
+#
+# class DeploymentModification(DeclarativeBase, 
base.DeploymentModificationBase):
+#     pass
+#
+#
+# class Node(DeclarativeBase, base.NodeBase):
+#     pass
+#
+#
+# class Relationship(DeclarativeBase, base.RelationshipBase):
+#     pass
+#
+#
+# class NodeInstance(DeclarativeBase, base.NodeInstanceBase):
+#     pass
+#
+#
+# class RelationshipInstance(DeclarativeBase, base.RelationshipInstanceBase):
+#     pass
+#
+#
+# class Plugin(DeclarativeBase, base.PluginBase):
+#     pass
+#
+#
+# class Task(DeclarativeBase, base.TaskBase):
+#     pass

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/aria/storage/structure.py
----------------------------------------------------------------------
diff --git a/aria/storage/structure.py b/aria/storage/structure.py
index 472b5ba..f9cd58b 100644
--- a/aria/storage/structure.py
+++ b/aria/storage/structure.py
@@ -37,6 +37,7 @@ from sqlalchemy import (
     Table
 )
 
+from aria.storage.api import generate_lower_name
 from ..parser.modeling.elements import Element
 
 
@@ -62,33 +63,29 @@ class ModelMixin(Element):
             return cls
 
         for table_cls in cls._decl_class_registry.values():
-            if tablename in (getattr(table_cls, '__name__', None),
-                             getattr(table_cls, '__tablename__', None)):
+            if tablename == getattr(table_cls, '__tablename__', None):
                 return table_cls
 
     @classmethod
-    def foreign_key(cls, table, nullable=False):
+    def foreign_key(cls, table_name, nullable=False):
         """Return a ForeignKey object with the relevant
 
         :param table: Unique id column in the parent table
         :param nullable: Should the column be allowed to remain empty
         """
-        table_cls = cls._get_cls_by_tablename(table.__tablename__)
-        foreign_key_str = 
'{tablename}.{unique_id}'.format(tablename=table_cls.__tablename__,
-                                                           
unique_id=table_cls.id_column_name())
-        column = Column(ForeignKey(foreign_key_str, ondelete='CASCADE'),
-                        nullable=nullable)
-        column.__remote_table_name = table_cls.__name__
-        return column
+        return Column(Integer,
+                      
ForeignKey('{tablename}.id'.format(tablename=table_name), ondelete='CASCADE'),
+                      nullable=nullable)
 
     @classmethod
-    def one_to_one_relationship(cls, table, backreference=None):
-        return relationship(table.__name__,
+    def one_to_one_relationship(cls, table_name, backreference=None):
+        return relationship(lambda: cls._get_cls_by_tablename(table_name),
                             backref=backref(backreference or 
cls.__tablename__, uselist=False))
 
     @classmethod
     def many_to_one_relationship(cls,
-                                 foreign_key_column,
+                                 parent_table_name,
+                                 foreign_key_column=None,
                                  backreference=None,
                                  backref_kwargs=None,
                                  **kwargs):
@@ -100,31 +97,27 @@ class ModelMixin(Element):
         :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} == ' \
-                          '{child_class.__name__}.{foreign_key_column}'\
-            .format(
-                parent_class_name=parent_table.__name__,
-                parent_unique_id=parent_table.id_column_name(),
-                child_class=cls,
-                foreign_key_column=foreign_key_column
-            )
-        return relationship(
-            parent_table.__name__,
-            primaryjoin=primaryjoin_str,
-            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_kwargs),
-            **kwargs
-        )
+        relationship_kwargs_ = kwargs
+        if foreign_key_column:
+            relationship_kwargs_['foreign_keys'] = [getattr(cls, 
foreign_key_column)]
+
+        return relationship(lambda: 
cls._get_cls_by_tablename(parent_table_name),
+                            backref=backref(
+                                backreference or cls.__tablename__,
+                                lazy='dynamic',
+                                # The following line make sure that when the 
*parent* is
+                                #  deleted, all its connected children are 
deleted as well
+                                cascade='all',
+
+                                **backref_kwargs or {}),
+
+                            **relationship_kwargs_)
 
     @classmethod
-    def one_to_many_relationship(cls, table, backrefernce=None):
-        return relationship(table.__name__,
-                            backref=backrefernce or cls.__tablename__)
+    def one_to_many_relationship(cls, child_table_name, backrefernce=None):
+        return relationship(lambda: 
cls._get_cls_by_tablename(child_table_name),
+                            backref=backrefernce or 
'{0}s'.format(cls.__tablename__),
+                            lazy='dynamic')
 
     @classmethod
     def relationship_to_self(cls, local_column):
@@ -137,13 +130,13 @@ class ModelMixin(Element):
             remote_side_str=remote_side_str,
             cls=cls,
             local_column=local_column)
-        return relationship(cls.__name__,
+        return 
relationship(cls._get_cls_by_tablename(cls.__tablename__).__name__,
                             primaryjoin=primaryjoin_str,
                             remote_side=remote_side_str,
                             post_update=True)
 
     @classmethod
-    def many_to_many_relationship(cls, other_cls, table_prefix):
+    def many_to_many_relationship(cls, other_table_name, table_prefix):
         """Return a many-to-many SQL relationship object
 
         Notes:
@@ -151,29 +144,18 @@ class ModelMixin(Element):
         2. This method creates a new helper table in the DB
 
         :param cls: The class of the table we're connecting from
-        :param other_cls: The class of the table we're connecting to
+        :param other_table_name: The class of the table we're connecting to
         :param table_prefix: Custom prefix for the helper table name and the
         backreference name
         """
         current_table_name = cls.__tablename__
         current_column_name = '{0}_id'.format(current_table_name)
-        current_foreign_key = '{0}.{1}'.format(
-            current_table_name,
-            cls.id_column_name()
-        )
+        current_foreign_key = '{0}.id'.format(current_table_name)
 
-        other_cls = cls._get_cls_by_tablename(other_cls.__tablename__)
-        other_table_name = other_cls.__tablename__
         other_column_name = '{0}_id'.format(other_table_name)
-        other_foreign_key = '{0}.{1}'.format(
-            other_table_name,
-            other_cls.id_column_name()
-        )
+        other_foreign_key = '{0}.id'.format(other_table_name)
 
-        helper_table_name = '{0}_{1}'.format(
-            current_table_name,
-            other_table_name
-        )
+        helper_table_name = '{0}_{1}'.format(current_table_name, 
other_table_name)
 
         backref_name = current_table_name
         if table_prefix:
@@ -188,8 +170,9 @@ class ModelMixin(Element):
             current_foreign_key,
             other_foreign_key
         )
+
         return relationship(
-            other_cls,
+            lambda: cls._get_cls_by_tablename(other_table_name),
             secondary=secondary_table,
             backref=backref(backref_name)
         )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/tests/mock/models.py
----------------------------------------------------------------------
diff --git a/tests/mock/models.py b/tests/mock/models.py
index 87fa352..e5f29ff 100644
--- a/tests/mock/models.py
+++ b/tests/mock/models.py
@@ -35,11 +35,6 @@ RELATIONSHIP_INSTANCE_NAME = 'relationship_instance'
 
 
 def get_dependency_node(deployment):
-    operation_templates = [models.OperationTemplate(implementation=op,
-                                                    
service_template=deployment.service_template)
-                           for op in operations.NODE_OPERATIONS]
-    interface_template = 
models.InterfaceTemplate(operation_templates=operation_templates)
-
     return models.NodeTemplate(
         name=DEPENDENCY_NODE_NAME,
         type_name='test_node_type',
@@ -48,7 +43,7 @@ def get_dependency_node(deployment):
         min_instances=1,
         max_instances=1,
         service_template=deployment.service_template,
-        interface_templates=[interface_template],
+        # interface_templates=[get_interface_template(op) for op in 
operations.NODE_OPERATIONS],
     )
 
 
@@ -162,3 +157,29 @@ def get_plugin(package_name='package', 
package_version='0.1'):
         uploaded_at=datetime.now(),
         wheels=[],
     )
+
+
+def get_interface_template(operation_name, operation_kwargs=None, 
interface_kwargs=None):
+    operation_template = models.OperationTemplate(
+        name=operation_name,
+        **(operation_kwargs or {})
+
+    )
+    return models.InterfaceTemplate(
+        operation_templates=[operation_template],
+        name=operation_name.rsplit('.', 1)[0],
+        **(interface_kwargs or {})
+    )
+
+
+def get_interface(operation_name, operation_kwargs=None, 
interface_kwargs=None):
+    operation = models.Operation(
+        name=operation_name,
+        **(operation_kwargs or {})
+    )
+
+    return models.Interface(
+        operations=[operation],
+        name=operation_name.rsplit('.', 1)[0],
+        **(interface_kwargs or {})
+    )

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/tests/orchestrator/workflows/api/test_task.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/workflows/api/test_task.py 
b/tests/orchestrator/workflows/api/test_task.py
index 198e461..2393af4 100644
--- a/tests/orchestrator/workflows/api/test_task.py
+++ b/tests/orchestrator/workflows/api/test_task.py
@@ -18,6 +18,7 @@ import pytest
 
 from aria.orchestrator import context
 from aria.orchestrator.workflows import api
+from aria.modeling import models
 
 from tests import mock, storage
 
@@ -39,16 +40,19 @@ class TestOperationTask(object):
 
     def test_node_operation_task_creation(self, ctx):
         operation_name = 'aria.interfaces.lifecycle.create'
-        op_details = {'operation': True, 'plugin': 'plugin'}
+        interface_template = mock.models.get_interface_template(
+            operation_name,
+            operation_kwargs=dict(plugin='plugin', operation=True))
+
         node = 
ctx.model.node_template.get_by_name(mock.models.DEPENDENT_NODE_NAME)
-        node.operations[operation_name] = op_details
+        node.interface_templates = [interface_template]
         node.plugins = [{'name': 'plugin',
                          'package_name': 'package',
                          'package_version': '0.1'}]
         ctx.model.node_template.update(node)
         node_instance = \
             
ctx.model.node.get_by_name(mock.models.DEPENDENT_NODE_INSTANCE_NAME)
-        inputs = {'inputs': True}
+        inputs = [models.Parameter(type_name='Boolean', value=True)]
         max_attempts = 10
         retry_interval = 10
         ignore_failure = True
@@ -75,14 +79,18 @@ class TestOperationTask(object):
 
     def test_source_relationship_operation_task_creation(self, ctx):
         operation_name = 'aria.interfaces.relationship_lifecycle.preconfigure'
-        op_details = {'operation': True, 'plugin': 'plugin'}
+
+        interface = mock.models.get_interface(
+            operation_name,
+            operation_kwargs=dict(operation=True, plugin='plugin'))
+
         relationship = ctx.model.relationship.list()[0]
-        relationship.source_operations[operation_name] = op_details
+        relationship.source_interfaces = [interface]
         relationship.source_node.plugins = [{'name': 'plugin',
                                              'package_name': 'package',
                                              'package_version': '0.1'}]
         relationship_instance = ctx.model.relationship_instance.list()[0]
-        inputs = {'inputs': True}
+        input = models.Parameter(type_name='Boolean', value=True)
         max_attempts = 10
         retry_interval = 10
 
@@ -91,7 +99,7 @@ class TestOperationTask(object):
                 name=operation_name,
                 instance=relationship_instance,
                 operation_end=api.task.OperationTask.SOURCE_OPERATION,
-                inputs=inputs,
+                inputs=[input],
                 max_attempts=max_attempts,
                 retry_interval=retry_interval)
 
@@ -138,7 +146,7 @@ class TestOperationTask(object):
                                    'package_version': '0.1'}
 
     def test_operation_task_default_values(self, ctx):
-        dependency_node_instance = ctx.model.node_instance.get_by_name(
+        dependency_node_instance = ctx.model.node.get_by_name(
             mock.models.DEPENDENCY_NODE_INSTANCE_NAME)
         with context.workflow.current.push(ctx):
             task = api.task.OperationTask(

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/tests/storage/__init__.py
----------------------------------------------------------------------
diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py
index 1c8b41b..acdfc8a 100644
--- a/tests/storage/__init__.py
+++ b/tests/storage/__init__.py
@@ -17,7 +17,7 @@ import platform
 from tempfile import mkdtemp
 from shutil import rmtree
 
-from aria.storage import model
+from aria.modeling import models
 from sqlalchemy import (
     create_engine,
     orm)
@@ -34,9 +34,9 @@ class TestFileSystem(object):
         rmtree(self.path, ignore_errors=True)
 
 
-def get_sqlite_api_kwargs(base_dir=None,
-                          filename='db.sqlite',
-                          declarative_base=model.DeclarativeBase):
+def get_sqlite_api_kwargs(declarative_base=models.DB,
+                          base_dir=None,
+                          filename='db.sqlite'):
     """
     Create sql params. works in in-memory and in filesystem mode.
     If base_dir is passed, the mode will be filesystem mode. while the default 
mode is in-memory.
@@ -61,7 +61,8 @@ def get_sqlite_api_kwargs(base_dir=None,
     session_factory = orm.sessionmaker(bind=engine)
     session = scoped_session(session_factory=session_factory) if base_dir else 
session_factory()
 
-    declarative_base.metadata.create_all(bind=engine)
+    if declarative_base:
+        declarative_base.metadata.create_all(bind=engine)
     return dict(engine=engine, session=session)
 
 
@@ -78,4 +79,4 @@ def release_sqlite_storage(storage):
             session.rollback()
             session.close()
         for engine in set(mapi._engine for mapi in mapis):
-            model.DeclarativeBase.metadata.drop_all(engine)
+            models.DB.metadata.drop_all(engine)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/tests/storage/test_model_storage.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_model_storage.py 
b/tests/storage/test_model_storage.py
index d9b7329..b96c2b2 100644
--- a/tests/storage/test_model_storage.py
+++ b/tests/storage/test_model_storage.py
@@ -25,6 +25,7 @@ from aria.storage import (
     structure,
     type as aria_type,
 )
+from aria import modeling
 from aria import application_model_storage
 from ..storage import get_sqlite_api_kwargs, release_sqlite_storage
 from ..mock import (
@@ -34,7 +35,7 @@ from ..mock import (
 )
 
 
-class MockModel(model.DeclarativeBase, structure.ModelMixin): #pylint: 
disable=abstract-method
+class MockModel(modeling.models.DB, structure.ModelMixin): #pylint: 
disable=abstract-method
     __tablename__ = 'mock_models'
     model_dict = Column(aria_type.Dict)
     model_list = Column(aria_type.List)
@@ -57,7 +58,7 @@ def context():
 
 @pytest.fixture(scope='module', autouse=True)
 def module_cleanup():
-    model.DeclarativeBase.metadata.remove(MockModel.__table__)  #pylint: 
disable=no-member
+    modeling.models.DB.metadata.remove(MockModel.__table__)  #pylint: 
disable=no-member
 
 
 def test_storage_base(storage):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9c6c378c/tests/storage/test_new_modelling.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_new_modelling.py 
b/tests/storage/test_new_modelling.py
index ff96d3d..477144b 100644
--- a/tests/storage/test_new_modelling.py
+++ b/tests/storage/test_new_modelling.py
@@ -14,8 +14,6 @@ from ..storage import (
     release_sqlite_storage
 )
 
-DB = declarative_base(cls=structure.ModelIDMixin)
-
 tosca_classes = [
     models.Parameter,
 
@@ -59,7 +57,7 @@ tosca_classes = [
 @pytest.fixture
 def storage():
     base_storage = ModelStorage(sql_mapi.SQLAlchemyModelAPI,
-                                
api_kwargs=get_sqlite_api_kwargs(declarative_base=DB),
+                                api_kwargs=get_sqlite_api_kwargs(),
                                 items=tosca_classes)
     yield base_storage
     release_sqlite_storage(base_storage)
@@ -71,5 +69,5 @@ def test_models_creation(storage):
     :param storage:
     :return:
     """
-    for cls in tosca_classes:
-        assert len(getattr(storage, api.generate_lower_name(cls)).list()) == 0
+    for cls in storage.registered.values():
+        assert len(cls.list()) == 0

Reply via email to