http://git-wip-us.apache.org/repos/asf/incubator-ariatosca-website/blob/23d6ba76/apache-ariatosca-0.1.1/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/apache-ariatosca-0.1.1/aria/modeling/service_template.py
b/apache-ariatosca-0.1.1/aria/modeling/service_template.py
deleted file mode 100644
index 57fd672..0000000
--- a/apache-ariatosca-0.1.1/aria/modeling/service_template.py
+++ /dev/null
@@ -1,2411 +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 modeling service template module
-"""
-
-# pylint: disable=too-many-lines, no-self-argument, no-member, abstract-method
-
-from __future__ import absolute_import # so we can import standard 'types'
-
-from datetime import datetime
-
-from sqlalchemy import (
- Column,
- Text,
- Integer,
- Boolean,
- DateTime,
- PickleType
-)
-from sqlalchemy.ext.declarative import declared_attr
-
-from ..parser import validation
-from ..parser.consumption import ConsumptionContext
-from ..parser.reading import deepcopy_with_locators
-from ..utils import (collections, formatting, console)
-from ..utils.versions import VersionString
-from .mixins import TemplateModelMixin
-from . import (
- relationship,
- utils,
- types as modeling_types
-)
-
-
-class ServiceTemplateBase(TemplateModelMixin):
- """
- Template for creating :class:`Service` instances.
-
- Usually created by various DSL parsers, such as ARIA's TOSCA extension.
However, it can also be
- created programmatically.
- """
-
- __tablename__ = 'service_template'
-
- __private_fields__ = ('substitution_template_fk',
- 'node_type_fk',
- 'group_type_fk',
- 'policy_type_fk',
- 'relationship_type_fk',
- 'capability_type_fk',
- 'interface_type_fk',
- 'artifact_type_fk')
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- main_file_name = Column(Text, doc="""
- Filename of CSAR or YAML file from which this service template was parsed.
-
- :type: :obj:`basestring`
- """)
-
- created_at = Column(DateTime, nullable=False, index=True, doc="""
- Creation timestamp.
-
- :type: :class:`~datetime.datetime`
- """)
-
- updated_at = Column(DateTime, doc="""
- Update timestamp.
-
- :type: :class:`~datetime.datetime`
- """)
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- @declared_attr
- def substitution_template(cls):
- """
- Exposes an entire service as a single node.
-
- :type: :class:`SubstitutionTemplate`
- """
- return relationship.one_to_one(
- cls, 'substitution_template',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def node_types(cls):
- """
- Base for the node type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='node_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def group_types(cls):
- """
- Base for the group type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='group_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def policy_types(cls):
- """
- Base for the policy type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='policy_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def relationship_types(cls):
- """
- Base for the relationship type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='relationship_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def capability_types(cls):
- """
- Base for the capability type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='capability_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def interface_types(cls):
- """
- Base for the interface type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='interface_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def artifact_types(cls):
- """
- Base for the artifact type hierarchy,
-
- :type: :class:`Type`
- """
- return relationship.one_to_one(
- cls, 'type', fk='artifact_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def services(cls):
- """
- Instantiated services.
-
- :type: [:class:`Service`]
- """
- return relationship.one_to_many(cls, 'service', dict_key='name')
-
- @declared_attr
- def node_templates(cls):
- """
- Templates for creating nodes.
-
- :type: {:obj:`basestring`, :class:`NodeTemplate`}
- """
- return relationship.one_to_many(cls, 'node_template', dict_key='name')
-
- @declared_attr
- def group_templates(cls):
- """
- Templates for creating groups.
-
- :type: {:obj:`basestring`, :class:`GroupTemplate`}
- """
- return relationship.one_to_many(cls, 'group_template', dict_key='name')
-
- @declared_attr
- def policy_templates(cls):
- """
- Templates for creating policies.
-
- :type: {:obj:`basestring`, :class:`PolicyTemplate`}
- """
- return relationship.one_to_many(cls, 'policy_template',
dict_key='name')
-
- @declared_attr
- def workflow_templates(cls):
- """
- Templates for creating workflows.
-
- :type: {:obj:`basestring`, :class:`OperationTemplate`}
- """
- return relationship.one_to_many(cls, 'operation_template',
dict_key='name')
-
- @declared_attr
- def outputs(cls):
- """
- Declarations for output parameters are filled in after service
installation.
-
- :type: {:obj:`basestring`: :class:`Output`}
- """
- return relationship.one_to_many(cls, 'output', dict_key='name')
-
- @declared_attr
- def inputs(cls):
- """
- Declarations for externally provided parameters.
-
- :type: {:obj:`basestring`: :class:`Input`}
- """
- return relationship.one_to_many(cls, 'input', dict_key='name')
-
- @declared_attr
- def plugin_specifications(cls):
- """
- Required plugins for instantiated services.
-
- :type: {:obj:`basestring`: :class:`PluginSpecification`}
- """
- return relationship.one_to_many(cls, 'plugin_specification',
dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- # endregion
-
- # region many_to_many relationships
-
- @declared_attr
- def meta_data(cls):
- """
- Associated metadata.
-
- :type: {:obj:`basestring`: :class:`Metadata`}
- """
- # Warning! We cannot use the attr name "metadata" because it's used by
SQLAlchemy!
- return relationship.many_to_many(cls, 'metadata', dict_key='name')
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def substitution_template_fk(cls):
- """For ServiceTemplate one-to-one to SubstitutionTemplate"""
- return relationship.foreign_key('substitution_template', nullable=True)
-
- @declared_attr
- def node_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def group_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def policy_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def relationship_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def capability_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def interface_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def artifact_type_fk(cls):
- """For ServiceTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('description', self.description),
- ('metadata', formatting.as_raw_dict(self.meta_data)),
- ('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)),
- ('workflow_templates',
formatting.as_raw_list(self.workflow_templates))))
-
- @property
- def types_as_raw(self):
- return collections.OrderedDict((
- ('node_types', formatting.as_raw(self.node_types)),
- ('group_types', formatting.as_raw(self.group_types)),
- ('policy_types', formatting.as_raw(self.policy_types)),
- ('relationship_types', formatting.as_raw(self.relationship_types)),
- ('capability_types', formatting.as_raw(self.capability_types)),
- ('interface_types', formatting.as_raw(self.interface_types)),
- ('artifact_types', formatting.as_raw(self.artifact_types))))
-
- def instantiate(self, container, model_storage, inputs=None): # pylint:
disable=arguments-differ
- from . import models
- context = ConsumptionContext.get_thread_local()
- now = datetime.now()
- service = models.Service(created_at=now,
- updated_at=now,
-
description=deepcopy_with_locators(self.description),
- service_template=self)
- context.modeling.instance = service
-
- service.inputs = utils.merge_parameter_values(inputs, self.inputs,
model_cls=models.Input)
- # TODO: now that we have inputs, we should scan properties and inputs
and evaluate functions
-
- for plugin_specification in self.plugin_specifications.itervalues():
- if plugin_specification.enabled:
- if plugin_specification.resolve(model_storage):
- plugin = plugin_specification.plugin
- service.plugins[plugin.name] = plugin
- else:
- context = ConsumptionContext.get_thread_local()
- context.validation.report('specified plugin not found:
{0}'.format(
- plugin_specification.name),
level=validation.Issue.EXTERNAL)
-
- utils.instantiate_dict(self, service.meta_data, self.meta_data)
-
- for node_template in self.node_templates.itervalues():
- for _ in range(node_template.default_instances):
- node = node_template.instantiate(container)
- service.nodes[node.name] = node
-
- utils.instantiate_dict(self, service.groups, self.group_templates)
- utils.instantiate_dict(self, service.policies, self.policy_templates)
- utils.instantiate_dict(self, service.workflows,
self.workflow_templates)
-
- if self.substitution_template is not None:
- service.substitution =
self.substitution_template.instantiate(container)
-
- utils.instantiate_dict(self, service.outputs, self.outputs)
-
- return service
-
- def validate(self):
- utils.validate_dict_values(self.meta_data)
- utils.validate_dict_values(self.node_templates)
- utils.validate_dict_values(self.group_templates)
- utils.validate_dict_values(self.policy_templates)
- if self.substitution_template is not None:
- self.substitution_template.validate()
- utils.validate_dict_values(self.inputs)
- utils.validate_dict_values(self.outputs)
- utils.validate_dict_values(self.workflow_templates)
- if self.node_types is not None:
- self.node_types.validate()
- if self.group_types is not None:
- self.group_types.validate()
- if self.policy_types is not None:
- self.policy_types.validate()
- if self.relationship_types is not None:
- self.relationship_types.validate()
- if self.capability_types is not None:
- self.capability_types.validate()
- if self.interface_types is not None:
- self.interface_types.validate()
- if self.artifact_types is not None:
- self.artifact_types.validate()
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.meta_data, report_issues)
- utils.coerce_dict_values(self.node_templates, report_issues)
- utils.coerce_dict_values(self.group_templates, report_issues)
- utils.coerce_dict_values(self.policy_templates, report_issues)
- if self.substitution_template is not None:
- self.substitution_template.coerce_values(report_issues)
- utils.coerce_dict_values(self.inputs, report_issues)
- utils.coerce_dict_values(self.outputs, report_issues)
- utils.coerce_dict_values(self.workflow_templates, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- if self.description is not None:
- console.puts(context.style.meta(self.description))
- utils.dump_dict_values(self.meta_data, 'Metadata')
- for node_template in self.node_templates.itervalues():
- node_template.dump()
- for group_template in self.group_templates.itervalues():
- group_template.dump()
- for policy_template in self.policy_templates.itervalues():
- policy_template.dump()
- if self.substitution_template is not None:
- self.substitution_template.dump()
- utils.dump_dict_values(self.inputs, 'Inputs')
- utils.dump_dict_values(self.outputs, 'Outputs')
- utils.dump_dict_values(self.workflow_templates, 'Workflow templates')
-
- def dump_types(self):
- if self.node_types.children:
- console.puts('Node types:')
- self.node_types.dump()
- if self.group_types.children:
- console.puts('Group types:')
- self.group_types.dump()
- if self.capability_types.children:
- console.puts('Capability types:')
- self.capability_types.dump()
- if self.relationship_types.children:
- console.puts('Relationship types:')
- self.relationship_types.dump()
- if self.policy_types.children:
- console.puts('Policy types:')
- self.policy_types.dump()
- if self.artifact_types.children:
- console.puts('Artifact types:')
- self.artifact_types.dump()
- if self.interface_types.children:
- console.puts('Interface types:')
- self.interface_types.dump()
-
-
-class NodeTemplateBase(TemplateModelMixin):
- """
- Template for creating zero or more :class:`Node` instances, which are
typed vertices in the
- service topology.
- """
-
- __tablename__ = 'node_template'
-
- __private_fields__ = ('type_fk',
- 'service_template_fk')
-
- # region association proxies
-
- @declared_attr
- def service_template_name(cls):
- return relationship.association_proxy('service_template', 'name')
-
- @declared_attr
- def type_name(cls):
- return relationship.association_proxy('type', 'name')
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def nodes(cls):
- """
- Instantiated nodes.
-
- :type: [:class:`Node`]
- """
- return relationship.one_to_many(cls, 'node')
-
- @declared_attr
- def interface_templates(cls):
- """
- Associated interface templates.
-
- :type: {:obj:`basestring`: :class:`InterfaceTemplate`}
- """
- return relationship.one_to_many(cls, 'interface_template',
dict_key='name')
-
- @declared_attr
- def artifact_templates(cls):
- """
- Associated artifacts.
-
- :type: {:obj:`basestring`: :class:`ArtifactTemplate`}
- """
- return relationship.one_to_many(cls, 'artifact_template',
dict_key='name')
-
- @declared_attr
- def capability_templates(cls):
- """
- Associated exposed capability templates.
-
- :type: {:obj:`basestring`: :class:`CapabilityTemplate`}
- """
- return relationship.one_to_many(cls, 'capability_template',
dict_key='name')
-
- @declared_attr
- def requirement_templates(cls):
- """
- Associated potential relationships with other nodes.
-
- :type: [:class:`RequirementTemplate`]
- """
- return relationship.one_to_many(cls, 'requirement_template',
other_fk='node_template_fk')
-
- @declared_attr
- def properties(cls):
- """
- Declarations for associated immutable parameters.
-
- :type: {:obj:`basestring`: :class:`Property`}
- """
- return relationship.one_to_many(cls, 'property', dict_key='name')
-
- @declared_attr
- def attributes(cls):
- """
- Declarations for associated mutable parameters.
-
- :type: {:obj:`basestring`: :class:`Attribute`}
- """
- return relationship.one_to_many(cls, 'attribute', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def type(cls):
- """
- Node type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def service_template(cls):
- """
- Containing service template.
-
- :type: :class:`ServiceTemplate`
- """
- return relationship.many_to_one(cls, 'service_template')
-
- # endregion
-
- # region foreign_keys
-
- @declared_attr
- def type_fk(cls):
- """For NodeTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- @declared_attr
- def service_template_fk(cls):
- """For ServiceTemplate one-to-many to NodeTemplate"""
- return relationship.foreign_key('service_template')
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- default_instances = Column(Integer, default=1, doc="""
- Default number nodes that will appear in the service.
-
- :type: :obj:`int`
- """)
-
- min_instances = Column(Integer, default=0, doc="""
- Minimum number nodes that will appear in the service.
-
- :type: :obj:`int`
- """)
-
- max_instances = Column(Integer, default=None, doc="""
- Maximum number nodes that will appear in the service.
-
- :type: :obj:`int`
- """)
-
- target_node_template_constraints = Column(PickleType, doc="""
- Constraints for filtering relationship targets.
-
- :type: [:class:`NodeTemplateConstraint`]
- """)
-
- def is_target_node_template_valid(self, target_node_template):
- if self.target_node_template_constraints:
- for node_template_constraint in
self.target_node_template_constraints:
- if not node_template_constraint.matches(self,
target_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),
- ('default_instances', self.default_instances),
- ('min_instances', self.min_instances),
- ('max_instances', self.max_instances),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('attributes', 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, container):
- from . import models
- if self.nodes:
- highest_name_suffix = max(int(n.name.rsplit('_', 1)[-1]) for n in
self.nodes)
- suffix = highest_name_suffix + 1
- else:
- suffix = 1
- name = '{name}_{index}'.format(name=self.name, index=suffix)
- node = models.Node(name=name,
- type=self.type,
-
description=deepcopy_with_locators(self.description),
- state=models.Node.INITIAL,
- node_template=self)
- utils.instantiate_dict(node, node.properties, self.properties)
- utils.instantiate_dict(node, node.attributes, self.attributes)
- utils.instantiate_dict(node, node.interfaces, self.interface_templates)
- utils.instantiate_dict(node, node.artifacts, self.artifact_templates)
- utils.instantiate_dict(node, node.capabilities,
self.capability_templates)
-
- # Default attributes
- if 'tosca_name' in node.attributes:
- node.attributes['tosca_name'].value = self.name
- if 'tosca_id' in node.attributes:
- node.attributes['tosca_id'].value = name
-
- return node
-
- def validate(self):
- utils.validate_dict_values(self.properties)
- utils.validate_dict_values(self.attributes)
- utils.validate_dict_values(self.interface_templates)
- utils.validate_dict_values(self.artifact_templates)
- utils.validate_dict_values(self.capability_templates)
- utils.validate_list_values(self.requirement_templates)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.properties, report_issues)
- utils.coerce_dict_values(self.attributes, report_issues)
- utils.coerce_dict_values(self.interface_templates, report_issues)
- utils.coerce_dict_values(self.artifact_templates, report_issues)
- utils.coerce_dict_values(self.capability_templates, report_issues)
- utils.coerce_list_values(self.requirement_templates, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- console.puts('Node template:
{0}'.format(context.style.node(self.name)))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Type:
{0}'.format(context.style.type(self.type.name)))
- console.puts('Instances: {0:d} ({1:d}{2})'.format(
- self.default_instances,
- self.min_instances,
- ' to {0:d}'.format(self.max_instances)
- if self.max_instances is not None
- else ' or more'))
- utils.dump_dict_values(self.properties, 'Properties')
- utils.dump_dict_values(self.attributes, 'Attributes')
- utils.dump_interfaces(self.interface_templates)
- utils.dump_dict_values(self.artifact_templates, 'Artifact
templates')
- utils.dump_dict_values(self.capability_templates, 'Capability
templates')
- utils.dump_list_values(self.requirement_templates, 'Requirement
templates')
-
-
-class GroupTemplateBase(TemplateModelMixin):
- """
- Template for creating a :class:`Group` instance, which is a typed logical
container for zero or
- more :class:`Node` instances.
- """
-
- __tablename__ = 'group_template'
-
- __private_fields__ = ('type_fk',
- 'service_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def groups(cls):
- """
- Instantiated groups.
-
- :type: [:class:`Group`]
- """
- return relationship.one_to_many(cls, 'group')
-
- @declared_attr
- def interface_templates(cls):
- """
- Associated interface templates.
-
- :type: {:obj:`basestring`: :class:`InterfaceTemplate`}
- """
- return relationship.one_to_many(cls, 'interface_template',
dict_key='name')
-
- @declared_attr
- def properties(cls):
- """
- Declarations for associated immutable parameters.
-
- :type: {:obj:`basestring`: :class:`Property`}
- """
- return relationship.one_to_many(cls, 'property', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def service_template(cls):
- """
- Containing service template.
-
- :type: :class:`ServiceTemplate`
- """
- return relationship.many_to_one(cls, 'service_template')
-
- @declared_attr
- def type(cls):
- """
- Group type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region many_to_many relationships
-
- @declared_attr
- def node_templates(cls):
- """
- Nodes instantiated by these templates will be members of the group.
-
- :type: [:class:`NodeTemplate`]
- """
- return relationship.many_to_many(cls, 'node_template')
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def type_fk(cls):
- """For GroupTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- @declared_attr
- def service_template_fk(cls):
- """For ServiceTemplate one-to-many to GroupTemplate"""
- return relationship.foreign_key('service_template')
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- @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))))
-
- def instantiate(self, container):
- from . import models
- group = models.Group(name=self.name,
- type=self.type,
-
description=deepcopy_with_locators(self.description),
- group_template=self)
- utils.instantiate_dict(self, group.properties, self.properties)
- utils.instantiate_dict(self, group.interfaces,
self.interface_templates)
- if self.node_templates:
- for node_template in self.node_templates:
- group.nodes += node_template.nodes
- return group
-
- def validate(self):
- utils.validate_dict_values(self.properties)
- utils.validate_dict_values(self.interface_templates)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.properties, report_issues)
- utils.coerce_dict_values(self.interface_templates, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- console.puts('Group template:
{0}'.format(context.style.node(self.name)))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Type:
{0}'.format(context.style.type(self.type.name)))
- utils.dump_dict_values(self.properties, 'Properties')
- utils.dump_interfaces(self.interface_templates)
- if self.node_templates:
- console.puts('Member node templates: {0}'.format(', '.join(
- (str(context.style.node(v.name)) for v in
self.node_templates))))
-
-
-class PolicyTemplateBase(TemplateModelMixin):
- """
- Template for creating a :class:`Policy` instance, which is a typed set of
orchestration hints
- applied to zero or more :class:`Node` or :class:`Group` instances.
- """
-
- __tablename__ = 'policy_template'
-
- __private_fields__ = ('type_fk',
- 'service_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def policies(cls):
- """
- Instantiated policies.
-
- :type: [:class:`Policy`]
- """
- return relationship.one_to_many(cls, 'policy')
-
- @declared_attr
- def properties(cls):
- """
- Declarations for associated immutable parameters.
-
- :type: {:obj:`basestring`: :class:`Property`}
- """
- return relationship.one_to_many(cls, 'property', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def service_template(cls):
- """
- Containing service template.
-
- :type: :class:`ServiceTemplate`
- """
- return relationship.many_to_one(cls, 'service_template')
-
- @declared_attr
- def type(cls):
- """
- Policy type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region many_to_many relationships
-
- @declared_attr
- def node_templates(cls):
- """
- Policy will be enacted on all nodes instantiated by these templates.
-
- :type: {:obj:`basestring`: :class:`NodeTemplate`}
- """
- return relationship.many_to_many(cls, 'node_template')
-
- @declared_attr
- def group_templates(cls):
- """
- Policy will be enacted on all nodes in all groups instantiated by
these templates.
-
- :type: {:obj:`basestring`: :class:`GroupTemplate`}
- """
- return relationship.many_to_many(cls, 'group_template')
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def type_fk(cls):
- """For PolicyTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- @declared_attr
- def service_template_fk(cls):
- """For ServiceTemplate one-to-many to PolicyTemplate"""
- return relationship.foreign_key('service_template')
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- @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))))
-
- def instantiate(self, container):
- from . import models
- policy = models.Policy(name=self.name,
- type=self.type,
-
description=deepcopy_with_locators(self.description),
- policy_template=self)
- utils.instantiate_dict(self, policy.properties, self.properties)
- if self.node_templates:
- for node_template in self.node_templates:
- policy.nodes += node_template.nodes
- if self.group_templates:
- for group_template in self.group_templates:
- policy.groups += group_template.groups
- return policy
-
- def validate(self):
- utils.validate_dict_values(self.properties)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.properties, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- console.puts('Policy template:
{0}'.format(context.style.node(self.name)))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Type:
{0}'.format(context.style.type(self.type.name)))
- utils.dump_dict_values(self.properties, 'Properties')
- if self.node_templates:
- console.puts('Target node templates: {0}'.format(', '.join(
- (str(context.style.node(v.name)) for v in
self.node_templates))))
- if self.group_templates:
- console.puts('Target group templates: {0}'.format(', '.join(
- (str(context.style.node(v.name)) for v in
self.group_templates))))
-
-
-class SubstitutionTemplateBase(TemplateModelMixin):
- """
- Template for creating a :class:`Substitution` instance, which exposes an
entire instantiated
- service as a single node.
- """
-
- __tablename__ = 'substitution_template'
-
- __private_fields__ = ('node_type_fk',)
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def substitutions(cls):
- """
- Instantiated substitutions.
-
- :type: [:class:`Substitution`]
- """
- return relationship.one_to_many(cls, 'substitution')
-
- @declared_attr
- def mappings(cls):
- """
- Map requirement and capabilities to exposed node.
-
- :type: {:obj:`basestring`: :class:`SubstitutionTemplateMapping`}
- """
- return relationship.one_to_many(cls, 'substitution_template_mapping',
dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def node_type(cls):
- """
- Exposed node type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def node_type_fk(cls):
- """For SubstitutionTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('node_type_name', self.node_type.name),
- ('mappings', formatting.as_raw_dict(self.mappings))))
-
- def instantiate(self, container):
- from . import models
- substitution = models.Substitution(node_type=self.node_type,
- substitution_template=self)
- utils.instantiate_dict(container, substitution.mappings, self.mappings)
- return substitution
-
- def validate(self):
- utils.validate_dict_values(self.mappings)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.mappings, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- console.puts('Substitution template:')
- with context.style.indent:
- console.puts('Node type:
{0}'.format(context.style.type(self.node_type.name)))
- utils.dump_dict_values(self.mappings, 'Mappings')
-
-
-class SubstitutionTemplateMappingBase(TemplateModelMixin):
- """
- Used by :class:`SubstitutionTemplate` to map a capability template or a
requirement template to
- the exposed node.
-
- The :attr:`name` field should match the capability or requirement name on
the exposed node's
- type.
-
- Only one of :attr:`capability_template` and :attr:`requirement_template`
can be set.
- """
-
- __tablename__ = 'substitution_template_mapping'
-
- __private_fields__ = ('substitution_template_fk',
- 'capability_template_fk',
- 'requirement_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- @declared_attr
- def capability_template(cls):
- """
- Capability template to expose (can be ``None``).
-
- :type: :class:`CapabilityTemplate`
- """
- return relationship.one_to_one(
- cls, 'capability_template',
back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def requirement_template(cls):
- """
- Requirement template to expose (can be ``None``).
-
- :type: :class:`RequirementTemplate`
- """
- return relationship.one_to_one(
- cls, 'requirement_template',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region one_to_many relationships
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def substitution_template(cls):
- """
- Containing substitution template.
-
- :type: :class:`SubstitutionTemplate`
- """
- return relationship.many_to_one(cls, 'substitution_template',
back_populates='mappings')
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def substitution_template_fk(cls):
- """For SubstitutionTemplate one-to-many to
SubstitutionTemplateMapping"""
- return relationship.foreign_key('substitution_template')
-
- @declared_attr
- def capability_template_fk(cls):
- """For SubstitutionTemplate one-to-one to CapabilityTemplate"""
- return relationship.foreign_key('capability_template', nullable=True)
-
- @declared_attr
- def requirement_template_fk(cls):
- """For SubstitutionTemplate one-to-one to RequirementTemplate"""
- return relationship.foreign_key('requirement_template', nullable=True)
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),))
-
- def coerce_values(self, report_issues):
- pass
-
- def instantiate(self, container):
- from . import models
- context = ConsumptionContext.get_thread_local()
- if self.capability_template is not None:
- node_template = self.capability_template.node_template
- else:
- node_template = self.requirement_template.node_template
- nodes = node_template.nodes
- if len(nodes) == 0:
- context.validation.report(
- 'mapping "{0}" refers to node template "{1}" but there are no '
- 'node instances'.format(self.mapped_name,
self.node_template.name),
- level=validation.Issue.BETWEEN_INSTANCES)
- return None
- # The TOSCA spec does not provide a way to choose the node,
- # so we will just pick the first one
- node = nodes[0]
- capability = None
- if self.capability_template:
- for a_capability in node.capabilities.itervalues():
- if a_capability.capability_template.name ==
self.capability_template.name:
- capability = a_capability
- return models.SubstitutionMapping(name=self.name,
- capability=capability,
-
requirement_template=self.requirement_template,
- node=node)
-
-
- def validate(self):
- context = ConsumptionContext.get_thread_local()
- if (self.capability_template is None) and (self.requirement_template
is None):
- context.validation.report('mapping "{0}" refers to neither
capability nor a requirement'
- ' in node template: {1}'.format(
- self.name,
-
formatting.safe_repr(self.node_template.name)),
- level=validation.Issue.BETWEEN_TYPES)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- if self.capability_template is not None:
- node_template = self.capability_template.node_template
- else:
- node_template = self.requirement_template.node_template
- console.puts('{0} -> {1}.{2}'.format(
- context.style.node(self.name),
- context.style.node(node_template.name),
- context.style.node(self.capability_template.name
- if self.capability_template
- else self.requirement_template.name)))
-
-
-class RequirementTemplateBase(TemplateModelMixin):
- """
- Template for creating :class:`Relationship` instances, which are
optionally-typed edges in the
- service topology, connecting a :class:`Node` to a :class:`Capability` of
another node.
-
- Note that there is no equivalent "Requirement" instance model. Instead,
during instantiation a
- requirement template is matched with a capability and a
:class:`Relationship` is instantiated.
-
- A requirement template *must* target a :class:`CapabilityType` or a
capability name. It can
- optionally target a specific :class:`NodeType` or :class:`NodeTemplate`.
-
- Requirement templates may optionally contain a
:class:`RelationshipTemplate`. If they do not,
- a :class:`Relationship` will be instantiated with default values.
- """
-
- __tablename__ = 'requirement_template'
-
- __private_fields__ = ('target_capability_type_fk',
- 'target_node_template_fk',
- 'target_node_type_fk',
- 'relationship_template_fk',
- 'node_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- @declared_attr
- def target_capability_type(cls):
- """
- Target capability type.
-
- :type: :class:`CapabilityType`
- """
- return relationship.one_to_one(cls,
- 'type',
- fk='target_capability_type_fk',
- back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def target_node_template(cls):
- """
- Target node template (can be ``None``).
-
- :type: :class:`NodeTemplate`
- """
- return relationship.one_to_one(cls,
- 'node_template',
- fk='target_node_template_fk',
- back_populates=relationship.NO_BACK_POP)
-
- @declared_attr
- def relationship_template(cls):
- """
- Associated relationship template (can be ``None``).
-
- :type: :class:`RelationshipTemplate`
- """
- return relationship.one_to_one(cls, 'relationship_template')
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def relationships(cls):
- """
- Instantiated relationships.
-
- :type: [:class:`Relationship`]
- """
- return relationship.one_to_many(cls, 'relationship')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def node_template(cls):
- """
- Containing node template.
-
- :type: :class:`NodeTemplate`
- """
- return relationship.many_to_one(cls, 'node_template',
fk='node_template_fk')
-
- @declared_attr
- def target_node_type(cls):
- """
- Target node type (can be ``None``).
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(
- cls, 'type', fk='target_node_type_fk',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def target_node_type_fk(cls):
- """For RequirementTemplate many-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def target_node_template_fk(cls):
- """For RequirementTemplate one-to-one to NodeTemplate"""
- return relationship.foreign_key('node_template', nullable=True)
-
- @declared_attr
- def target_capability_type_fk(cls):
- """For RequirementTemplate one-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- @declared_attr
- def node_template_fk(cls):
- """For NodeTemplate one-to-many to RequirementTemplate"""
- return relationship.foreign_key('node_template')
-
- @declared_attr
- def relationship_template_fk(cls):
- """For RequirementTemplate one-to-one to RelationshipTemplate"""
- return relationship.foreign_key('relationship_template', nullable=True)
-
- # endregion
-
- target_capability_name = Column(Text, doc="""
- Target capability name in node template or node type (can be ``None``).
-
- :type: :obj:`basestring`
- """)
-
- target_node_template_constraints = Column(PickleType, doc="""
- Constraints for filtering relationship targets.
-
- :type: [:class:`NodeTemplateConstraint`]
- """)
-
- def find_target(self, source_node_template):
- context = ConsumptionContext.get_thread_local()
-
- # We might already have a specific node template, so we'll just verify
it
- if self.target_node_template is not None:
- if not
source_node_template.is_target_node_template_valid(self.target_node_template):
- context.validation.report('requirement "{0}" of node template
"{1}" is for node '
- 'template "{2}" but it does not
match constraints'.format(
- self.name,
- self.target_node_template.name,
- source_node_template.name),
- level=validation.Issue.BETWEEN_TYPES)
- if (self.target_capability_type is not None) \
- or (self.target_capability_name is not None):
- target_node_capability =
self.find_target_capability(source_node_template,
-
self.target_node_template)
- if target_node_capability is None:
- return None, None
- else:
- target_node_capability = None
-
- return self.target_node_template, target_node_capability
-
- # Find first node that matches the type
- elif self.target_node_type is not None:
- for target_node_template in \
-
self.node_template.service_template.node_templates.values():
- if
self.target_node_type.get_descendant(target_node_template.type.name) is None:
- continue
-
- if not
source_node_template.is_target_node_template_valid(target_node_template):
- continue
-
- target_node_capability =
self.find_target_capability(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, source_node_template,
target_node_template):
- for capability_template in
target_node_template.capability_templates.itervalues():
- if capability_template.satisfies_requirement(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
- if self.target_node_type is not None else None),
- ('target_node_template_name', self.target_node_template.name
- if self.target_node_template is not None else None),
- ('target_capability_type_name', self.target_capability_type.name
- if self.target_capability_type is not None else None),
- ('target_capability_name', self.target_capability_name),
- ('relationship_template',
formatting.as_raw(self.relationship_template))))
-
- def validate(self):
- if self.relationship_template:
- self.relationship_template.validate()
-
- def coerce_values(self, report_issues):
- if self.relationship_template is not None:
- self.relationship_template.coerce_values(report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- if self.name:
- console.puts(context.style.node(self.name))
- else:
- console.puts('Requirement:')
- with context.style.indent:
- if self.target_node_type is not None:
- console.puts('Target node type: {0}'.format(
- context.style.type(self.target_node_type.name)))
- elif self.target_node_template is not None:
- console.puts('Target node template: {0}'.format(
- context.style.node(self.target_node_template.name)))
- if self.target_capability_type is not None:
- console.puts('Target capability type: {0}'.format(
- context.style.type(self.target_capability_type.name)))
- elif self.target_capability_name is not None:
- console.puts('Target capability name: {0}'.format(
- 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()
-
-
-class RelationshipTemplateBase(TemplateModelMixin):
- """
- Optional addition to a :class:`RequirementTemplate`.
-
- Note that a relationship template here is not exactly equivalent to a
relationship template
- entity in TOSCA. For example, a TOSCA requirement specifying a
relationship type rather than a
- relationship template would still be represented here as a relationship
template.
- """
-
- __tablename__ = 'relationship_template'
-
- __private_fields__ = ('type_fk',)
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def relationships(cls):
- """
- Instantiated relationships.
-
- :type: [:class:`Relationship`]
- """
- return relationship.one_to_many(cls, 'relationship')
-
- @declared_attr
- def interface_templates(cls):
- """
- Associated interface templates.
-
- :type: {:obj:`basestring`: :class:`InterfaceTemplate`}
- """
- return relationship.one_to_many(cls, 'interface_template',
dict_key='name')
-
- @declared_attr
- def properties(cls):
- """
- Declarations for associated immutable parameters.
-
- :type: {:obj:`basestring`: :class:`Property`}
- """
- return relationship.one_to_many(cls, 'property', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def type(cls):
- """
- Relationship type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def type_fk(cls):
- """For RelationshipTemplate many-to-one to Type"""
- return relationship.foreign_key('type', nullable=True)
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('type_name', self.type.name if self.type is not None else None),
- ('name', self.name),
- ('description', self.description),
- ('properties', formatting.as_raw_dict(self.properties)),
- ('interface_templates',
formatting.as_raw_list(self.interface_templates))))
-
- def instantiate(self, container):
- from . import models
- relationship_model = models.Relationship(name=self.name,
- type=self.type,
- relationship_template=self)
- utils.instantiate_dict(container, relationship_model.properties,
self.properties)
- utils.instantiate_dict(container, relationship_model.interfaces,
self.interface_templates)
- return relationship_model
-
- def validate(self):
- # TODO: either type or name must be set
- utils.validate_dict_values(self.properties)
- utils.validate_dict_values(self.interface_templates)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.properties, report_issues)
- utils.coerce_dict_values(self.interface_templates, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- if self.type is not None:
- console.puts('Relationship type:
{0}'.format(context.style.type(self.type.name)))
- else:
- console.puts('Relationship template: {0}'.format(
- context.style.node(self.name)))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- utils.dump_dict_values(self.properties, 'Properties')
- utils.dump_interfaces(self.interface_templates, 'Interface
templates')
-
-
-class CapabilityTemplateBase(TemplateModelMixin):
- """
- Template for creating :class:`Capability` instances, typed attachments
which serve two purposes:
- to provide extra properties and attributes to :class:`Node` instances, and
to expose targets for
- :class:`Relationship` instances from other nodes.
- """
-
- __tablename__ = 'capability_template'
-
- __private_fields__ = ('type_fk',
- 'node_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def capabilities(cls):
- """
- Instantiated capabilities.
-
- :type: [:class:`Capability`]
- """
- return relationship.one_to_many(cls, 'capability')
-
- @declared_attr
- def properties(cls):
- """
- Declarations for associated immutable parameters.
-
- :type: {:obj:`basestring`: :class:`Property`}
- """
- return relationship.one_to_many(cls, 'property', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def node_template(cls):
- """
- Containing node template.
-
- :type: :class:`NodeTemplate`
- """
- return relationship.many_to_one(cls, 'node_template')
-
- @declared_attr
- def type(cls):
- """
- Capability type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region many_to_many relationships
-
- @declared_attr
- def valid_source_node_types(cls):
- """
- Reject requirements that are not from these node types.
-
- :type: [:class:`Type`]
- """
- return relationship.many_to_many(cls, 'type', prefix='valid_sources')
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def type_fk(cls):
- """For CapabilityTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- @declared_attr
- def node_template_fk(cls):
- """For NodeTemplate one-to-many to CapabilityTemplate"""
- return relationship.foreign_key('node_template')
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- min_occurrences = Column(Integer, default=None, doc="""
- Minimum number of requirement matches required.
-
- :type: :obj:`int`
- """)
-
- max_occurrences = Column(Integer, default=None, doc="""
- Maximum number of requirement matches allowed.
-
- :type: :obj:`int`
- """)
-
- def satisfies_requirement(self,
- source_node_template,
- requirement,
- target_node_template):
- # Do we match the required capability type?
- if requirement.target_capability_type and \
- requirement.target_capability_type.get_descendant(self.type.name)
is None:
- return False
-
- # Are we in valid_source_node_types?
- if self.valid_source_node_types:
- for valid_source_node_type in self.valid_source_node_types:
- if
valid_source_node_type.get_descendant(source_node_template.type.name) is None:
- return False
-
- # Apply requirement constraints
- if requirement.target_node_template_constraints:
- for node_template_constraint in
requirement.target_node_template_constraints:
- if not node_template_constraint.matches(source_node_template,
target_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_types', [v.name for v in
self.valid_source_node_types]),
- ('properties', formatting.as_raw_dict(self.properties))))
-
- def instantiate(self, container):
- from . import models
- capability = models.Capability(name=self.name,
- type=self.type,
- min_occurrences=self.min_occurrences,
- max_occurrences=self.max_occurrences,
- occurrences=0,
- capability_template=self)
- utils.instantiate_dict(container, capability.properties,
self.properties)
- return capability
-
- def validate(self):
- utils.validate_dict_values(self.properties)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.properties, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- console.puts(context.style.node(self.name))
- if self.description:
- console.puts(context.style.meta(self.description))
- with context.style.indent:
- console.puts('Type:
{0}'.format(context.style.type(self.type.name)))
- console.puts(
- 'Occurrences: {0:d}{1}'.format(
- self.min_occurrences or 0,
- ' to {0:d}'.format(self.max_occurrences)
- if self.max_occurrences is not None
- else ' or more'))
- if self.valid_source_node_types:
- console.puts('Valid source node types: {0}'.format(
- ', '.join((str(context.style.type(v.name))
- for v in self.valid_source_node_types))))
- utils.dump_dict_values(self.properties, 'Properties')
-
-
-class InterfaceTemplateBase(TemplateModelMixin):
- """
- Template for creating :class:`Interface` instances, which are typed
bundles of
- :class:`Operation` instances.
-
- Can be associated with a :class:`NodeTemplate`, a :class:`GroupTemplate`,
or a
- :class:`RelationshipTemplate`.
- """
-
- __tablename__ = 'interface_template'
-
- __private_fields__ = ('type_fk',
- 'node_template_fk',
- 'group_template_fk',
- 'relationship_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def inputs(cls):
- """
- Declarations for externally provided parameters that can be used by
all operations of the
- interface.
-
- :type: {:obj:`basestring`: :class:`Input`}
- """
- return relationship.one_to_many(cls, 'input', dict_key='name')
-
- @declared_attr
- def interfaces(cls):
- """
- Instantiated interfaces.
-
- :type: [:class:`Interface`]
- """
- return relationship.one_to_many(cls, 'interface')
-
- @declared_attr
- def operation_templates(cls):
- """
- Associated operation templates.
-
- :type: {:obj:`basestring`: :class:`OperationTemplate`}
- """
- return relationship.one_to_many(cls, 'operation_template',
dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def node_template(cls):
- """
- Containing node template (can be ``None``).
-
- :type: :class:`NodeTemplate`
- """
- return relationship.many_to_one(cls, 'node_template')
-
- @declared_attr
- def group_template(cls):
- """
- Containing group template (can be ``None``).
-
- :type: :class:`GroupTemplate`
- """
- return relationship.many_to_one(cls, 'group_template')
-
- @declared_attr
- def relationship_template(cls):
- """
- Containing relationship template (can be ``None``).
-
- :type: :class:`RelationshipTemplate`
- """
- return relationship.many_to_one(cls, 'relationship_template')
-
- @declared_attr
- def type(cls):
- """
- Interface type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def type_fk(cls):
- """For InterfaceTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- @declared_attr
- def node_template_fk(cls):
- """For NodeTemplate one-to-many to InterfaceTemplate"""
- return relationship.foreign_key('node_template', nullable=True)
-
- @declared_attr
- def group_template_fk(cls):
- """For GroupTemplate one-to-many to InterfaceTemplate"""
- return relationship.foreign_key('group_template', nullable=True)
-
- @declared_attr
- def relationship_template_fk(cls):
- """For RelationshipTemplate one-to-many to InterfaceTemplate"""
- return relationship.foreign_key('relationship_template', nullable=True)
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- @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)), # pylint:
disable=no-member
- # TODO fix self.properties reference
- ('operation_templates',
formatting.as_raw_list(self.operation_templates))))
-
- def instantiate(self, container):
- from . import models
- interface = models.Interface(name=self.name,
- type=self.type,
-
description=deepcopy_with_locators(self.description),
- interface_template=self)
- utils.instantiate_dict(container, interface.inputs, self.inputs)
- utils.instantiate_dict(container, interface.operations,
self.operation_templates)
- return interface
-
- def validate(self):
- utils.validate_dict_values(self.inputs)
- utils.validate_dict_values(self.operation_templates)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.inputs, report_issues)
- utils.coerce_dict_values(self.operation_templates, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- 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:
{0}'.format(context.style.type(self.type.name)))
- utils.dump_dict_values(self.inputs, 'Inputs')
- utils.dump_dict_values(self.operation_templates, 'Operation
templates')
-
-
-class OperationTemplateBase(TemplateModelMixin):
- """
- Template for creating :class:`Operation` instances, which are entry points
to Python functions
- called as part of a workflow execution.
- """
-
- __tablename__ = 'operation_template'
-
- __private_fields__ = ('service_template_fk',
- 'interface_template_fk',
- 'plugin_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- @declared_attr
- def plugin_specification(cls):
- """
- Associated plugin specification.
-
- :type: :class:`PluginSpecification`
- """
- return relationship.one_to_one(
- cls, 'plugin_specification',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def operations(cls):
- """
- Instantiated operations.
-
- :type: [:class:`Operation`]
- """
- return relationship.one_to_many(cls, 'operation')
-
- @declared_attr
- def inputs(cls):
- """
- Declarations for parameters provided to the :attr:`implementation`.
-
- :type: {:obj:`basestring`: :class:`Input`}
- """
- return relationship.one_to_many(cls, 'input', dict_key='name')
-
- @declared_attr
- def configurations(cls):
- """
- Configuration parameters for the operation instance Python
:attr:`function`.
-
- :type: {:obj:`basestring`: :class:`Configuration`}
- """
- return relationship.one_to_many(cls, 'configuration', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def service_template(cls):
- """
- Containing service template (can be ``None``). For workflow operation
templates.
-
- :type: :class:`ServiceTemplate`
- """
- return relationship.many_to_one(cls, 'service_template',
- back_populates='workflow_templates')
-
- @declared_attr
- def interface_template(cls):
- """
- Containing interface template (can be ``None``).
-
- :type: :class:`InterfaceTemplate`
- """
- return relationship.many_to_one(cls, 'interface_template')
-
- # endregion
-
- # region many_to_many relationships
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def service_template_fk(cls):
- """For ServiceTemplate one-to-many to OperationTemplate"""
- return relationship.foreign_key('service_template', nullable=True)
-
- @declared_attr
- def interface_template_fk(cls):
- """For InterfaceTemplate one-to-many to OperationTemplate"""
- return relationship.foreign_key('interface_template', nullable=True)
-
- @declared_attr
- def plugin_specification_fk(cls):
- """For OperationTemplate one-to-one to PluginSpecification"""
- return relationship.foreign_key('plugin_specification', nullable=True)
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- relationship_edge = Column(Boolean, doc="""
- When ``True`` specifies that the operation is on the relationship's target
edge; ``False`` is
- the source edge (only used by operations on relationships)
-
- :type: :obj:`bool`
- """)
-
- implementation = Column(Text, doc="""
- Implementation (usually the name of an artifact).
-
- :type: :obj:`basestring`
- """)
-
- dependencies = Column(modeling_types.StrictList(item_cls=basestring),
doc="""
- Dependencies (usually names of artifacts).
-
- :type: [:obj:`basestring`]
- """)
-
- function = Column(Text, doc="""
- Full path to Python function.
-
- :type: :obj:`basestring`
- """)
-
- executor = Column(Text, doc="""
- Name of executor.
-
- :type: :obj:`basestring`
- """)
-
- max_attempts = Column(Integer, doc="""
- Maximum number of attempts allowed in case of task failure.
-
- :type: :obj:`int`
- """)
-
- retry_interval = Column(Integer, doc="""
- Interval between task retry attemps (in seconds).
-
- :type: :obj:`float`
- """)
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('description', self.description),
- ('implementation', self.implementation),
- ('dependencies', self.dependencies),
- ('inputs', formatting.as_raw_dict(self.inputs))))
-
- def instantiate(self, container):
- from . import models
-
- plugin = self.plugin_specification.plugin \
- if (self.plugin_specification is not None) and
self.plugin_specification.enabled \
- else None
-
- operation = models.Operation(name=self.name,
-
description=deepcopy_with_locators(self.description),
- relationship_edge=self.relationship_edge,
- implementation=self.implementation,
- dependencies=self.dependencies,
- executor=self.executor,
- plugin=plugin,
- function=self.function,
- max_attempts=self.max_attempts,
- retry_interval=self.retry_interval,
- operation_template=self)
-
- utils.instantiate_dict(container, operation.inputs, self.inputs)
- utils.instantiate_dict(container, operation.configurations,
self.configurations)
-
- return operation
-
- def validate(self):
- utils.validate_dict_values(self.inputs)
- utils.validate_dict_values(self.configurations)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.inputs, report_issues)
- utils.coerce_dict_values(self.configurations, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- 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: {0}'.format(
- context.style.literal(self.implementation)))
- if self.dependencies:
- console.puts('Dependencies: {0}'.format(
- ', '.join((str(context.style.literal(v)) for v in
self.dependencies))))
- utils.dump_dict_values(self.inputs, 'Inputs')
- if self.executor is not None:
- console.puts('Executor:
{0}'.format(context.style.literal(self.executor)))
- if self.max_attempts is not None:
- console.puts('Max attempts:
{0}'.format(context.style.literal(self.max_attempts)))
- if self.retry_interval is not None:
- console.puts('Retry interval: {0}'.format(
- context.style.literal(self.retry_interval)))
- if self.plugin_specification is not None:
- console.puts('Plugin specification: {0}'.format(
- context.style.literal(self.plugin_specification.name)))
- utils.dump_dict_values(self.configurations, 'Configuration')
- if self.function is not None:
- console.puts('Function:
{0}'.format(context.style.literal(self.function)))
-
-
-class ArtifactTemplateBase(TemplateModelMixin):
- """
- Template for creating an :class:`Artifact` instance, which is a typed
file, either provided in a
- CSAR or downloaded from a repository.
- """
-
- __tablename__ = 'artifact_template'
-
- __private_fields__ = ('type_fk',
- 'node_template_fk')
-
- # region association proxies
-
- # endregion
-
- # region one_to_one relationships
-
- # endregion
-
- # region one_to_many relationships
-
- @declared_attr
- def artifacts(cls):
- """
- Instantiated artifacts.
-
- :type: [:class:`Artifact`]
- """
- return relationship.one_to_many(cls, 'artifact')
-
- @declared_attr
- def properties(cls):
- """
- Declarations for associated immutable parameters.
-
- :type: {:obj:`basestring`: :class:`Property`}
- """
- return relationship.one_to_many(cls, 'property', dict_key='name')
-
- # endregion
-
- # region many_to_one relationships
-
- @declared_attr
- def node_template(cls):
- """
- Containing node template.
-
- :type: :class:`NodeTemplate`
- """
- return relationship.many_to_one(cls, 'node_template')
-
- @declared_attr
- def type(cls):
- """
- Artifact type.
-
- :type: :class:`Type`
- """
- return relationship.many_to_one(cls, 'type',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def type_fk(cls):
- """For ArtifactTemplate many-to-one to Type"""
- return relationship.foreign_key('type')
-
- @declared_attr
- def node_template_fk(cls):
- """For NodeTemplate one-to-many to ArtifactTemplate"""
- return relationship.foreign_key('node_template')
-
- # endregion
-
- description = Column(Text, doc="""
- Human-readable description.
-
- :type: :obj:`basestring`
- """)
-
- source_path = Column(Text, doc="""
- Source path (in CSAR or repository).
-
- :type: :obj:`basestring`
- """)
-
- target_path = Column(Text, doc="""
- Path at which to install at destination.
-
- :type: :obj:`basestring`
- """)
-
- repository_url = Column(Text, doc="""
- Repository URL.
-
- :type: :obj:`basestring`
- """)
-
- repository_credential = Column(modeling_types.StrictDict(basestring,
basestring), doc="""
- Credentials for accessing the repository.
-
- :type: {:obj:`basestring`, :obj:`basestring`}
- """)
-
- @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 instantiate(self, container):
- from . import models
- artifact = models.Artifact(name=self.name,
- type=self.type,
-
description=deepcopy_with_locators(self.description),
- source_path=self.source_path,
- target_path=self.target_path,
- repository_url=self.repository_url,
-
repository_credential=self.repository_credential,
- artifact_template=self)
- utils.instantiate_dict(container, artifact.properties, self.properties)
- return artifact
-
- def validate(self):
- utils.validate_dict_values(self.properties)
-
- def coerce_values(self, report_issues):
- utils.coerce_dict_values(self.properties, report_issues)
-
- def dump(self):
- context = ConsumptionContext.get_thread_local()
- 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:
{0}'.format(context.style.type(self.type.name)))
- console.puts('Source path:
{0}'.format(context.style.literal(self.source_path)))
- if self.target_path is not None:
- console.puts('Target path:
{0}'.format(context.style.literal(self.target_path)))
- if self.repository_url is not None:
- console.puts('Repository URL: {0}'.format(
- context.style.literal(self.repository_url)))
- if self.repository_credential:
- console.puts('Repository credential: {0}'.format(
- context.style.literal(self.repository_credential)))
- utils.dump_dict_values(self.properties, 'Properties')
-
-
-class PluginSpecificationBase(TemplateModelMixin):
- """
- Requirement for a :class:`Plugin`.
-
- The actual plugin to be selected depends on those currently installed in
ARIA.
- """
-
- __tablename__ = 'plugin_specification'
-
- __private_fields__ = ('service_template_fk',
- 'plugin_fk')
-
- version = Column(Text, doc="""
- Minimum plugin version.
-
- :type: :obj:`basestring`
- """)
-
- enabled = Column(Boolean, nullable=False, default=True, doc="""
- Whether the plugin is enabled.
-
- :type: :obj:`bool`
- """)
-
- # region many_to_one relationships
-
- @declared_attr
- def service_template(cls):
- """
- Containing service template.
-
- :type: :class:`ServiceTemplate`
- """
- return relationship.many_to_one(cls, 'service_template')
-
- @declared_attr
- def plugin(cls): # pylint: disable=method-hidden
- """
- Matched plugin.
-
- :type: :class:`Plugin`
- """
- return relationship.many_to_one(cls, 'plugin',
back_populates=relationship.NO_BACK_POP)
-
- # endregion
-
- # region foreign keys
-
- @declared_attr
- def service_template_fk(cls):
- """For ServiceTemplate one-to-many to PluginSpecification"""
- return relationship.foreign_key('service_template', nullable=True)
-
- @declared_attr
- def plugin_fk(cls):
- """For PluginSpecification many-to-one to Plugin"""
- return relationship.foreign_key('plugin', nullable=True)
-
- # endregion
-
- @property
- def as_raw(self):
- return collections.OrderedDict((
- ('name', self.name),
- ('version', self.version),
- ('enabled', self.enabled)))
-
- def coerce_values(self, report_issues):
- pass
-
- def resolve(self, model_storage):
- # TODO: we are planning a separate "instantiation" module where this
will be called or
- # moved to.
- plugins = model_storage.plugin.list()
- matching_plugins = []
- if plugins:
- for plugin in plugins:
- if (plugin.name == self.name) and \
- ((self.version is None) or \
- (VersionString(plugin.package_version) >= self.version)):
- matching_plugins.append(plugin)
- self.plugin = None
- if matching_plugins:
- # Return highest version of plugin
- key = lambda plugin: VersionString(plugin.package_version).key
- self.plugin = sorted(matching_plugins, key=key)[-1]
- return self.plugin is not None