You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by em...@apache.org on 2017/02/17 22:01:07 UTC
[2/5] incubator-ariatosca git commit: Initial refactoring (mostly
broken)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/58e10523/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'
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/58e10523/aria/storage/modeling/template_elements.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/template_elements.py b/aria/storage/modeling/template_elements.py
deleted file mode 100644
index 4212b15..0000000
--- a/aria/storage/modeling/template_elements.py
+++ /dev/null
@@ -1,1387 +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 copy import deepcopy
-from types import FunctionType
-
-from sqlalchemy import (
- Column,
- Text,
- Integer,
- DateTime,
- Boolean,
-)
-from sqlalchemy.ext.associationproxy import association_proxy
-from sqlalchemy.ext.declarative import declared_attr
-
-from aria.parser import validation
-from aria.utils import collections, formatting, console
-
-from . import (
- utils,
- instance_elements,
- structure,
- type as aria_type
-)
-
-# pylint: disable=no-self-argument, no-member, abstract-method
-
-
-# region Element templates
-
-
-class ServiceTemplateBase(structure.ModelMixin):
-
- __tablename__ = 'service_template'
-
- __private_fields__ = ['substitution_template_fk']
-
- description = Column(Text)
- metadata = Column(Text)
-
- # region orchestrator required columns
-
- created_at = Column(DateTime, nullable=False, index=True)
- main_file_name = Column(Text)
- plan = Column(aria_type.Dict, nullable=False)
- updated_at = Column(DateTime)
-
- # endregion
-
- # region foreign keys
- @declared_attr
- def substitution_template_fk(cls):
- return cls.foreign_key('substitution_template', nullable=True)
-
- # endregion
-
- # region one-to-one relationships
- @declared_attr
- def substitution_template(cls):
- return cls.one_to_one_relationship('substitution_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
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('description', self.description),
- ('metadata', formatting.as_raw(self.metadata)),
- ('node_templates', formatting.as_raw_list(self.node_templates)),
- ('group_templates', formatting.as_raw_list(self.group_templates)),
- ('policy_templates', formatting.as_raw_list(self.policy_templates)),
- ('substitution_template', formatting.as_raw(self.substitution_template)),
- ('inputs', formatting.as_raw_dict(self.inputs)),
- ('outputs', formatting.as_raw_dict(self.outputs)),
- ('operation_templates', formatting.as_raw_list(self.operation_templates))))
-
- def instantiate(self, context, container):
- service_instance = instance_elements.ServiceInstanceBase()
- context.modeling.instance = service_instance
-
- service_instance.description = deepcopy_with_locators(self.description)
-
- if self.metadata is not None:
- service_instance.metadata = self.metadata.instantiate(context, container)
-
- for node_template in self.node_templates.itervalues():
- for _ in range(node_template.default_instances):
- node = node_template.instantiate(context, container)
- service_instance.nodes[node.id] = node
-
- utils.instantiate_dict(context, self, service_instance.groups, self.group_templates)
- utils.instantiate_dict(context, self, service_instance.policies, self.policy_templates)
- utils.instantiate_dict(context, self, service_instance.operations, self.operation_templates)
-
- if self.substitution_template is not None:
- service_instance.substitution = self.substitution_template.instantiate(context,
- container)
-
- utils.instantiate_dict(context, self, service_instance.inputs, self.inputs)
- utils.instantiate_dict(context, self, service_instance.outputs, self.outputs)
-
- for name, the_input in context.modeling.inputs.iteritems():
- if name not in service_instance.inputs:
- context.validation.report('input "%s" is not supported' % name)
- else:
- service_instance.inputs[name].value = the_input
-
- return service_instance
-
- def validate(self, context):
- if self.metadata is not None:
- self.metadata.validate(context)
- utils.validate_dict_values(context, self.node_templates)
- utils.validate_dict_values(context, self.group_templates)
- utils.validate_dict_values(context, self.policy_templates)
- if self.substitution_template is not None:
- self.substitution_template.validate(context)
- utils.validate_dict_values(context, self.inputs)
- utils.validate_dict_values(context, self.outputs)
- utils.validate_dict_values(context, self.operation_templates)
-
- def coerce_values(self, context, container, report_issues):
- if self.metadata is not None:
- self.metadata.coerce_values(context, container, report_issues)
- utils.coerce_dict_values(context, container, self.node_templates, report_issues)
- utils.coerce_dict_values(context, container, self.group_templates, report_issues)
- utils.coerce_dict_values(context, container, self.policy_templates, report_issues)
- if self.substitution_template is not None:
- self.substitution_template.coerce_values(context, container, report_issues)
- utils.coerce_dict_values(context, container, self.inputs, report_issues)
- utils.coerce_dict_values(context, container, self.outputs, report_issues)
- utils.coerce_dict_values(context, container, self.operation_templates, report_issues)
-
- def dump(self, context):
- if self.description is not None:
- console.puts(context.style.meta(self.description))
- if self.metadata is not None:
- self.metadata.dump(context)
- for node_template in self.node_templates.itervalues():
- node_template.dump(context)
- for group_template in self.group_templates.itervalues():
- group_template.dump(context)
- for policy_template in self.policy_templates.itervalues():
- policy_template.dump(context)
- if self.substitution_template is not None:
- self.substitution_template.dump(context)
- dump_parameters(context, self.inputs, 'Inputs')
- dump_parameters(context, self.outputs, 'Outputs')
- utils.dump_dict_values(context, self.operation_templates, 'Operation templates')
-
-
-class InterfaceTemplateBase(structure.ModelMixin):
- __tablename__ = 'interface_template'
-
- __private_fields__ = ['node_template_fk',
- 'group_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def node_template_fk(cls):
- return cls.foreign_key('node_template', nullable=True)
-
- @declared_attr
- def group_template_fk(cls):
- return cls.foreign_key('group_template', nullable=True)
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
-
- # region many-to-one relationship
- @declared_attr
- def node_template(cls):
- return cls.many_to_one_relationship('node_template')
-
- @declared_attr
- def group_template(cls):
- return cls.many_to_one_relationship('group_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 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),
- ('inputs', formatting.as_raw_dict(self.properties)), # pylint: disable=no-member
- # TODO fix self.properties reference
- ('operation_templates', formatting.as_raw_list(self.operation_templates))))
-
- def instantiate(self, context, container):
- interface = instance_elements.InterfaceBase(self.name, self.type_name)
- interface.description = deepcopy_with_locators(self.description)
- utils.instantiate_dict(context, container, interface.inputs, self.inputs)
- utils.instantiate_dict(context, container, interface.operations, self.operation_templates)
- return interface
-
- 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.operation_templates)
-
- 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.operation_templates, 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))
- dump_parameters(context, self.inputs, 'Inputs')
- utils.dump_dict_values(context, self.operation_templates, 'Operation templates')
-
-
-class OperationTemplateBase(structure.ModelMixin):
- __tablename__ = 'operation_template'
-
- __private_fields__ = ['service_template_fk',
- 'interface_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def service_template_fk(cls):
- return cls.foreign_key('service_template', nullable=True)
-
- @declared_attr
- def interface_template_fk(cls):
- return cls.foreign_key('interface_template', nullable=True)
-
- # endregion
-
- description = Column(Text)
- implementation = Column(Text)
- dependencies = Column(aria_type.StrictList(item_cls=basestring))
- executor = Column(Text)
- max_retries = Column(Integer)
- retry_interval = Column(Integer)
-
- # region orchestrator required columns
- plugin = Column(Text)
- operation = Column(Boolean)
-
- # region many-to-one relationships
- @declared_attr
- def service_template(cls):
- return cls.many_to_one_relationship('service_template')
-
- @declared_attr
- def interface_template(cls):
- return cls.many_to_one_relationship('interface_template')
- # 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),
- ('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 instantiate(self, context, container):
- operation = instance_elements.OperationBase(self.name)
- operation.description = deepcopy_with_locators(self.description)
- operation.implementation = self.implementation
- operation.dependencies = self.dependencies
- operation.executor = self.executor
- operation.max_retries = self.max_retries
- operation.retry_interval = self.retry_interval
- utils.instantiate_dict(context, container, operation.inputs, self.inputs)
- return operation
-
- 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))
- dump_parameters(context, self.inputs, 'Inputs')
-
-
-class ArtifactTemplateBase(structure.ModelMixin):
- """
- A file associated with a :class:`NodeTemplate`.
-
- 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_template'
-
- __private_fields__ = ['node_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def node_template_fk(cls):
- return cls.foreign_key('node_template')
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- source_path = Column(Text)
- target_path = Column(Text)
- repository_url = Column(Text)
- repository_credential = Column(aria_type.StrictDict(basestring, basestring))
-
- # region many-to-one relationship
- @declared_attr
- def node_template(cls):
- return cls.many_to_one_relationship('node_template')
- # 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.iteritems()))))
-
- def instantiate(self, context, container):
- artifact = instance_elements.ArtifactBase(self.name, self.type_name, self.source_path)
- artifact.description = deepcopy_with_locators(self.description)
- artifact.target_path = self.target_path
- artifact.repository_url = self.repository_url
- artifact.repository_credential = self.repository_credential
- utils.instantiate_dict(context, container, artifact.properties, self.properties)
- return artifact
-
- 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))
- dump_parameters(context, self.properties)
-
-
-class PolicyTemplateBase(structure.ModelMixin):
- """
- Policies can be applied to zero or more :class:`NodeTemplate` or :class:`GroupTemplate`
- instances.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`target_node_template_names`: Must be represented in the :class:`ServiceModel`
- * :code:`target_group_template_names`: Must be represented in the :class:`ServiceModel`
- """
- __tablename__ = 'policy_template'
-
- __private_fields__ = ['service_templaet_fk',
- 'group_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def service_template_fk(cls):
- return cls.foreign_key('service_template')
-
- @declared_attr
- def group_template_fk(cls):
- return cls.foreign_key('group_template')
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- target_node_template_names = Column(aria_type.StrictList(basestring))
- target_group_template_names = Column(aria_type.StrictList(basestring))
-
- # region many-to-one relationship
- @declared_attr
- def service_template(cls):
- return cls.many_to_one_relationship('service_template')
-
- @declared_attr
- def group_template(cls):
- return cls.many_to_one_relationship('group_template')
-
- # 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),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('target_node_template_names', self.target_node_template_names),
- ('target_group_template_names', self.target_group_template_names)))
-
- def instantiate(self, context, *args, **kwargs):
- policy = instance_elements.PolicyBase(self.name, self.type_name)
- utils.instantiate_dict(context, self, policy.properties, self.properties)
- for node_template_name in self.target_node_template_names:
- policy.target_node_ids.extend(
- context.modeling.instance.get_node_ids(node_template_name))
- for group_template_name in self.target_group_template_names:
- policy.target_group_ids.extend(
- context.modeling.instance.get_group_ids(group_template_name))
- return policy
-
- def validate(self, context):
- if context.modeling.policy_types.get_descendant(self.type_name) is None:
- context.validation.report('policy template "%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, self, self.properties, report_issues)
-
- def dump(self, context):
- console.puts('Policy template: %s' % context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Type: %s' % context.style.type(self.type_name))
- dump_parameters(context, self.properties)
- if self.target_node_template_names:
- console.puts('Target node templates: %s' % ', '.join(
- (str(context.style.node(v)) for v in self.target_node_template_names)))
- if self.target_group_template_names:
- console.puts('Target group templates: %s' % ', '.join(
- (str(context.style.node(v)) for v in self.target_group_template_names)))
-
-
-class GroupPolicyTemplateBase(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_template'
-
- __private_fields__ = ['group_template_fk']
-
- # region foreign keys
- @declared_attr
- def group_template_fk(cls):
- return cls.foreign_key('group_template')
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
-
- # 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 instantiate(self, context, container):
- group_policy = instance_elements.GroupPolicyBase(self.name, self.type_name)
- group_policy.description = deepcopy_with_locators(self.description)
- utils.instantiate_dict(context, container, group_policy.properties, self.properties)
- utils.instantiate_dict(context, container, group_policy.triggers, self.triggers)
- return group_policy
-
- 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))
- dump_parameters(context, self.properties)
- utils.dump_dict_values(context, self.triggers, 'Triggers')
-
-
-class GroupPolicyTriggerTemplateBase(structure.ModelMixin):
- """
- Triggers for :class:`GroupPolicyTemplate`.
-
- 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_template'
-
- __private_fields__ = ['group_policy_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def group_policy_template_fk(cls):
- return cls.foreign_key('group_policy_template')
-
- # endregion
-
- description = Column(Text)
- implementation = Column(Text)
-
- # region many-to-one relationship
- @declared_attr
- def group_policy_template(cls):
- return cls.many_to_one_relationship('group_policy_template')
-
- # 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 instantiate(self, context, container):
- group_policy_trigger = instance_elements.GroupPolicyTriggerBase(self.name,
- self.implementation)
- group_policy_trigger.description = deepcopy_with_locators(self.description)
- utils.instantiate_dict(context, container, group_policy_trigger.properties,
- self.properties)
- return group_policy_trigger
-
- 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))
- dump_parameters(context, self.properties)
-
-
-class MappingTemplateBase(structure.ModelMixin):
- """
- Used by :class:`SubstitutionTemplate` to map a capability or a requirement to a node.
-
- Properties:
-
- * :code:`mapped_name`: Exposed capability or requirement name
- * :code:`node_template_name`: Must be represented in the :class:`ServiceModel`
- * :code:`name`: Name of capability or requirement at the node template
- """
- __tablename__ = 'mapping_template'
-
- mapped_name = Column(Text)
- node_template_name = Column(Text)
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('mapped_name', self.mapped_name),
- ('node_template_name', self.node_template_name),
- ('name', self.name)))
-
- def instantiate(self, context, *args, **kwargs):
- nodes = context.modeling.instance.find_nodes(self.node_template_name)
- if len(nodes) == 0:
- context.validation.report(
- 'mapping "%s" refer to node template "%s" but there are no '
- 'node instances' % (self.mapped_name,
- self.node_template_name),
- level=validation.Issue.BETWEEN_INSTANCES)
- return None
- return instance_elements.MappingBase(self.mapped_name, nodes[0].id, self.name)
-
- def validate(self, context):
- if self.node_template_name not in context.modeling.model.node_templates:
- context.validation.report('mapping "%s" refers to an unknown node template: %s'
- % (
- self.mapped_name,
- formatting.safe_repr(self.node_template_name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- def dump(self, context):
- console.puts('%s -> %s.%s' % (context.style.node(self.mapped_name),
- context.style.node(self.node_template_name),
- context.style.node(self.name)))
-
-
-class SubstitutionTemplateBase(structure.ModelMixin):
- """
- Used to substitute a single node for the entire deployment.
-
- Properties:
-
- * :code:`node_type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`capability_templates`: Dict of :class:`MappingTemplate`
- * :code:`requirement_templates`: Dict of :class:`MappingTemplate`
- """
- __tablename__ = 'substitution_template'
- node_type_name = Column(Text)
-
- # region many-to-many relationships
-
- @declared_attr
- def capability_templates(cls):
- return cls.many_to_many_relationship('mapping_template',
- table_prefix='capability_templates',
- relationship_kwargs=dict(lazy='dynamic'))
-
- @declared_attr
- def requirement_templates(cls):
- return cls.many_to_many_relationship('mapping_template',
- table_prefix='requirement_templates',
- relationship_kwargs=dict(lazy='dynamic'))
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('node_type_name', self.node_type_name),
- ('capability_templates', formatting.as_raw_list(self.capability_templates)),
- ('requirement_templates', formatting.as_raw_list(self.requirement_templates))))
-
- def instantiate(self, context, container):
- substitution = instance_elements.SubstitutionBase(self.node_type_name)
- utils.instantiate_dict(context, container, substitution.capabilities,
- self.capability_templates)
- utils.instantiate_dict(context, container, substitution.requirements,
- self.requirement_templates)
- return substitution
-
- def validate(self, context):
- if context.modeling.node_types.get_descendant(self.node_type_name) is None:
- context.validation.report('substitution template has an unknown type: %s'
- % formatting.safe_repr(self.node_type_name),
- level=validation.Issue.BETWEEN_TYPES)
-
- utils.validate_dict_values(context, self.capability_templates)
- utils.validate_dict_values(context, self.requirement_templates)
-
- def coerce_values(self, context, container, report_issues):
- utils.coerce_dict_values(context, self, self.capability_templates, report_issues)
- utils.coerce_dict_values(context, self, self.requirement_templates, report_issues)
-
- def dump(self, context):
- console.puts('Substitution template:')
- with context.style.indent:
- console.puts('Node type: %s' % context.style.type(self.node_type_name))
- utils.dump_dict_values(context, self.capability_templates,
- 'Capability template mappings')
- utils.dump_dict_values(context, self.requirement_templates,
- 'Requirement template mappings')
-
-
-# endregion
-
-# region Node templates
-
-class NodeTemplateBase(structure.ModelMixin):
- __tablename__ = 'node_template'
-
- __private_fields__ = ['service_template_fk',
- 'host_fk']
-
- # region foreign_keys
-
- @declared_attr
- def service_template_fk(cls):
- return cls.foreign_key('service_template')
-
- @declared_attr
- def host_fk(cls):
- return cls.foreign_key('node_template', nullable=True)
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- default_instances = Column(Integer, default=1)
- min_instances = Column(Integer, default=0)
- max_instances = Column(Integer, default=None)
- target_node_template_constraints = Column(aria_type.StrictList(FunctionType))
-
- # region orchestrator required columns
-
- plugins = Column(aria_type.List)
- type_hierarchy = Column(aria_type.List)
-
- @declared_attr
- def host(cls):
- return cls.relationship_to_self('host_fk')
-
- @declared_attr
- def service_template_name(cls):
- return association_proxy('service_template', cls.name_column_name())
-
- # endregion
-
- # region many-to-one relationship
- @declared_attr
- def service_template(cls):
- return cls.many_to_one_relationship('service_template')
-
- # endregion
-
- # region many-to-many relationships
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- def is_target_node_valid(self, target_node_template):
- if self.target_node_template_constraints:
- for node_type_constraint in self.target_node_template_constraints:
- if not node_type_constraint(target_node_template, self):
- return False
- return True
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('type_name', self.type_name),
- ('default_instances', self.default_instances),
- ('min_instances', self.min_instances),
- ('max_instances', self.max_instances),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('interface_templates', formatting.as_raw_list(self.interface_templates)),
- ('artifact_templates', formatting.as_raw_list(self.artifact_templates)),
- ('capability_templates', formatting.as_raw_list(self.capability_templates)),
- ('requirement_templates', formatting.as_raw_list(self.requirement_templates))))
-
- def instantiate(self, context, *args, **kwargs):
- node = instance_elements.NodeBase(context, self.type_name, self.name)
- utils.instantiate_dict(context, node, node.properties, self.properties)
- utils.instantiate_dict(context, node, node.interfaces, self.interface_templates)
- utils.instantiate_dict(context, node, node.artifacts, self.artifact_templates)
- utils.instantiate_dict(context, node, node.capabilities, self.capability_templates)
- return node
-
- def validate(self, context):
- if context.modeling.node_types.get_descendant(self.type_name) is None:
- context.validation.report('node template "%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.interface_templates)
- utils.validate_dict_values(context, self.artifact_templates)
- utils.validate_dict_values(context, self.capability_templates)
- utils.validate_list_values(context, self.requirement_templates)
-
- 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.interface_templates, report_issues)
- utils.coerce_dict_values(context, self, self.artifact_templates, report_issues)
- utils.coerce_dict_values(context, self, self.capability_templates, report_issues)
- utils.coerce_list_values(context, self, self.requirement_templates, report_issues)
-
- def dump(self, context):
- console.puts('Node template: %s' % context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Type: %s' % context.style.type(self.type_name))
- console.puts('Instances: %d (%d%s)'
- % (self.default_instances,
- self.min_instances,
- (' to %d' % self.max_instances
- if self.max_instances is not None
- else ' or more')))
- dump_parameters(context, self.properties)
- utils.dump_interfaces(context, self.interface_templates)
- utils.dump_dict_values(context, self.artifact_templates, 'Artifact tempaltes')
- utils.dump_dict_values(context, self.capability_templates, 'Capability templates')
- utils.dump_list_values(context, self.requirement_templates, 'Requirement templates')
-
-
-class GroupTemplateBase(structure.ModelMixin):
- """
- A template for creating zero or more :class:`Group` instances.
-
- Groups are logical containers for zero or more nodes that allow applying zero or more
- :class:`GroupPolicy` instances to the nodes together.
-
- Properties:
-
- * :code:`name`: Name (will be used as a prefix for group IDs)
- * :code:`description`: Description
- * :code:`type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`properties`: Dict of :class:`Parameter`
- * :code:`interface_templates`: Dict of :class:`InterfaceTemplate`
- * :code:`policy_templates`: Dict of :class:`GroupPolicyTemplate`
- * :code:`member_node_template_names`: Must be represented in the :class:`ServiceModel`
- * :code:`member_group_template_names`: Must be represented in the :class:`ServiceModel`
- """
- __tablename__ = 'group_template'
-
- __private_fields__ = ['service_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def service_template_fk(cls):
- return cls.foreign_key('service_template')
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- member_node_template_names = Column(aria_type.StrictList(basestring))
- member_group_template_names = Column(aria_type.StrictList(basestring))
-
- # region many-to-one relationship
- @declared_attr
- def service_template(cls):
- return cls.many_to_one_relationship('service_template')
-
- # 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),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('interface_templates', formatting.as_raw_list(self.interface_templates)),
- ('policy_templates', formatting.as_raw_list(self.policy_templates)),
- ('member_node_template_names', self.member_node_template_names),
- ('member_group_template_names', self.member_group_template_names1)))
-
- def instantiate(self, context, *args, **kwargs):
- group = instance_elements.GroupBase(context, self.type_name, self.name)
- utils.instantiate_dict(context, self, group.properties, self.properties)
- utils.instantiate_dict(context, self, group.interfaces, self.interface_templates)
- utils.instantiate_dict(context, self, group.policies, self.policy_templates)
- for member_node_template_name in self.member_node_template_names:
- group.member_node_ids += \
- context.modeling.instance.get_node_ids(member_node_template_name)
- for member_group_template_name in self.member_group_template_names:
- group.member_group_ids += \
- context.modeling.instance.get_group_ids(member_group_template_name)
- return group
-
- def validate(self, context):
- if context.modeling.group_types.get_descendant(self.type_name) is None:
- context.validation.report('group template "%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.interface_templates)
- utils.validate_dict_values(context, self.policy_templates)
-
- 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.interface_templates, report_issues)
- utils.coerce_dict_values(context, self, self.policy_templates, report_issues)
-
- def dump(self, context):
- console.puts('Group template: %s' % context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- if self.type_name:
- console.puts('Type: %s' % context.style.type(self.type_name))
- dump_parameters(context, self.properties)
- utils.dump_interfaces(context, self.interface_templates)
- utils.dump_dict_values(context, self.policy_templates, 'Policy templates')
- if self.member_node_template_names:
- console.puts('Member node templates: %s' % ', '.join(
- (str(context.style.node(v)) for v in self.member_node_template_names)))
-
-
-# endregion
-
-# region Relationship templates
-
-class RequirementTemplateBase(structure.ModelMixin):
- """
- A requirement for a :class:`NodeTemplate`. During instantiation will be matched with a
- capability of another
- node.
-
- Requirements may optionally contain a :class:`RelationshipTemplate` that will be created between
- the nodes.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`target_node_type_name`: Must be represented in the :class:`ModelingContext`
- * :code:`target_node_template_name`: Must be represented in the :class:`ServiceModel`
- * :code:`target_node_template_constraints`: List of :class:`FunctionType`
- * :code:`target_capability_type_name`: Type of capability in target node
- * :code:`target_capability_name`: Name of capability in target node
- * :code:`relationship_template`: :class:`RelationshipTemplate`
- """
- __tablename__ = 'requirement_template'
-
- __private_fields__ = ['node_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def node_template_fk(cls):
- return cls.foreign_key('node_template', nullable=True)
-
- # endregion
-
-
- target_node_type_name = Column(Text)
- target_node_template_name = Column(Text)
- target_node_template_constraints = Column(aria_type.StrictList(FunctionType))
- target_capability_type_name = Column(Text)
- target_capability_name = Column(Text)
- # CHECK: ???
- relationship_template = Column(Text) # optional
-
- # region many-to-one relationship
- @declared_attr
- def node_template(cls):
- return cls.many_to_one_relationship('node_template')
- # endregion
-
- def instantiate(self, context, container):
- raise NotImplementedError
-
- def find_target(self, context, source_node_template):
- # We might already have a specific node template, so we'll just verify it
- if self.target_node_template_name is not None:
- target_node_template = \
- context.modeling.model.node_templates.get(self.target_node_template_name)
-
- if not source_node_template.is_target_node_valid(target_node_template):
- context.validation.report('requirement "%s" of node template "%s" is for node '
- 'template "%s" but it does not match constraints'
- % (self.name,
- self.target_node_template_name,
- source_node_template.name),
- level=validation.Issue.BETWEEN_TYPES)
- return None, None
-
- if self.target_capability_type_name is not None \
- or self.target_capability_name is not None:
- target_node_capability = self.find_target_capability(context,
- source_node_template,
- target_node_template)
- if target_node_capability is None:
- return None, None
- else:
- target_node_capability = None
-
- return target_node_template, target_node_capability
-
- # Find first node that matches the type
- elif self.target_node_type_name is not None:
- for target_node_template in context.modeling.model.node_templates.itervalues():
- if not context.modeling.node_types.is_descendant(self.target_node_type_name,
- target_node_template.type_name):
- continue
-
- if not source_node_template.is_target_node_valid(target_node_template):
- continue
-
- target_node_capability = self.find_target_capability(context,
- source_node_template,
- target_node_template)
- if target_node_capability is None:
- continue
-
- return target_node_template, target_node_capability
-
- return None, None
-
- def find_target_capability(self, context, source_node_template, target_node_template):
- for capability_template in target_node_template.capability_templates.itervalues():
- if capability_template.satisfies_requirement(context,
- source_node_template,
- self,
- target_node_template):
- return capability_template
- return None
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('target_node_type_name', self.target_node_type_name),
- ('target_node_template_name', self.target_node_template_name),
- ('target_capability_type_name', self.target_capability_type_name),
- ('target_capability_name', self.target_capability_name),
- ('relationship_template', formatting.as_raw(self.relationship_template))))
-
- def validate(self, context):
- node_types = context.modeling.node_types
- capability_types = context.modeling.capability_types
- if self.target_node_type_name \
- and node_types.get_descendant(self.target_node_type_name) is None:
- context.validation.report('requirement "%s" refers to an unknown node type: %s'
- % (self.name,
- formatting.safe_repr(self.target_node_type_name)),
- level=validation.Issue.BETWEEN_TYPES)
- if self.target_capability_type_name and \
- capability_types.get_descendant(self.target_capability_type_name is None):
- context.validation.report('requirement "%s" refers to an unknown capability type: %s'
- % (self.name,
- formatting.safe_repr(self.target_capability_type_name)),
- level=validation.Issue.BETWEEN_TYPES)
- if self.relationship_template:
- self.relationship_template.validate(context)
-
- def coerce_values(self, context, container, report_issues):
- if self.relationship_template is not None:
- self.relationship_template.coerce_values(context, container, report_issues)
-
- def dump(self, context):
- if self.name:
- console.puts(context.style.node(self.name))
- else:
- console.puts('Requirement:')
- with context.style.indent:
- if self.target_node_type_name is not None:
- console.puts('Target node type: %s'
- % context.style.type(self.target_node_type_name))
- elif self.target_node_template_name is not None:
- console.puts('Target node template: %s'
- % context.style.node(self.target_node_template_name))
- if self.target_capability_type_name is not None:
- console.puts('Target capability type: %s'
- % context.style.type(self.target_capability_type_name))
- elif self.target_capability_name is not None:
- console.puts('Target capability name: %s'
- % context.style.node(self.target_capability_name))
- if self.target_node_template_constraints:
- console.puts('Target node template constraints:')
- with context.style.indent:
- for constraint in self.target_node_template_constraints:
- console.puts(context.style.literal(constraint))
- if self.relationship_template:
- console.puts('Relationship:')
- with context.style.indent:
- self.relationship_template.dump(context)
-
-
-class CapabilityTemplateBase(structure.ModelMixin):
- """
- A capability of a :class:`NodeTemplate`. Nodes expose zero or more capabilities that can be
- matched with :class:`Requirement` instances of other nodes.
-
- Properties:
-
- * :code:`name`: Name
- * :code:`description`: Description
- * :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:`valid_source_node_type_names`: Must be represented in the :class:`ModelingContext`
- * :code:`properties`: Dict of :class:`Parameter`
- """
- __tablename__ = 'capability_template'
-
- __private_fields__ = ['node_template_fk']
-
- # region foreign keys
-
- @declared_attr
- def node_template_fk(cls):
- return cls.foreign_key('node_template', nullable=True)
-
- # endregion
-
- description = Column(Text)
- type_name = Column(Text)
- min_occurrences = Column(Integer, default=None) # optional
- max_occurrences = Column(Integer, default=None) # optional
- # CHECK: type?
- valid_source_node_type_names = Column(Text)
-
- # region many-to-one relationship
- @declared_attr
- def node_template(cls):
- return cls.many_to_one_relationship('node_template')
- # endregion
-
- # region many-to-many relationships
-
- @declared_attr
- def properties(cls):
- return cls.many_to_many_relationship('parameter', table_prefix='properties')
-
- # endregion
-
- def satisfies_requirement(self,
- context,
- source_node_template,
- requirement,
- target_node_template):
- # Do we match the required capability type?
- capability_types = context.modeling.capability_types
- if not capability_types.is_descendant(requirement.target_capability_type_name,
- self.type_name):
- return False
-
- # Are we in valid_source_node_type_names?
- if self.valid_source_node_type_names:
- for valid_source_node_type_name in self.valid_source_node_type_names:
- if not context.modeling.node_types.is_descendant(valid_source_node_type_name,
- source_node_template.type_name):
- return False
-
- # Apply requirement constraints
- if requirement.target_node_template_constraints:
- for node_type_constraint in requirement.target_node_template_constraints:
- if not node_type_constraint(target_node_template, source_node_template):
- return False
-
- return True
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('type_name', self.type_name),
- ('min_occurrences', self.min_occurrences),
- ('max_occurrences', self.max_occurrences),
- ('valid_source_node_type_names', self.valid_source_node_type_names),
- ('properties', formatting.as_raw_dict(self.properties))))
-
- def instantiate(self, context, container):
- capability = instance_elements.CapabilityBase(self.name, self.type_name)
- capability.min_occurrences = self.min_occurrences
- capability.max_occurrences = self.max_occurrences
- utils.instantiate_dict(context, container, capability.properties, self.properties)
- return capability
-
- def validate(self, context):
- if context.modeling.capability_types.get_descendant(self.type_name) is None:
- context.validation.report('capability "%s" refers to an unknown type: %s'
- % (self.name, formatting.safe_repr(self.type)), # pylint: disable=no-member
- # TODO fix self.type reference
- 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, self, 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('Type: %s' % context.style.type(self.type_name))
- console.puts(
- 'Occurrences: %d%s'
- % (self.min_occurrences or 0, (' to %d' % self.max_occurrences)
- if self.max_occurrences is not None else ' or more'))
- if self.valid_source_node_type_names:
- console.puts('Valid source node types: %s'
- % ', '.join((str(context.style.type(v))
- for v in self.valid_source_node_type_names)))
- dump_parameters(context, self.properties)
-
-# endregion
-
-
-def dump_parameters(context, parameters, name='Properties'):
- if not parameters:
- return
- console.puts('%s:' % name)
- with context.style.indent:
- for parameter_name, parameter in parameters.items():
- if parameter.type_name is not None:
- console.puts('%s = %s (%s)' % (context.style.property(parameter_name),
- context.style.literal(parameter.value),
- context.style.type(parameter.type_name)))
- else:
- console.puts('%s = %s' % (context.style.property(parameter_name),
- context.style.literal(parameter.value)))
- if parameter.description:
- console.puts(context.style.meta(parameter.description))
-
-
-# TODO (left for tal): Move following two methods to some place parser specific
-def deepcopy_with_locators(value):
- """
- Like :code:`deepcopy`, but also copies over locators.
- """
-
- res = deepcopy(value)
- copy_locators(res, value)
- return res
-
-
-def copy_locators(target, source):
- """
- Copies over :code:`_locator` for all elements, recursively.
-
- Assumes that target and source have exactly the same list/dict structure.
- """
-
- locator = getattr(source, '_locator', None)
- if locator is not None:
- try:
- setattr(target, '_locator', locator)
- except AttributeError:
- pass
-
- if isinstance(target, list) and isinstance(source, list):
- for i, _ in enumerate(target):
- copy_locators(target[i], source[i])
- elif isinstance(target, dict) and isinstance(source, dict):
- for k, v in target.items():
- copy_locators(v, source[k])
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/58e10523/aria/storage/modeling/type.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/type.py b/aria/storage/modeling/type.py
deleted file mode 100644
index 9e3de3d..0000000
--- a/aria/storage/modeling/type.py
+++ /dev/null
@@ -1,302 +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.
-
-import json
-from collections import namedtuple
-
-from sqlalchemy import (
- TypeDecorator,
- VARCHAR,
- event
-)
-from sqlalchemy.ext import mutable
-
-from .. import exceptions
-
-
-class _MutableType(TypeDecorator):
- """
- Dict representation of type.
- """
- @property
- def python_type(self):
- raise NotImplementedError
-
- def process_literal_param(self, value, dialect):
- pass
-
- impl = VARCHAR
-
- def process_bind_param(self, value, dialect):
- if value is not None:
- value = json.dumps(value)
- return value
-
- def process_result_value(self, value, dialect):
- if value is not None:
- value = json.loads(value)
- return value
-
-
-class Dict(_MutableType):
- @property
- def python_type(self):
- return dict
-
-
-class List(_MutableType):
- @property
- def python_type(self):
- return list
-
-
-class _StrictDictMixin(object):
-
- @classmethod
- def coerce(cls, key, value):
- "Convert plain dictionaries to MutableDict."
- try:
- if not isinstance(value, cls):
- if isinstance(value, dict):
- for k, v in value.items():
- cls._assert_strict_key(k)
- cls._assert_strict_value(v)
- return cls(value)
- return mutable.MutableDict.coerce(key, value)
- else:
- return value
- except ValueError as e:
- raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
-
- def __setitem__(self, key, value):
- self._assert_strict_key(key)
- self._assert_strict_value(value)
- super(_StrictDictMixin, self).__setitem__(key, value)
-
- def setdefault(self, key, value):
- self._assert_strict_key(key)
- self._assert_strict_value(value)
- super(_StrictDictMixin, self).setdefault(key, value)
-
- def update(self, *args, **kwargs):
- for k, v in kwargs.items():
- self._assert_strict_key(k)
- self._assert_strict_value(v)
- super(_StrictDictMixin, self).update(*args, **kwargs)
-
- @classmethod
- def _assert_strict_key(cls, key):
- if cls._key_cls is not None and not isinstance(key, cls._key_cls):
- raise exceptions.StorageError("Key type was set strictly to {0}, but was {1}".format(
- cls._key_cls, type(key)
- ))
-
- @classmethod
- def _assert_strict_value(cls, value):
- if cls._value_cls is not None and not isinstance(value, cls._value_cls):
- raise exceptions.StorageError("Value type was set strictly to {0}, but was {1}".format(
- cls._value_cls, type(value)
- ))
-
-
-class _MutableDict(mutable.MutableDict):
- """
- Enables tracking for dict values.
- """
-
- @classmethod
- def coerce(cls, key, value):
- "Convert plain dictionaries to MutableDict."
- try:
- return mutable.MutableDict.coerce(key, value)
- except ValueError as e:
- raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
-
-
-class _StrictListMixin(object):
-
- @classmethod
- def coerce(cls, key, value):
- "Convert plain dictionaries to MutableDict."
- try:
- if not isinstance(value, cls):
- if isinstance(value, list):
- for item in value:
- cls._assert_item(item)
- return cls(value)
- return mutable.MutableList.coerce(key, value)
- else:
- return value
- except ValueError as e:
- raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
-
- def __setitem__(self, index, value):
- """Detect list set events and emit change events."""
- self._assert_item(value)
- super(_StrictListMixin, self).__setitem__(index, value)
-
- def append(self, item):
- self._assert_item(item)
- super(_StrictListMixin, self).append(item)
-
- def extend(self, item):
- self._assert_item(item)
- super(_StrictListMixin, self).extend(item)
-
- def insert(self, index, item):
- self._assert_item(item)
- super(_StrictListMixin, self).insert(index, item)
-
- @classmethod
- def _assert_item(cls, item):
- if cls._item_cls is not None and not isinstance(item, cls._item_cls):
- raise exceptions.StorageError("Key type was set strictly to {0}, but was {1}".format(
- cls._item_cls, type(item)
- ))
-
-
-class _MutableList(mutable.MutableList):
-
- @classmethod
- def coerce(cls, key, value):
- "Convert plain dictionaries to MutableDict."
- try:
- return mutable.MutableList.coerce(key, value)
- except ValueError as e:
- raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
-
-_StrictDictID = namedtuple('_StrictDictID', 'key_cls, value_cls')
-_StrictValue = namedtuple('_StrictValue', 'type_cls, listener_cls')
-
-
-class _StrictDict(object):
- """
- This entire class functions as a factory for strict dicts and their listeners.
- No type class, and no listener type class is created more than once. If a relevant type class
- exists it is returned.
- """
- _strict_map = {}
-
- def __call__(self, key_cls=None, value_cls=None):
- strict_dict_map_key = _StrictDictID(key_cls=key_cls, value_cls=value_cls)
- if strict_dict_map_key not in self._strict_map:
- key_cls_name = getattr(key_cls, '__name__', str(key_cls))
- value_cls_name = getattr(value_cls, '__name__', str(value_cls))
- # Creating the type class itself. this class would be returned (used by the sqlalchemy
- # Column).
- strict_dict_cls = type(
- 'StrictDict_{0}_{1}'.format(key_cls_name, value_cls_name),
- (Dict, ),
- {}
- )
- # Creating the type listening class.
- # The new class inherits from both the _MutableDict class and the _StrictDictMixin,
- # while setting the necessary _key_cls and _value_cls as class attributes.
- listener_cls = type(
- 'StrictMutableDict_{0}_{1}'.format(key_cls_name, value_cls_name),
- (_StrictDictMixin, _MutableDict),
- {'_key_cls': key_cls, '_value_cls': value_cls}
- )
- self._strict_map[strict_dict_map_key] = _StrictValue(type_cls=strict_dict_cls,
- listener_cls=listener_cls)
-
- return self._strict_map[strict_dict_map_key].type_cls
-
-StrictDict = _StrictDict()
-
-
-class _StrictList(object):
- """
- This entire class functions as a factory for strict lists and their listeners.
- No type class, and no listener type class is created more than once. If a relevant type class
- exists it is returned.
- """
- _strict_map = {}
-
- def __call__(self, item_cls=None):
-
- if item_cls not in self._strict_map:
- item_cls_name = getattr(item_cls, '__name__', str(item_cls))
- # Creating the type class itself. this class would be returned (used by the sqlalchemy
- # Column).
- strict_list_cls = type(
- 'StrictList_{0}'.format(item_cls_name),
- (List, ),
- {}
- )
- # Creating the type listening class.
- # The new class inherits from both the _MutableList class and the _StrictListMixin,
- # while setting the necessary _item_cls as class attribute.
- listener_cls = type(
- 'StrictMutableList_{0}'.format(item_cls_name),
- (_StrictListMixin, _MutableList),
- {'_item_cls': item_cls}
- )
- self._strict_map[item_cls] = _StrictValue(type_cls=strict_list_cls,
- listener_cls=listener_cls)
-
- return self._strict_map[item_cls].type_cls
-
-StrictList = _StrictList()
-
-
-def _mutable_association_listener(mapper, cls):
- strict_dict_type_to_listener = \
- dict((v.type_cls, v.listener_cls) for v in _StrictDict._strict_map.values())
-
- strict_list_type_to_listener = \
- dict((v.type_cls, v.listener_cls) for v in _StrictList._strict_map.values())
-
- for prop in mapper.column_attrs:
- column_type = prop.columns[0].type
- # Dict Listeners
- if type(column_type) in strict_dict_type_to_listener: # pylint: disable=unidiomatic-typecheck
- strict_dict_type_to_listener[type(column_type)].associate_with_attribute(
- getattr(cls, prop.key))
- elif isinstance(column_type, Dict):
- _MutableDict.associate_with_attribute(getattr(cls, prop.key))
-
- # List Listeners
- if type(column_type) in strict_list_type_to_listener: # pylint: disable=unidiomatic-typecheck
- strict_list_type_to_listener[type(column_type)].associate_with_attribute(
- getattr(cls, prop.key))
- elif isinstance(column_type, List):
- _MutableList.associate_with_attribute(getattr(cls, prop.key))
-_LISTENER_ARGS = (mutable.mapper, 'mapper_configured', _mutable_association_listener)
-
-
-def _register_mutable_association_listener():
- event.listen(*_LISTENER_ARGS)
-
-
-def remove_mutable_association_listener():
- """
- Remove the event listener that associates ``Dict`` and ``List`` column types with
- ``MutableDict`` and ``MutableList``, respectively.
-
- This call must happen before any model instance is instantiated.
- This is because once it does, that would trigger the listener we are trying to remove.
- Once it is triggered, many other listeners will then be registered.
- At that point, it is too late.
-
- The reason this function exists is that the association listener, interferes with ARIA change
- tracking instrumentation, so a way to disable it is required.
-
- Note that the event listener this call removes is registered by default.
- """
- if event.contains(*_LISTENER_ARGS):
- event.remove(*_LISTENER_ARGS)
-
-_register_mutable_association_listener()
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/58e10523/aria/storage/modeling/utils.py
----------------------------------------------------------------------
diff --git a/aria/storage/modeling/utils.py b/aria/storage/modeling/utils.py
deleted file mode 100644
index 75e34f5..0000000
--- a/aria/storage/modeling/utils.py
+++ /dev/null
@@ -1,139 +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 random import randrange
-
-from shortuuid import ShortUUID
-
-from ...utils.console import puts
-
-
-# UUID = ShortUUID() # default alphabet is base57, which is alphanumeric without visually ambiguous
-# characters; ID length is 22
-UUID = ShortUUID(alphabet='abcdefghijklmnopqrstuvwxyz0123456789') # alphanumeric; ID length is 25
-
-
-def generate_id_string(length=None):
- """
- A random string with a strong guarantee of universal uniqueness (uses UUID).
-
- The default length is 25 characters.
- """
-
- the_id = UUID.uuid()
- if length is not None:
- the_id = the_id[:length]
- return the_id
-
-
-def generate_hex_string():
- """
- A random string of 5 hex digits with no guarantee of universal uniqueness.
- """
-
- return '%05x' % randrange(16 ** 5)
-
-
-def validate_dict_values(context, the_dict):
- if not the_dict:
- return
- validate_list_values(context, the_dict.itervalues())
-
-
-def validate_list_values(context, the_list):
- if not the_list:
- return
- for value in the_list:
- value.validate(context)
-
-
-def coerce_dict_values(context, container, the_dict, report_issues=False):
- if not the_dict:
- return
- coerce_list_values(context, container, the_dict.itervalues(), report_issues)
-
-
-def coerce_list_values(context, container, the_list, report_issues=False):
- if not the_list:
- return
- for value in the_list:
- value.coerce_values(context, container, report_issues)
-
-
-def instantiate_dict(context, container, the_dict, from_dict):
- if not from_dict:
- return
- for name, value in from_dict.iteritems():
- value = value.instantiate(context, container)
- if value is not None:
- the_dict[name] = value
-
-
-def dump_list_values(context, the_list, name):
- if not the_list:
- return
- puts('%s:' % name)
- with context.style.indent:
- for value in the_list:
- value.dump(context)
-
-
-def dump_dict_values(context, the_dict, name):
- if not the_dict:
- return
- dump_list_values(context, the_dict.itervalues(), name)
-
-
-def dump_parameters(context, parameters, name='Properties'):
- if not parameters:
- return
- puts('%s:' % name)
- with context.style.indent:
- for parameter_name, parameter in parameters.iteritems():
- if parameter.type_name is not None:
- puts('%s = %s (%s)' % (context.style.property(parameter_name),
- context.style.literal(parameter.value),
- context.style.type(parameter.type_name)))
- else:
- puts('%s = %s' % (context.style.property(parameter_name),
- context.style.literal(parameter.value)))
- if parameter.description:
- puts(context.style.meta(parameter.description))
-
-
-def dump_interfaces(context, interfaces, name='Interfaces'):
- if not interfaces:
- return
- puts('%s:' % name)
- with context.style.indent:
- for interface in interfaces.itervalues():
- interface.dump(context)
-
-
-def pluralize(noun):
- if noun.endswith('s'):
- return '{0}es'.format(noun)
- elif noun.endswith('y'):
- return '{0}ies'.format(noun[:-1])
- else:
- return '{0}s'.format(noun)
-
-
-class classproperty(object): # pylint: disable=invalid-name
- def __init__(self, f):
- self._func = f
-
- def __get__(self, instance, owner):
- return self._func(owner)