You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by av...@apache.org on 2017/03/22 13:48:55 UTC
[06/13] incubator-ariatosca git commit: ARIA-105 Integrate parser and
orchestrator models
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9841ca4a/aria/storage/modeling/elements.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/elements.py b/aria/storage/modeling/elements.py
deleted file mode 100644
index 8c720b9..0000000
--- a/aria/storage/modeling/elements.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from sqlalchemy import (
- Column,
- Text
-)
-
-from ...parser.modeling import utils
-from ...utils.collections import OrderedDict
-from ...utils.console import puts
-from .. import exceptions
-
-from . import structure
-from . import type
-
-# pylint: disable=no-self-argument, no-member, abstract-method
-
-
-class ParameterBase(structure.ModelMixin):
- """
- Represents a typed value.
-
- This class is used by both service model and service instance elements.
- """
- __tablename__ = 'parameter'
- name = Column(Text, nullable=False)
- type = Column(Text, nullable=False)
-
- # Check: value type
- str_value = Column(Text)
- description = Column(Text)
-
- @property
- def as_raw(self):
- return OrderedDict((
- ('name', self.name),
- ('type_name', self.type),
- ('value', self.value),
- ('description', self.description)))
-
- @property
- def value(self):
- if self.type is None:
- return
- try:
- if self.type.lower() in ['str', 'unicode']:
- return self.str_value.decode('utf-8')
- elif self.type.lower() == 'int':
- return int(self.str_value)
- elif self.type.lower() == 'bool':
- return bool(self.str_value)
- elif self.type.lower() == 'float':
- return float(self.str_value)
- else:
- raise exceptions.StorageError('No supported type_name was provided')
- except ValueError:
- raise exceptions.StorageError('Trying to cast {0} to {1} failed'.format(self.str_value,
- self.type))
-
- def instantiate(self, context, container):
- return ParameterBase(self.type, self.str_value, self.description)
-
- def coerce_values(self, context, container, report_issues):
- if self.str_value is not None:
- self.str_value = utils.coerce_value(context, container, self.str_value, report_issues)
-
-
-class MetadataBase(structure.ModelMixin):
- """
- Custom values associated with the deployment template and its plans.
-
- This class is used by both service model and service instance elements.
-
- Properties:
-
- * :code:`values`: Dict of custom values
- """
- values = Column(type.StrictDict(key_cls=basestring))
-
- @property
- def as_raw(self):
- return self.values
-
- def instantiate(self, context, container):
- metadata = MetadataBase()
- metadata.values.update(self.values)
- return metadata
-
- def dump(self, context):
- puts('Metadata:')
- with context.style.indent:
- for name, value in self.values.iteritems():
- puts('%s: %s' % (name, context.style.meta(value)))
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9841ca4a/aria/storage/modeling/instance_elements.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/instance_elements.py b/aria/storage/modeling/instance_elements.py
deleted file mode 100644
index 86e2ea6..0000000
--- a/aria/storage/modeling/instance_elements.py
+++ /dev/null
@@ -1,1288 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from sqlalchemy import (
- Column,
- Text,
- Integer,
- Boolean,
-)
-from sqlalchemy import DateTime
-from sqlalchemy.ext.associationproxy import association_proxy
-from sqlalchemy.ext.declarative import declared_attr
-from sqlalchemy.ext.orderinglist import ordering_list
-
-from aria.parser import validation
-from aria.utils import collections, formatting, console
-
-from . import (
- utils,
- structure,
- type as aria_types
-)
-
-# pylint: disable=no-self-argument, no-member, abstract-method
-
-# region Element instances
-
-
-class ServiceInstanceBase(structure.ModelMixin):
- __tablename__ = 'service_instance'
-
- __private_fields__ = ['substituion_fk',
- 'service_template_fk']
-
- description = Column(Text)
- _metadata = Column(Text)
-
- # region orchestrator required columns
-
- created_at = Column(DateTime, nullable=False, index=True)
- permalink = Column(Text)
- policy_triggers = Column(aria_types.Dict)
- policy_types = Column(aria_types.Dict)
- scaling_groups = Column(aria_types.Dict)
- updated_at = Column(DateTime)
- workflows = Column(aria_types.Dict)
-
- @declared_attr
- def service_template_name(cls):
- return association_proxy('service_template', 'name')
-
- # endregion
-
- # region foreign keys
- @declared_attr
- def substitution_fk(cls):
- return cls.foreign_key('substitution', nullable=True)
-
- @declared_attr
- def service_template_fk(cls):
- return cls.foreign_key('service_template')
-
- # endregion
-
- # region one-to-one relationships
- @declared_attr
- def substitution(cls):
- return cls.one_to_one_relationship('substitution')
- # endregion
-
- # region many-to-one relationships
- @declared_attr
- def service_template(cls):
- return cls.many_to_one_relationship('service_template')
-
- # endregion
-
- # region many-to-many relationships
- @declared_attr
- def inputs(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='inputs')
-
- @declared_attr
- def outputs(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='outputs')
-
- # endregion
-
- # association proxies
-
- def satisfy_requirements(self, context):
- satisfied = True
- for node in self.nodes.all():
- if not node.satisfy_requirements(context):
- satisfied = False
- return satisfied
-
- def validate_capabilities(self, context):
- satisfied = True
- for node in self.nodes.all():
- if not node.validate_capabilities(context):
- satisfied = False
- return satisfied
-
- def find_nodes(self, node_template_name):
- nodes = []
- for node in self.nodes.all():
- if node.template_name == node_template_name:
- nodes.append(node)
- return collections.FrozenList(nodes)
-
- def get_node_ids(self, node_template_name):
- return collections.FrozenList((node.id for node in self.find_nodes(node_template_name)))
-
- def find_groups(self, group_template_name):
- groups = []
- for group in self.groups.all():
- if group.template_name == group_template_name:
- groups.append(group)
- return collections.FrozenList(groups)
-
- def get_group_ids(self, group_template_name):
- return collections.FrozenList((group.id for group in self.find_groups(group_template_name)))
-
- def is_node_a_target(self, context, target_node):
- for node in self.nodes.all():
- if self._is_node_a_target(context, node, target_node):
- return True
- return False
-
- def _is_node_a_target(self, context, source_node, target_node):
- if source_node.relationships:
- for relationship in source_node.relationships:
- if relationship.target_node_id == target_node.id:
- return True
- else:
- node = context.modeling.instance.nodes.get(relationship.target_node_id)
- if node is not None:
- if self._is_node_a_target(context, node, target_node):
- return True
- return False
-
-
-class OperationBase(structure.ModelMixin):
- """
- An operation in a :class:`Interface`.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :code:`implementation`: Implementation string (interpreted by the orchestrator)
- * :code:`dependencies`: List of strings (interpreted by the orchestrator)
- * :code:`executor`: Executor string (interpreted by the orchestrator)
- * :code:`max_retries`: Maximum number of retries allowed in case of failure
- * :code:`retry_interval`: Interval between retries
- * :code:`inputs`: Dict of :class:`Parameter`
- """
- __tablename__ = 'operation'
-
- __private_fields__ = ['service_template_fk',
- 'interface_instance_fk']
-
- # region foreign_keys
-
- @declared_attr
- def service_instance_fk(cls):
- return cls.foreign_key('service_instance', nullable=True)
-
- @declared_attr
- def interface_instance_fk(cls):
- return cls.foreign_key('interface', nullable=True)
-
- # endregion
- description = Column(Text)
- implementation = Column(Text)
- dependencies = Column(aria_types.StrictList(item_cls=basestring))
-
- executor = Column(Text)
- max_retries = Column(Integer, default=None)
- retry_interval = Column(Integer, default=None)
- plugin = Column(Text)
- operation = Column(Boolean)
-
- # region many-to-one relationships
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance')
-
- @declared_attr
- def interface(cls):
- return cls.many_to_one_relationship('interface')
- # region many-to-many relationships
-
- @declared_attr
- def inputs(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='inputs')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('implementation', self.implementation),
- ('dependencies', self.dependencies),
- ('executor', self.executor),
- ('max_retries', self.max_retries),
- ('retry_interval', self.retry_interval),
- ('inputs', formatting.as_raw_dict(self.inputs))))
-
- def validate(self, context):
- utils.validate_dict_values(context, self.inputs)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.inputs, report_issues)
-
- def dump(self, context):
- console.puts(context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- if self.implementation is not None:
- console.puts('Implementation: %s' % context.style.literal(self.implementation))
- if self.dependencies:
- console.puts(
- 'Dependencies: %s'
- % ', '.join((str(context.style.literal(v)) for v in self.dependencies)))
- if self.executor is not None:
- console.puts('Executor: %s' % context.style.literal(self.executor))
- if self.max_retries is not None:
- console.puts('Max retries: %s' % context.style.literal(self.max_retries))
- if self.retry_interval is not None:
- console.puts('Retry interval: %s' % context.style.literal(self.retry_interval))
- utils.dump_parameters(context, self.inputs, 'Inputs')
-
-
-class InterfaceBase(structure.ModelMixin):
- """
- A typed set of :class:`Operation`.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`inputs`: Dict of :class:`Parameter`
- * :code:`operations`: Dict of :class:`Operation`
- """
- __tablename__ = 'interface'
-
- __private_fields__ = ['group_fk',
- 'node_fk',
- 'relationship_fk']
-
-
- # region foreign_keys
- @declared_attr
- def group_fk(cls):
- return cls.foreign_key('group', nullable=True)
-
- @declared_attr
- def node_fk(cls):
- return cls.foreign_key('node', nullable=True)
-
- @declared_attr
- def relationship_fk(cls):
- return cls.foreign_key('relationship', nullable=True)
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- edge = Column(Text)
-
- # region many-to-one relationships
-
- @declared_attr
- def node(cls):
- return cls.many_to_one_relationship('node')
-
- @declared_attr
- def relationship(cls):
- return cls.many_to_one_relationship('relationship')
-
- @declared_attr
- def group(cls):
- return cls.many_to_one_relationship('group')
-
- # endregion
-
- # region many-to-many relationships
-
- @declared_attr
- def inputs(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='inputs')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('type_name', self.type_name),
- ('inputs', formatting.as_raw_dict(self.inputs)),
- ('operations', formatting.as_raw_list(self.operations))))
-
- def validate(self, context):
- if self.type_name:
- if context.modeling.interface_types.get_descendant(self.type_name) is None:
- context.validation.report('interface "%s" has an unknown type: %s'
- % (self.name,
- formatting.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.inputs)
- utils.validate_dict_values(context, self.operations)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.inputs, report_issues)
- utils.coerce_dict_values(context, container, self.operations, report_issues)
-
- def dump(self, context):
- console.puts(context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Interface type: %s' % context.style.type(self.type_name))
- utils.dump_parameters(context, self.inputs, 'Inputs')
- utils.dump_dict_values(context, self.operations, 'Operations')
-
-
-class CapabilityBase(structure.ModelMixin):
- """
- A capability of a :class:`Node`.
-
- An instance of a :class:`CapabilityTemplate`.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`min_occurrences`: Minimum number of requirement matches required
- * :code:`max_occurrences`: Maximum number of requirement matches allowed
- * :code:`properties`: Dict of :class:`Parameter`
- """
- __tablename__ = 'capability'
-
- __private_fields__ = ['node_fk']
-
- # region foreign_keys
- @declared_attr
- def node_fk(cls):
- return cls.foreign_key('node')
-
- # endregion
- type_name = Column(Text)
-
- min_occurrences = Column(Integer, default=None) # optional
- max_occurrences = Column(Integer, default=None) # optional
- occurrences = Column(Integer, default=0)
-
- # region many-to-one relationships
- @declared_attr
- def node(cls):
- return cls.many_to_one_relationship('node')
-
- # endregion
-
-
- # region many-to-many relationships
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def has_enough_relationships(self):
- if self.min_occurrences is not None:
- return self.occurrences >= self.min_occurrences
- return True
-
- def relate(self):
- if self.max_occurrences is not None:
- if self.occurrences == self.max_occurrences:
- return False
- self.occurrences += 1
- return True
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('type_name', self.type_name),
- ('properties', formatting.as_raw_dict(self.properties))))
-
- def validate(self, context):
- if context.modeling.capability_types.get_descendant(self.type_name) is None:
- context.validation.report('capability "%s" has an unknown type: %s'
- % (self.name,
- formatting.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.properties)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
-
- def dump(self, context):
- console.puts(context.style.node(self.name))
- with context.style.indent:
- console.puts('Type: %s' % context.style.type(self.type_name))
- console.puts('Occurrences: %s (%s%s)'
- % (self.occurrences,
- self.min_occurrences or 0,
- (' to %d' % self.max_occurrences)
- if self.max_occurrences is not None
- else ' or more'))
- utils.dump_parameters(context, self.properties)
-
-
-class ArtifactBase(structure.ModelMixin):
- """
- A file associated with a :class:`Node`.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`source_path`: Source path (CSAR or repository)
- * :code:`target_path`: Path at destination machine
- * :code:`repository_url`: Repository URL
- * :code:`repository_credential`: Dict of string
- * :code:`properties`: Dict of :class:`Parameter`
- """
- __tablename__ = 'artifact'
-
- __private_fields__ = ['node_fk']
-
- # region foreign_keys
-
- @declared_attr
- def node_fk(cls):
- return cls.foreign_key('node')
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- source_path = Column(Text)
- target_path = Column(Text)
- repository_url = Column(Text)
- repository_credential = Column(aria_types.StrictDict(basestring, basestring))
-
- # region many-to-one relationships
- @declared_attr
- def node(cls):
- return cls.many_to_one_relationship('node')
-
- # endregion
-
-
- # region many-to-many relationships
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('type_name', self.type_name),
- ('source_path', self.source_path),
- ('target_path', self.target_path),
- ('repository_url', self.repository_url),
- ('repository_credential', formatting.as_agnostic(self.repository_credential)),
- ('properties', formatting.as_raw_dict(self.properties))))
-
- def validate(self, context):
- if context.modeling.artifact_types.get_descendant(self.type_name) is None:
- context.validation.report('artifact "%s" has an unknown type: %s'
- % (self.name,
- formatting.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
- utils.validate_dict_values(context, self.properties)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
-
- def dump(self, context):
- console.puts(context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Artifact type: %s' % context.style.type(self.type_name))
- console.puts('Source path: %s' % context.style.literal(self.source_path))
- if self.target_path is not None:
- console.puts('Target path: %s' % context.style.literal(self.target_path))
- if self.repository_url is not None:
- console.puts('Repository URL: %s' % context.style.literal(self.repository_url))
- if self.repository_credential:
- console.puts('Repository credential: %s'
- % context.style.literal(self.repository_credential))
- utils.dump_parameters(context, self.properties)
-
-
-class PolicyBase(structure.ModelMixin):
- """
- An instance of a :class:`PolicyTemplate`.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`target_node_ids`: Must be represented in the :class:`ServiceInstance`
- * :code:`target_group_ids`: Must be represented in the :class:`ServiceInstance`
- """
- __tablename__ = 'policy'
-
- __private_fields__ = ['service_instance_fk']
-
- # region foreign_keys
-
- @declared_attr
- def service_instance_fk(cls):
- return cls.foreign_key('service_instance')
-
- # endregion
- type_name = Column(Text)
- target_node_ids = Column(aria_types.StrictList(basestring))
- target_group_ids = Column(aria_types.StrictList(basestring))
-
- # region many-to-one relationships
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance')
-
- # region many-to-many relationships
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('type_name', self.type_name),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('target_node_ids', self.target_node_ids),
- ('target_group_ids', self.target_group_ids)))
-
- def validate(self, context):
- if context.modeling.policy_types.get_descendant(self.type_name) is None:
- context.validation.report('policy "%s" has an unknown type: %s'
- % (self.name, utils.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.properties)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
-
- def dump(self, context):
- console.puts('Policy: %s' % context.style.node(self.name))
- with context.style.indent:
- console.puts('Type: %s' % context.style.type(self.type_name))
- utils.dump_parameters(context, self.properties)
- if self.target_node_ids:
- console.puts('Target nodes:')
- with context.style.indent:
- for node_id in self.target_node_ids:
- console.puts(context.style.node(node_id))
- if self.target_group_ids:
- console.puts('Target groups:')
- with context.style.indent:
- for group_id in self.target_group_ids:
- console.puts(context.style.node(group_id))
-
-
-class GroupPolicyBase(structure.ModelMixin):
- """
- Policies applied to groups.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`triggers`: Dict of :class:`GroupPolicyTrigger`
- """
- __tablename__ = 'group_policy'
-
- __private_fields__ = ['group_fk']
-
- # region foreign_keys
-
- @declared_attr
- def group_fk(cls):
- return cls.foreign_key('group')
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
-
- # region many-to-one relationships
- @declared_attr
- def group(cls):
- return cls.many_to_one_relationship('group')
-
- # end region
-
- # region many-to-many relationships
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('type_name', self.type_name),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('triggers', formatting.as_raw_list(self.triggers))))
-
- def validate(self, context):
- if context.modeling.policy_types.get_descendant(self.type_name) is None:
- context.validation.report(
- 'group policy "%s" has an unknown type: %s'
- % (self.name,
- formatting.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.properties)
- utils.validate_dict_values(context, self.triggers)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
- utils.coerce_dict_values(context, container, self.triggers, report_issues)
-
- def dump(self, context):
- console.puts(context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Group policy type: %s' % context.style.type(self.type_name))
- utils.dump_parameters(context, self.properties)
- utils.dump_dict_values(context, self.triggers, 'Triggers')
-
-
-class GroupPolicyTriggerBase(structure.ModelMixin):
- """
- Triggers for :class:`GroupPolicy`.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :code:`implementation`: Implementation string (interpreted by the orchestrator)
- * :code:`properties`: Dict of :class:`Parameter`
- """
- __tablename__ = 'group_policy_trigger'
-
- __private_fields__ = ['group_policy_fk']
-
- # region foreign keys
-
- @declared_attr
- def group_policy_fk(cls):
- return cls.foreign_key('group_policy')
-
- # endregion
-
- description = Column(Text)
- implementation = Column(Text)
-
- # region many-to-one relationships
-
- @declared_attr
- def group_policy(cls):
- return cls.many_to_one_relationship('group_policy')
-
- # endregion
-
- # region many-to-many relationships
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('implementation', self.implementation),
- ('properties', formatting.as_raw_dict(self.properties))))
-
- def validate(self, context):
- utils.validate_dict_values(context, self.properties)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
-
- def dump(self, context):
- console.puts(context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Implementation: %s' % context.style.literal(self.implementation))
- utils.dump_parameters(context, self.properties)
-
-
-class MappingBase(structure.ModelMixin):
- """
- An instance of a :class:`MappingTemplate`.
-
- Properties:
-
- * :code:`mapped_name`: Exposed capability or requirement name
- * :code:`node_id`: Must be represented in the :class:`ServiceInstance`
- * :code:`name`: Name of capability or requirement at the node
- """
- __tablename__ = 'mapping'
-
- mapped_name = Column(Text)
- node_id = Column(Text)
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('mapped_name', self.mapped_name),
- ('node_id', self.node_id),
- ('name', self.name)))
-
- def dump(self, context):
- console.puts('%s -> %s.%s'
- % (context.style.node(self.mapped_name),
- context.style.node(self.node_id),
- context.style.node(self.name)))
-
-
-class SubstitutionBase(structure.ModelMixin):
- """
- An instance of a :class:`SubstitutionTemplate`.
-
- Properties:
-
- * :code:`node_type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`capabilities`: Dict of :class:`Mapping`
- * :code:`requirements`: Dict of :class:`Mapping`
- """
- __tablename__ = 'substitution'
-
- node_type_name = Column(Text)
-
- # region many-to-many relationships
-
- @declared_attr
- def capabilities(cls):
- return cls.many_to_many_relationship('mapping', table_prefix='capabilities')
-
- @declared_attr
- def requirements(cls):
- return cls.many_to_many_relationship('mapping',
- table_prefix='requirements',
- relationship_kwargs=dict(lazy='dynamic'))
-
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('node_type_name', self.node_type_name),
- ('capabilities', formatting.as_raw_list(self.capabilities)),
- ('requirements', formatting.as_raw_list(self.requirements))))
-
- def validate(self, context):
- if context.modeling.node_types.get_descendant(self.node_type_name) is None:
- context.validation.report('substitution "%s" has an unknown type: %s'
- % (self.name, # pylint: disable=no-member
- # TODO fix self.name reference
- formatting.safe_repr(self.node_type_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.capabilities)
- utils.validate_dict_values(context, self.requirements)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.capabilities, report_issues)
- utils.coerce_dict_values(context, container, self.requirements, report_issues)
-
- def dump(self, context):
- console.puts('Substitution:')
- with context.style.indent:
- console.puts('Node type: %s' % context.style.type(self.node_type_name))
- utils.dump_dict_values(context, self.capabilities, 'Capability mappings')
- utils.dump_dict_values(context, self.requirements, 'Requirement mappings')
-
-
-# endregion
-
-# region Node instances
-
-class NodeBase(structure.ModelMixin):
- """
- An instance of a :class:`NodeTemplate`.
-
- Nodes may have zero or more :class:`Relationship` instances to other nodes.
-
- Properties:
-
- * :code:`id`: Unique ID (prefixed with the template name)
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`template_name`: Must be represented in the :class:`ServiceModel`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`interfaces`: Dict of :class:`Interface`
- * :code:`artifacts`: Dict of :class:`Artifact`
- * :code:`capabilities`: Dict of :class:`CapabilityTemplate`
- * :code:`relationships`: List of :class:`Relationship`
- """
- __tablename__ = 'node'
- version = Column(Integer, nullable=False)
- __mapper_args__ = {'version_id_col': version}
-
- __private_fields__ = ['service_instance_fk',
- 'host_fk',
- 'node_template_fk']
-
- # region foreign_keys
- @declared_attr
- def service_instance_fk(cls):
- return cls.foreign_key('service_instance')
-
- @declared_attr
- def host_fk(cls):
- return cls.foreign_key('node', nullable=True)
-
- @declared_attr
- def node_template_fk(cls):
- return cls.foreign_key('node_template')
-
- # endregion
-
- type_name = Column(Text)
- template_name = Column(Text)
-
- # region orchestrator required columns
- runtime_properties = Column(aria_types.Dict)
- scaling_groups = Column(aria_types.List)
- state = Column(Text, nullable=False)
-
- @declared_attr
- def plugins(cls):
- return association_proxy('node_template', 'plugins')
-
- @declared_attr
- def host(cls):
- return cls.relationship_to_self('host_fk')
-
- @declared_attr
- def service_instance_name(cls):
- return association_proxy('service_instance', 'name')
-
- @property
- def ip(self):
- if not self.host_fk:
- return None
- host_node = self.host
- if 'ip' in host_node.runtime_properties: # pylint: disable=no-member
- return host_node.runtime_properties['ip'] # pylint: disable=no-member
- host_node = host_node.node_template # pylint: disable=no-member
- host_ip_property = [prop for prop in host_node.properties if prop.name == 'ip']
- if host_ip_property:
- return host_ip_property[0].value
- return None
-
- @declared_attr
- def node_template(cls):
- return cls.many_to_one_relationship('node_template')
-
- @declared_attr
- def service_template(cls):
- return association_proxy('service_instance', 'service_template')
- # endregion
-
- # region many-to-one relationships
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance')
-
- # endregion
-
- # region many-to-many relationships
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- def satisfy_requirements(self, context):
- node_template = context.modeling.model.node_templates.get(self.template_name)
- satisfied = True
- for i in range(len(node_template.requirement_templates)):
- requirement_template = node_template.requirement_templates[i]
-
- # Find target template
- target_node_template, target_node_capability = \
- requirement_template.find_target(context, node_template)
- if target_node_template is not None:
- satisfied = self._satisfy_capability(context,
- target_node_capability,
- target_node_template,
- requirement_template,
- requirement_template_index=i)
- else:
- context.validation.report('requirement "%s" of node "%s" has no target node '
- 'template' % (requirement_template.name,
- self.id),
- level=validation.Issue.BETWEEN_INSTANCES)
- satisfied = False
- return satisfied
-
- def _satisfy_capability(self, context, target_node_capability, target_node_template,
- requirement_template, requirement_template_index):
- # Find target nodes
- target_nodes = context.modeling.instance.find_nodes(target_node_template.name)
- if target_nodes:
- target_node = None
- target_capability = None
-
- if target_node_capability is not None:
- # Relate to the first target node that has capacity
- for node in target_nodes:
- target_capability = node.capabilities.get(target_node_capability.name)
- if target_capability.relate():
- target_node = node
- break
- else:
- # Use first target node
- target_node = target_nodes[0]
-
- if target_node is not None:
- relationship = RelationshipBase(
- name=requirement_template.name,
- source_requirement_index=requirement_template_index,
- target_node_id=target_node.id,
- target_capability_name=target_capability.name
- )
- self.relationships.append(relationship)
- else:
- context.validation.report('requirement "%s" of node "%s" targets node '
- 'template "%s" but its instantiated nodes do not '
- 'have enough capacity'
- % (requirement_template.name,
- self.id,
- target_node_template.name),
- level=validation.Issue.BETWEEN_INSTANCES)
- return False
- else:
- context.validation.report('requirement "%s" of node "%s" targets node template '
- '"%s" but it has no instantiated nodes'
- % (requirement_template.name,
- self.id,
- target_node_template.name),
- level=validation.Issue.BETWEEN_INSTANCES)
- return False
-
- def validate_capabilities(self, context):
- satisfied = False
- for capability in self.capabilities.itervalues():
- if not capability.has_enough_relationships:
- context.validation.report('capability "%s" of node "%s" requires at least %d '
- 'relationships but has %d'
- % (capability.name,
- self.id,
- capability.min_occurrences,
- capability.occurrences),
- level=validation.Issue.BETWEEN_INSTANCES)
- satisfied = False
- return satisfied
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('id', self.id),
- ('type_name', self.type_name),
- ('template_name', self.template_name),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('interfaces', formatting.as_raw_list(self.interfaces)),
- ('artifacts', formatting.as_raw_list(self.artifacts)),
- ('capabilities', formatting.as_raw_list(self.capabilities)),
- ('relationships', formatting.as_raw_list(self.relationships))))
-
- def validate(self, context):
- if len(self.id) > context.modeling.id_max_length:
- context.validation.report('"%s" has an ID longer than the limit of %d characters: %d'
- % (self.id,
- context.modeling.id_max_length,
- len(self.id)),
- level=validation.Issue.BETWEEN_INSTANCES)
-
- # TODO: validate that node template is of type?
-
- utils.validate_dict_values(context, self.properties)
- utils.validate_dict_values(context, self.interfaces)
- utils.validate_dict_values(context, self.artifacts)
- utils.validate_dict_values(context, self.capabilities)
- utils.validate_list_values(context, self.relationships)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, self, self.properties, report_issues)
- utils.coerce_dict_values(context, self, self.interfaces, report_issues)
- utils.coerce_dict_values(context, self, self.artifacts, report_issues)
- utils.coerce_dict_values(context, self, self.capabilities, report_issues)
- utils.coerce_list_values(context, self, self.relationships, report_issues)
-
- def dump(self, context):
- console.puts('Node: %s' % context.style.node(self.id))
- with context.style.indent:
- console.puts('Template: %s' % context.style.node(self.template_name))
- console.puts('Type: %s' % context.style.type(self.type_name))
- utils.dump_parameters(context, self.properties)
- utils.dump_interfaces(context, self.interfaces)
- utils.dump_dict_values(context, self.artifacts, 'Artifacts')
- utils.dump_dict_values(context, self.capabilities, 'Capabilities')
- utils.dump_list_values(context, self.relationships, 'Relationships')
-
-
-class GroupBase(structure.ModelMixin):
- """
- An instance of a :class:`GroupTemplate`.
-
- Properties:
-
- * :code:`id`: Unique ID (prefixed with the template name)
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`template_name`: Must be represented in the :class:`ServiceModel`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`interfaces`: Dict of :class:`Interface`
- * :code:`policies`: Dict of :class:`GroupPolicy`
- * :code:`member_node_ids`: Must be represented in the :class:`ServiceInstance`
- * :code:`member_group_ids`: Must be represented in the :class:`ServiceInstance`
- """
- __tablename__ = 'group'
-
- __private_fields__ = ['service_instance_fk']
-
- # region foreign_keys
-
- @declared_attr
- def service_instance_fk(cls):
- return cls.foreign_key('service_instance')
-
- # endregion
-
- type_name = Column(Text)
- template_name = Column(Text)
- member_node_ids = Column(aria_types.StrictList(basestring))
- member_group_ids = Column(aria_types.StrictList(basestring))
-
- # region many-to-one relationships
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance')
-
- # region many-to-many relationships
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('id', self.id),
- ('type_name', self.type_name),
- ('template_name', self.template_name),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('interfaces', formatting.as_raw_list(self.interfaces)),
- ('policies', formatting.as_raw_list(self.policies)),
- ('member_node_ids', self.member_node_ids),
- ('member_group_ids', self.member_group_ids)))
-
- def validate(self, context):
- if context.modeling.group_types.get_descendant(self.type_name) is None:
- context.validation.report('group "%s" has an unknown type: %s'
- % (self.name, # pylint: disable=no-member
- # TODO fix self.name reference
- formatting.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.properties)
- utils.validate_dict_values(context, self.interfaces)
- utils.validate_dict_values(context, self.policies)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
- utils.coerce_dict_values(context, container, self.interfaces, report_issues)
- utils.coerce_dict_values(context, container, self.policies, report_issues)
-
- def dump(self, context):
- console.puts('Group: %s' % context.style.node(self.id))
- with context.style.indent:
- console.puts('Type: %s' % context.style.type(self.type_name))
- console.puts('Template: %s' % context.style.type(self.template_name))
- utils.dump_parameters(context, self.properties)
- utils.dump_interfaces(context, self.interfaces)
- utils.dump_dict_values(context, self.policies, 'Policies')
- if self.member_node_ids:
- console.puts('Member nodes:')
- with context.style.indent:
- for node_id in self.member_node_ids:
- console.puts(context.style.node(node_id))
-
-# endregion
-
-# region Relationship instances
-
-
-class RelationshipBase(structure.ModelMixin):
- """
- Connects :class:`Node` to another node.
-
- An instance of a :class:`RelationshipTemplate`.
-
- Properties:
-
- * :code:`name`: Name (usually the name of the requirement at the source node template)
- * :code:`source_requirement_index`: Must be represented in the source node template
- * :code:`target_node_id`: Must be represented in the :class:`ServiceInstance`
- * :code:`target_capability_name`: Matches the capability at the target node
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`template_name`: Must be represented in the :class:`ServiceModel`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`source_interfaces`: Dict of :class:`Interface`
- * :code:`target_interfaces`: Dict of :class:`Interface`
- """
- __tablename__ = 'relationship'
-
- __private_fields__ = ['source_node_fk',
- 'target_node_fk']
-
- source_requirement_index = Column(Integer)
- target_node_id = Column(Text)
- target_capability_name = Column(Text)
- type_name = Column(Text)
- template_name = Column(Text)
- type_hierarchy = Column(aria_types.List)
-
- # region orchestrator required columns
- source_position = Column(Integer)
- target_position = Column(Integer)
-
- @declared_attr
- def source_node_fk(cls):
- return cls.foreign_key('node', nullable=True)
-
- @declared_attr
- def source_node(cls):
- return cls.many_to_one_relationship(
- 'node',
- '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_node_name(cls):
- return association_proxy('source_node', cls.name_column_name())
-
- @declared_attr
- def target_node_fk(cls):
- return cls.foreign_key('node', nullable=True)
-
- @declared_attr
- def target_node(cls):
- return cls.many_to_one_relationship(
- 'node',
- '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_node_name(cls):
- return association_proxy('target_node', cls.name_column_name())
- # endregion
-
- # region many-to-many relationship
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('source_requirement_index', self.source_requirement_index),
- ('target_node_id', self.target_node_id),
- ('target_capability_name', self.target_capability_name),
- ('type_name', self.type_name),
- ('template_name', self.template_name),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('source_interfaces', formatting.as_raw_list(self.source_interfaces)),
- ('target_interfaces', formatting.as_raw_list(self.target_interfaces))))
-
- def validate(self, context):
- if self.type_name:
- if context.modeling.relationship_types.get_descendant(self.type_name) is None:
- context.validation.report('relationship "%s" has an unknown type: %s'
- % (self.name,
- formatting.safe_repr(self.type_name)),
- level=validation.Issue.BETWEEN_TYPES)
- utils.validate_dict_values(context, self.properties)
- utils.validate_dict_values(context, self.source_interfaces)
- utils.validate_dict_values(context, self.target_interfaces)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, container, self.properties, report_issues)
- utils.coerce_dict_values(context, container, self.source_interfaces, report_issues)
- utils.coerce_dict_values(context, container, self.target_interfaces, report_issues)
-
- def dump(self, context):
- if self.name:
- if self.source_requirement_index is not None:
- console.puts('%s (%d) ->' % (
- context.style.node(self.name),
- self.source_requirement_index))
- else:
- console.puts('%s ->' % context.style.node(self.name))
- else:
- console.puts('->')
- with context.style.indent:
- console.puts('Node: %s' % context.style.node(self.target_node_id))
- if self.target_capability_name is not None:
- console.puts('Capability: %s' % context.style.node(self.target_capability_name))
- if self.type_name is not None:
- console.puts('Relationship type: %s' % context.style.type(self.type_name))
- if self.template_name is not None:
- console.puts('Relationship template: %s' % context.style.node(self.template_name))
- utils.dump_parameters(context, self.properties)
- utils.dump_interfaces(context, self.source_interfaces, 'Source interfaces')
- utils.dump_interfaces(context, self.target_interfaces, 'Target interfaces')
-
-# endregion
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9841ca4a/aria/storage/modeling/model.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/model.py b/aria/storage/modeling/model.py
deleted file mode 100644
index cf7d933..0000000
--- a/aria/storage/modeling/model.py
+++ /dev/null
@@ -1,223 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from sqlalchemy.ext.declarative import declarative_base
-
-from . import (
- template_elements,
- instance_elements,
- orchestrator_elements,
- elements,
- structure,
-)
-
-__all__ = (
- 'aria_declarative_base',
-
- 'Parameter',
-
- 'MappingTemplate',
- 'InterfaceTemplate',
- 'OperationTemplate',
- 'ServiceTemplate',
- 'NodeTemplate',
- 'GroupTemplate',
- 'ArtifactTemplate',
- 'PolicyTemplate',
- 'GroupPolicyTemplate',
- 'GroupPolicyTriggerTemplate',
- 'RequirementTemplate',
- 'CapabilityTemplate',
-
- 'Mapping',
- 'Substitution',
- 'ServiceInstance',
- 'Node',
- 'Relationship',
- 'Artifact',
- 'Group',
- 'Interface',
- 'Operation',
- 'Capability',
- 'Policy',
- 'GroupPolicy',
- 'GroupPolicyTrigger',
-
- 'Execution',
- 'ServiceInstanceUpdate',
- 'ServiceInstanceUpdateStep',
- 'ServiceInstanceModification',
- 'Plugin',
- 'Task'
-)
-
-aria_declarative_base = declarative_base(cls=structure.ModelIDMixin)
-
-# pylint: disable=abstract-method
-
-# region elements
-
-
-class Parameter(aria_declarative_base, elements.ParameterBase):
- pass
-
-# endregion
-
-# region template models
-
-
-class MappingTemplate(aria_declarative_base, template_elements.MappingTemplateBase):
- pass
-
-
-class SubstitutionTemplate(aria_declarative_base, template_elements.SubstitutionTemplateBase):
- pass
-
-
-class InterfaceTemplate(aria_declarative_base, template_elements.InterfaceTemplateBase):
- pass
-
-
-class OperationTemplate(aria_declarative_base, template_elements.OperationTemplateBase):
- pass
-
-
-class ServiceTemplate(aria_declarative_base, template_elements.ServiceTemplateBase):
- pass
-
-
-class NodeTemplate(aria_declarative_base, template_elements.NodeTemplateBase):
- pass
-
-
-class GroupTemplate(aria_declarative_base, template_elements.GroupTemplateBase):
- pass
-
-
-class ArtifactTemplate(aria_declarative_base, template_elements.ArtifactTemplateBase):
- pass
-
-
-class PolicyTemplate(aria_declarative_base, template_elements.PolicyTemplateBase):
- pass
-
-
-class GroupPolicyTemplate(aria_declarative_base, template_elements.GroupPolicyTemplateBase):
- pass
-
-
-class GroupPolicyTriggerTemplate(aria_declarative_base,
- template_elements.GroupPolicyTriggerTemplateBase):
- pass
-
-
-class RequirementTemplate(aria_declarative_base, template_elements.RequirementTemplateBase):
- pass
-
-
-class CapabilityTemplate(aria_declarative_base, template_elements.CapabilityTemplateBase):
- pass
-
-
-# endregion
-
-# region instance models
-
-class Mapping(aria_declarative_base, instance_elements.MappingBase):
- pass
-
-
-class Substitution(aria_declarative_base, instance_elements.SubstitutionBase):
- pass
-
-
-class ServiceInstance(aria_declarative_base, instance_elements.ServiceInstanceBase):
- pass
-
-
-class Node(aria_declarative_base, instance_elements.NodeBase):
- pass
-
-
-class Relationship(aria_declarative_base, instance_elements.RelationshipBase):
- pass
-
-
-class Artifact(aria_declarative_base, instance_elements.ArtifactBase):
- pass
-
-
-class Group(aria_declarative_base, instance_elements.GroupBase):
- pass
-
-
-class Interface(aria_declarative_base, instance_elements.InterfaceBase):
- pass
-
-
-class Operation(aria_declarative_base, instance_elements.OperationBase):
- pass
-
-
-class Capability(aria_declarative_base, instance_elements.CapabilityBase):
- pass
-
-
-class Policy(aria_declarative_base, instance_elements.PolicyBase):
- pass
-
-
-class GroupPolicy(aria_declarative_base, instance_elements.GroupPolicyBase):
- pass
-
-
-class GroupPolicyTrigger(aria_declarative_base, instance_elements.GroupPolicyTriggerBase):
- pass
-
-
-# endregion
-
-# region orchestrator models
-
-class Execution(aria_declarative_base, orchestrator_elements.Execution):
- pass
-
-
-class ServiceInstanceUpdate(aria_declarative_base,
- orchestrator_elements.ServiceInstanceUpdateBase):
- pass
-
-
-class ServiceInstanceUpdateStep(aria_declarative_base,
- orchestrator_elements.ServiceInstanceUpdateStepBase):
- pass
-
-
-class ServiceInstanceModification(aria_declarative_base,
- orchestrator_elements.ServiceInstanceModificationBase):
- pass
-
-
-class Plugin(aria_declarative_base, orchestrator_elements.PluginBase):
- pass
-
-
-class Task(aria_declarative_base, orchestrator_elements.TaskBase):
- pass
-
-
-class Log(aria_declarative_base, orchestrator_elements.LogBase):
- pass
-# endregion
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9841ca4a/aria/storage/modeling/orchestrator_elements.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/orchestrator_elements.py b/aria/storage/modeling/orchestrator_elements.py
deleted file mode 100644
index ef773ed..0000000
--- a/aria/storage/modeling/orchestrator_elements.py
+++ /dev/null
@@ -1,497 +0,0 @@
-# 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 import (
- Column,
- Integer,
- Text,
- DateTime,
- Boolean,
- Enum,
- String,
- Float,
- orm,
-)
-from sqlalchemy.ext.associationproxy import association_proxy
-from sqlalchemy.ext.declarative import declared_attr
-
-from aria.orchestrator.exceptions import TaskAbortException, TaskRetryException
-
-from .type import List, Dict
-from .structure import ModelMixin
-
-__all__ = (
- 'ServiceInstanceUpdateStepBase',
- 'ServiceInstanceUpdateBase',
- 'ServiceInstanceModificationBase',
- 'Execution',
- 'PluginBase',
- 'TaskBase'
-)
-
-# pylint: disable=no-self-argument, no-member, abstract-method
-
-
-class Execution(ModelMixin):
- """
- Execution model representation.
- """
- # Needed only for pylint. the id will be populated by sqlalcehmy and the proper column.
- __tablename__ = 'execution'
-
- __private_fields__ = ['service_instance_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 service_template(cls):
- return association_proxy('service_instance', 'service_template')
-
- @declared_attr
- def service_instance_fk(cls):
- return cls.foreign_key('service_instance')
-
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance')
-
- @declared_attr
- def service_instance_name(cls):
- return association_proxy('service_instance', cls.name_column_name())
-
- @declared_attr
- def service_template_name(cls):
- return association_proxy('service_instance', 'service_template_name')
-
- def __str__(self):
- return '<{0} id=`{1}` (status={2})>'.format(
- self.__class__.__name__,
- getattr(self, self.name_column_name()),
- self.status
- )
-
-
-class ServiceInstanceUpdateBase(ModelMixin):
- """
- Deployment update model representation.
- """
- # Needed only for pylint. the id will be populated by sqlalcehmy and the proper column.
- steps = None
-
- __tablename__ = 'service_instance_update'
- __private_fields__ = ['service_instance_fk',
- 'execution_fk']
-
- _private_fields = ['execution_fk', 'deployment_fk']
-
- created_at = Column(DateTime, nullable=False, index=True)
- service_instance_plan = Column(Dict, nullable=False)
- service_instance_update_node_instances = Column(Dict)
- service_instance_update_service_instance = Column(Dict)
- service_instance_update_nodes = Column(List)
- modified_entity_ids = Column(Dict)
- state = Column(Text)
-
- @declared_attr
- def execution_fk(cls):
- return cls.foreign_key('execution', nullable=True)
-
- @declared_attr
- def execution(cls):
- return cls.many_to_one_relationship('execution')
-
- @declared_attr
- def execution_name(cls):
- return association_proxy('execution', cls.name_column_name())
-
- @declared_attr
- def service_instance_fk(cls):
- return cls.foreign_key('service_instance')
-
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance')
-
- @declared_attr
- def service_instance_name(cls):
- return association_proxy('service_instance', cls.name_column_name())
-
- def to_dict(self, suppress_error=False, **kwargs):
- dep_update_dict = super(ServiceInstanceUpdateBase, 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 ServiceInstanceUpdateStepBase(ModelMixin):
- """
- Deployment update step model representation.
- """
- # Needed only for pylint. the id will be populated by sqlalcehmy and the proper column.
- __tablename__ = 'service_instance_update_step'
- __private_fields__ = ['service_instance_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 service_instance_update_fk(cls):
- return cls.foreign_key('service_instance_update')
-
- @declared_attr
- def service_instance_update(cls):
- return cls.many_to_one_relationship('service_instance_update',
- 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 ServiceInstanceModificationBase(ModelMixin):
- """
- Deployment modification model representation.
- """
- __tablename__ = 'service_instance_modification'
- __private_fields__ = ['service_instance_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 service_instance_fk(cls):
- return cls.foreign_key('service_instance')
-
- @declared_attr
- def service_instance(cls):
- return cls.many_to_one_relationship('service_instance',
- backreference='modifications')
-
- @declared_attr
- def service_instance_name(cls):
- return association_proxy('service_instance', cls.name_column_name())
-
-
-class PluginBase(ModelMixin):
- """
- Plugin model representation.
- """
- __tablename__ = 'plugin'
-
- 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__ = 'task'
- __private_fields__ = ['node_fk',
- 'relationship_fk',
- 'execution_fk',
- 'plugin_fk']
-
- @declared_attr
- def node_fk(cls):
- return cls.foreign_key('node', nullable=True)
-
- @declared_attr
- def node_name(cls):
- return association_proxy('node', cls.name_column_name())
-
- @declared_attr
- def node(cls):
- return cls.many_to_one_relationship('node')
-
- @declared_attr
- def relationship_fk(cls):
- return cls.foreign_key('relationship', nullable=True)
-
- @declared_attr
- def relationship_name(cls):
- return association_proxy('relationships', cls.name_column_name())
-
- @declared_attr
- def relationship(cls):
- return cls.many_to_one_relationship('relationship')
-
- @declared_attr
- def plugin_fk(cls):
- return cls.foreign_key('plugin', nullable=True)
-
- @declared_attr
- def plugin(cls):
- return cls.many_to_one_relationship('plugin')
-
- @declared_attr
- def execution_fk(cls):
- return cls.foreign_key('execution', nullable=True)
-
- @declared_attr
- def execution(cls):
- return cls.many_to_one_relationship('execution')
-
- @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]
-
- RUNS_ON_SOURCE = 'source'
- RUNS_ON_TARGET = 'target'
- RUNS_ON_NODE_INSTANCE = 'node_instance'
- RUNS_ON = (RUNS_ON_NODE_INSTANCE, RUNS_ON_SOURCE, RUNS_ON_TARGET)
-
- @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
- implementation = Column(String)
- inputs = Column(Dict)
- # This is unrelated to the plugin of the task. This field is related to the plugin name
- # received from the blueprint.
- plugin_name = Column(String)
- _runs_on = Column(Enum(*RUNS_ON, name='runs_on'), name='runs_on')
-
- @property
- def runs_on(self):
- if self._runs_on == self.RUNS_ON_NODE_INSTANCE:
- return self.node
- elif self._runs_on == self.RUNS_ON_SOURCE:
- return self.relationship.source_node # pylint: disable=no-member
- elif self._runs_on == self.RUNS_ON_TARGET:
- return self.relationship.target_node # pylint: disable=no-member
- return None
-
- @property
- def actor(self):
- """
- Return the actor of the task
- :return:
- """
- return self.node or self.relationship
-
- @classmethod
- def as_node_instance(cls, instance, runs_on, **kwargs):
- return cls(node=instance, _runs_on=runs_on, **kwargs)
-
- @classmethod
- def as_relationship_instance(cls, instance, runs_on, **kwargs):
- return cls(relationship=instance, _runs_on=runs_on, **kwargs)
-
- @staticmethod
- def abort(message=None):
- raise TaskAbortException(message)
-
- @staticmethod
- def retry(message=None, retry_interval=None):
- raise TaskRetryException(message, retry_interval=retry_interval)
-
-
-class LogBase(ModelMixin):
- __tablename__ = 'log'
-
- @declared_attr
- def execution_fk(cls):
- return cls.foreign_key('execution')
-
- @declared_attr
- def execution(cls):
- return cls.many_to_one_relationship('execution')
-
- @declared_attr
- def task_fk(cls):
- return cls.foreign_key('task', nullable=True)
-
- @declared_attr
- def task(cls):
- return cls.many_to_one_relationship('task')
-
- level = Column(String)
- msg = Column(String)
- created_at = Column(DateTime, index=True)
- actor = Column(String)
-
- def __repr__(self):
- return "<{self.created_at}: [{self.level}] @{self.actor}> {msg}".format(
- self=self, msg=self.msg[:50])
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/9841ca4a/aria/storage/modeling/structure.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/structure.py b/aria/storage/modeling/structure.py
deleted file mode 100644
index eacdb44..0000000
--- a/aria/storage/modeling/structure.py
+++ /dev/null
@@ -1,320 +0,0 @@
-# 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.structures module
-Path: aria.storage.structures
-
-models module holds aria's models.
-
-classes:
- * Field - represents a single field.
- * IterField - represents an iterable field.
- * PointerField - represents a single pointer field.
- * IterPointerField - represents an iterable pointers field.
- * Model - abstract model implementation.
-"""
-
-from sqlalchemy.orm import relationship, backref
-from sqlalchemy.ext import associationproxy
-from sqlalchemy import (
- Column,
- ForeignKey,
- Integer,
- Text,
- Table,
-)
-
-from . import utils
-
-
-class Function(object):
- """
- An intrinsic function.
-
- Serves as a placeholder for a value that should eventually be derived
- by calling the function.
- """
-
- @property
- def as_raw(self):
- raise NotImplementedError
-
- def _evaluate(self, context, container):
- raise NotImplementedError
-
- def __deepcopy__(self, memo):
- # Circumvent cloning in order to maintain our state
- return self
-
-
-class ElementBase(object):
- """
- Base class for :class:`ServiceInstance` elements.
-
- All elements support validation, diagnostic dumping, and representation as
- raw data (which can be translated into JSON or YAML) via :code:`as_raw`.
- """
-
- @property
- def as_raw(self):
- raise NotImplementedError
-
- def validate(self, context):
- pass
-
- def coerce_values(self, context, container, report_issues):
- pass
-
- def dump(self, context):
- pass
-
-
-class ModelElementBase(ElementBase):
- """
- Base class for :class:`ServiceModel` elements.
-
- All model elements can be instantiated into :class:`ServiceInstance` elements.
- """
-
- def instantiate(self, context, container):
- raise NotImplementedError
-
-
-class ModelMixin(ModelElementBase):
-
- @utils.classproperty
- def __modelname__(cls): # pylint: disable=no-self-argument
- return getattr(cls, '__mapiname__', cls.__tablename__)
-
- @classmethod
- def id_column_name(cls):
- raise NotImplementedError
-
- @classmethod
- def name_column_name(cls):
- raise NotImplementedError
-
- @classmethod
- def _get_cls_by_tablename(cls, tablename):
- """Return class reference mapped to table.
-
- :param tablename: String with name of table.
- :return: Class reference or None.
- """
- if tablename in (cls.__name__, cls.__tablename__):
- return cls
-
- for table_cls in cls._decl_class_registry.values():
- if tablename == getattr(table_cls, '__tablename__', None):
- return table_cls
-
- @classmethod
- 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
- """
- return Column(Integer,
- ForeignKey('{tablename}.id'.format(tablename=table_name), ondelete='CASCADE'),
- nullable=nullable)
-
- @classmethod
- 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,
- parent_table_name,
- foreign_key_column=None,
- backreference=None,
- backref_kwargs=None,
- **kwargs):
- """Return a one-to-many SQL relationship object
- Meant to be used from inside the *child* object
-
- :param parent_class: Class of the parent table
- :param cls: Class of the child table
- :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)
- """
- relationship_kwargs = kwargs
- if foreign_key_column:
- relationship_kwargs.setdefault('foreign_keys', getattr(cls, foreign_key_column))
-
- backref_kwargs = backref_kwargs or {}
- backref_kwargs.setdefault('lazy', 'dynamic')
- # The following line make sure that when the *parent* is
- # deleted, all its connected children are deleted as well
- backref_kwargs.setdefault('cascade', 'all')
-
- return relationship(lambda: cls._get_cls_by_tablename(parent_table_name),
- backref=backref(backreference or utils.pluralize(cls.__tablename__),
- **backref_kwargs or {}),
- **relationship_kwargs)
-
- @classmethod
- def relationship_to_self(cls, local_column):
-
- remote_side_str = '{cls.__name__}.{remote_column}'.format(
- cls=cls,
- remote_column=cls.id_column_name()
- )
- primaryjoin_str = '{remote_side_str} == {cls.__name__}.{local_column}'.format(
- remote_side_str=remote_side_str,
- cls=cls,
- local_column=local_column)
- 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_table_name, table_prefix, relationship_kwargs=None):
- """Return a many-to-many SQL relationship object
-
- Notes:
- 1. The backreference name is the current table's table name
- 2. This method creates a new helper table in the DB
-
- :param cls: The class of the table we're connecting from
- :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}.id'.format(current_table_name)
-
- other_column_name = '{0}_id'.format(other_table_name)
- other_foreign_key = '{0}.id'.format(other_table_name)
-
- helper_table_name = '{0}_{1}'.format(current_table_name, other_table_name)
-
- backref_name = current_table_name
- if table_prefix:
- helper_table_name = '{0}_{1}'.format(table_prefix, helper_table_name)
- backref_name = '{0}_{1}'.format(table_prefix, backref_name)
-
- secondary_table = cls.get_secondary_table(
- cls.metadata,
- helper_table_name,
- current_column_name,
- other_column_name,
- current_foreign_key,
- other_foreign_key
- )
-
- return relationship(
- lambda: cls._get_cls_by_tablename(other_table_name),
- secondary=secondary_table,
- backref=backref(backref_name),
- **(relationship_kwargs or {})
- )
-
- @staticmethod
- def get_secondary_table(metadata,
- helper_table_name,
- first_column_name,
- second_column_name,
- first_foreign_key,
- second_foreign_key):
- """Create a helper table for a many-to-many relationship
-
- :param helper_table_name: The name of the table
- :param first_column_name: The name of the first column in the table
- :param second_column_name: The name of the second column in the table
- :param first_foreign_key: The string representing the first foreign key,
- for example `blueprint.storage_id`, or `tenants.id`
- :param second_foreign_key: The string representing the second foreign key
- :return: A Table object
- """
- return Table(
- helper_table_name,
- metadata,
- Column(
- first_column_name,
- Integer,
- ForeignKey(first_foreign_key)
- ),
- Column(
- second_column_name,
- Integer,
- ForeignKey(second_foreign_key)
- )
- )
-
- def to_dict(self, fields=None, suppress_error=False):
- """Return a dict representation of the model
-
- :param suppress_error: If set to True, sets `None` to attributes that
- it's unable to retrieve (e.g., if a relationship wasn't established
- yet, and so it's impossible to access a property through it)
- """
- res = dict()
- fields = fields or self.fields()
- for field in fields:
- try:
- field_value = getattr(self, field)
- except AttributeError:
- if suppress_error:
- field_value = None
- else:
- raise
- if isinstance(field_value, list):
- 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
-
- @classmethod
- def _association_proxies(cls):
- for col, value in vars(cls).items():
- if isinstance(value, associationproxy.AssociationProxy):
- yield col
-
- @classmethod
- def fields(cls):
- """Return the list of field names for this table
-
- Mostly for backwards compatibility in the code (that uses `fields`)
- """
- fields = set(cls._association_proxies())
- fields.update(cls.__table__.columns.keys())
- return fields - set(getattr(cls, '__private_fields__', []))
-
- def __repr__(self):
- return '<{__class__.__name__} id=`{id}`>'.format(
- __class__=self.__class__,
- id=getattr(self, self.name_column_name()))
-
-
-class ModelIDMixin(object):
- id = Column(Integer, primary_key=True, autoincrement=True)
- name = Column(Text, nullable=True, index=True)
-
- @classmethod
- def id_column_name(cls):
- return 'id'
-
- @classmethod
- def name_column_name(cls):
- return 'name'