wip
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/56841a4d Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/56841a4d Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/56841a4d Branch: refs/heads/ARIA-174-Refactor-instantiation-phase Commit: 56841a4d235201272faf496d3d77625b59d90f86 Parents: a43bc6b Author: max-orlov <ma...@gigaspaces.com> Authored: Thu Jul 13 16:49:15 2017 +0300 Committer: max-orlov <ma...@gigaspaces.com> Committed: Wed Aug 9 14:54:08 2017 +0300 ---------------------------------------------------------------------- aria/cli/commands/executions.py | 2 +- aria/cli/commands/service_templates.py | 7 +- aria/cli/commands/services.py | 6 +- aria/core.py | 36 +- aria/modeling/functions.py | 9 +- aria/modeling/mixins.py | 34 +- aria/modeling/service_common.py | 27 - aria/modeling/service_instance.py | 535 +------------- aria/modeling/service_template.py | 706 +------------------ aria/modeling/utils.py | 85 +-- .../execution_plugin/instantiation.py | 64 +- aria/orchestrator/topology/__init__.py | 16 + aria/orchestrator/topology/common.py | 52 ++ aria/orchestrator/topology/instance_handler.py | 644 +++++++++++++++++ aria/orchestrator/topology/template_handler.py | 597 ++++++++++++++++ aria/orchestrator/topology/topology.py | 217 ++++++ aria/orchestrator/topology/utils.py | 67 ++ aria/orchestrator/workflow_runner.py | 5 +- aria/orchestrator/workflows/api/task.py | 5 +- aria/parser/consumption/__init__.py | 3 - aria/parser/consumption/consumer.py | 6 + aria/parser/consumption/context.py | 4 +- aria/parser/consumption/modeling.py | 49 +- aria/parser/consumption/style.py | 54 -- aria/parser/modeling/context.py | 6 +- aria/parser/presentation/fields.py | 10 +- aria/parser/presentation/presentation.py | 4 +- aria/parser/reading/__init__.py | 6 +- aria/parser/reading/locator.py | 35 - aria/parser/validation/context.py | 59 +- aria/parser/validation/issue.py | 72 +- aria/utils/console.py | 53 +- .../simple_v1_0/modeling/__init__.py | 4 +- tests/instantiation/test_configuration.py | 13 +- tests/parser/service_templates.py | 17 +- tests/parser/test_reqs_caps.py | 29 + .../tosca-simple-1.0/reqs_caps/reqs_caps1.yaml | 40 ++ tests/storage/__init__.py | 2 - 38 files changed, 1951 insertions(+), 1629 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/cli/commands/executions.py ---------------------------------------------------------------------- diff --git a/aria/cli/commands/executions.py b/aria/cli/commands/executions.py index 4783442..f130d95 100644 --- a/aria/cli/commands/executions.py +++ b/aria/cli/commands/executions.py @@ -181,7 +181,7 @@ def resume(execution_id, executor = DryExecutor() if dry else None # use WorkflowRunner's default executor execution = model_storage.execution.get(execution_id) - if execution.status != execution.status.CANCELLED: + if execution.status != execution.CANCELLED: logger.info("Can't resume execution {execution.id} - " "execution is in status {execution.status}. " "Can only resume executions in status {valid_status}" http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/cli/commands/service_templates.py ---------------------------------------------------------------------- diff --git a/aria/cli/commands/service_templates.py b/aria/cli/commands/service_templates.py index f567aa8..608d178 100644 --- a/aria/cli/commands/service_templates.py +++ b/aria/cli/commands/service_templates.py @@ -28,7 +28,7 @@ from ...core import Core from ...storage import exceptions as storage_exceptions from ...parser import consumption from ...utils import (formatting, collections, console) - +from ... orchestrator.topology import Topology DESCRIPTION_FIELD_LENGTH_LIMIT = 20 SERVICE_TEMPLATE_COLUMNS = \ @@ -73,10 +73,9 @@ def show(service_template_name, model_storage, mode_full, mode_types, format_jso elif format_yaml: console.puts(formatting.yaml_dumps(collections.prune(service_template.as_raw))) else: - service_template.dump() + console.puts(Topology().dump(service_template)) elif mode_types: - consumption.ConsumptionContext() - service_template.dump_types() + console.puts(Topology().dump_types(service_template=service_template)) else: logger.info('Showing service template {0}...'.format(service_template_name)) service_template_dict = service_template.to_dict() http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/cli/commands/services.py ---------------------------------------------------------------------- diff --git a/aria/cli/commands/services.py b/aria/cli/commands/services.py index a99f5b3..4890bb7 100644 --- a/aria/cli/commands/services.py +++ b/aria/cli/commands/services.py @@ -20,6 +20,7 @@ CLI ``services`` sub-commands. import os from StringIO import StringIO +from aria.orchestrator.topology import Topology from . import service_templates from .. import helptexts from .. import table @@ -73,10 +74,9 @@ def show(service_name, model_storage, mode_full, mode_graph, format_json, format elif format_yaml: console.puts(formatting.yaml_dumps(collections.prune(service.as_raw))) else: - service.dump() + console.puts(Topology().dump(service)) elif mode_graph: - consumption.ConsumptionContext() - service.dump_graph() + console.puts(Topology().dump_graph(service)) else: logger.info('Showing service {0}...'.format(service_name)) service_dict = service.to_dict() http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/core.py ---------------------------------------------------------------------- diff --git a/aria/core.py b/aria/core.py index e214b1a..e726be7 100644 --- a/aria/core.py +++ b/aria/core.py @@ -20,6 +20,7 @@ ARIA core module. from . import exceptions from .parser import consumption from .parser.loading.location import UriLocation +from .orchestrator.topology import Topology class Core(object): @@ -67,31 +68,26 @@ class Core(object): self.resource_storage.service_template.delete(entry_id=str(service_template.id)) def create_service(self, service_template_id, inputs, service_name=None): - service_template = self.model_storage.service_template.get(service_template_id) - # creating an empty ConsumptionContext, initiating a threadlocal context - context = consumption.ConsumptionContext() - storage_session = self.model_storage._all_api_kwargs['session'] # setting no autoflush for the duration of instantiation - this helps avoid dependency # constraints as they're being set up with storage_session.no_autoflush: - service = service_template.instantiate(None, self.model_storage, inputs=inputs) - - consumption.ConsumerChain( - context, - ( - consumption.CoerceServiceInstanceValues, - consumption.ValidateServiceInstance, - consumption.SatisfyRequirements, - consumption.CoerceServiceInstanceValues, - consumption.ValidateCapabilities, - consumption.FindHosts, - consumption.ConfigureOperations, - consumption.CoerceServiceInstanceValues - )).consume() - if context.validation.dump_issues(): + topology = Topology(self.model_storage) + service = topology.instantiate(service_template, inputs=inputs) + topology.coerce(service) + + topology.validate(service) + topology.satisfy_requirements(service) + topology.coerce(service) + + topology.validate_capabilities(service) + topology.find_hosts(service) + topology.configure_operations(service) + topology.coerce(service) + + if topology.dump_issues(): raise exceptions.InstantiationError('Failed to instantiate service template `{0}`' .format(service_template.name)) @@ -122,6 +118,8 @@ class Core(object): def _parse_service_template(service_template_path): context = consumption.ConsumptionContext() context.presentation.location = UriLocation(service_template_path) + # TODO: this is the last place which uses the consumer chains (since read is a proper Parser + # todo..based consumer, it has no place in the topology package). consumption.ConsumerChain( context, ( http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/modeling/functions.py ---------------------------------------------------------------------- diff --git a/aria/modeling/functions.py b/aria/modeling/functions.py index 6544adf..7330268 100644 --- a/aria/modeling/functions.py +++ b/aria/modeling/functions.py @@ -17,7 +17,6 @@ Mechanism for evaluating intrinsic functions. """ -from ..parser.consumption import ConsumptionContext from ..parser.exceptions import InvalidValueError from ..utils.collections import OrderedDict from . import exceptions @@ -103,10 +102,12 @@ def evaluate(value, container_holder, report_issues=False): # pylint: disable=to final = False except exceptions.CannotEvaluateFunctionException: pass - except InvalidValueError as e: + except InvalidValueError: if report_issues: - context = ConsumptionContext.get_thread_local() - context.validation.report(e.issue) + # TODO: do not use the context for "reporting" + pass + # context = ConsumptionContext.get_thread_local() + # context.validation.report(e.issue) elif isinstance(value, list): evaluated_list = [] http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/modeling/mixins.py ---------------------------------------------------------------------- diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py index 4acbe6e..1a3cb32 100644 --- a/aria/modeling/mixins.py +++ b/aria/modeling/mixins.py @@ -25,8 +25,7 @@ from sqlalchemy import ( PickleType ) -from ..parser.consumption import ConsumptionContext -from ..utils import console, collections, caching, formatting +from ..utils import collections, caching from ..utils.type import canonical_type_name, full_type_name from . import utils, functions @@ -132,26 +131,17 @@ class InstanceModelMixin(ModelMixin): def as_raw(self): raise NotImplementedError - def validate(self): - pass - def coerce_values(self, report_issues): pass - def dump(self): - pass - -class TemplateModelMixin(InstanceModelMixin): +class TemplateModelMixin(InstanceModelMixin): # pylint: disable=abstract-method """ Mix-in for service template models. All model models can be instantiated into service instance models. """ - def instantiate(self, container): - raise NotImplementedError - class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods): #pylint: disable=abstract-method """ @@ -306,12 +296,6 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods): ('value', self.value), ('description', self.description))) - def instantiate(self, container): - return self.__class__(name=self.name, # pylint: disable=unexpected-keyword-arg - type_name=self.type_name, - _value=self._value, - description=self.description) - def coerce_values(self, report_issues): value = self._value if value is not None: @@ -320,20 +304,6 @@ class ParameterMixin(TemplateModelMixin, caching.HasCachedMethods): # A final evaluation can safely replace the existing value self._value = evaluation.value - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.type_name is not None: - console.puts('{0}: {1} ({2})'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)), - context.style.type(self.type_name))) - else: - console.puts('{0}: {1}'.format( - context.style.property(self.name), - context.style.literal(formatting.as_raw(self.value)))) - if self.description: - console.puts(context.style.meta(self.description)) - @property def unwrapped(self): return self.name, self.value http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/modeling/service_common.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py index 4ce9dae..478e530 100644 --- a/aria/modeling/service_common.py +++ b/aria/modeling/service_common.py @@ -26,11 +26,9 @@ from sqlalchemy import ( ) from sqlalchemy.ext.declarative import declared_attr -from ..parser.consumption import ConsumptionContext from ..utils import ( collections, formatting, - console, ) from .mixins import InstanceModelMixin, TemplateModelMixin, ParameterMixin from . import relationship @@ -563,17 +561,6 @@ class TypeBase(InstanceModelMixin): self._append_raw_children(types) return types - def coerce_values(self, report_issues): - pass - - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.name: - console.puts(context.style.type(self.name)) - with context.style.indent: - for child in self.children: - child.dump() - def _append_raw_children(self, types): for child in self.children: raw_child = formatting.as_raw(child) @@ -612,17 +599,3 @@ class MetadataBase(TemplateModelMixin): return collections.OrderedDict(( ('name', self.name), ('value', self.value))) - - def coerce_values(self, report_issues): - pass - - def instantiate(self, container): - from . import models - return models.Metadata(name=self.name, - value=self.value) - - def dump(self): - context = ConsumptionContext.get_thread_local() - console.puts('{0}: {1}'.format( - context.style.property(self.name), - context.style.literal(self.value))) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/modeling/service_instance.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py index ae6a0a0..daeb0a4 100644 --- a/aria/modeling/service_instance.py +++ b/aria/modeling/service_instance.py @@ -30,19 +30,15 @@ from sqlalchemy import DateTime from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.orderinglist import ordering_list +from . import ( + relationship, + types as modeling_types +) from .mixins import InstanceModelMixin -from ..orchestrator import execution_plugin -from ..parser import validation -from ..parser.consumption import ConsumptionContext + from ..utils import ( collections, formatting, - console -) -from . import ( - relationship, - utils, - types as modeling_types ) @@ -232,50 +228,6 @@ class ServiceBase(InstanceModelMixin): :type: :class:`~datetime.datetime` """) - def satisfy_requirements(self): - satisfied = True - for node in self.nodes.itervalues(): - if not node.satisfy_requirements(): - satisfied = False - return satisfied - - def validate_capabilities(self): - satisfied = True - for node in self.nodes.itervalues(): - if not node.validate_capabilities(): - satisfied = False - return satisfied - - def find_hosts(self): - for node in self.nodes.itervalues(): - node.find_host() - - def configure_operations(self): - for node in self.nodes.itervalues(): - node.configure_operations() - for group in self.groups.itervalues(): - group.configure_operations() - for operation in self.workflows.itervalues(): - operation.configure() - - def is_node_a_target(self, target_node): - for node in self.nodes.itervalues(): - if self._is_node_a_target(node, target_node): - return True - return False - - def _is_node_a_target(self, source_node, target_node): - if source_node.outbound_relationships: - for relationship_model in source_node.outbound_relationships: - if relationship_model.target_node.name == target_node.name: - return True - else: - node = relationship_model.target_node - if node is not None: - if self._is_node_a_target(node, target_node): - return True - return False - @property def as_raw(self): return collections.OrderedDict(( @@ -289,70 +241,6 @@ class ServiceBase(InstanceModelMixin): ('outputs', formatting.as_raw_dict(self.outputs)), ('workflows', formatting.as_raw_list(self.workflows)))) - def validate(self): - utils.validate_dict_values(self.meta_data) - utils.validate_dict_values(self.nodes) - utils.validate_dict_values(self.groups) - utils.validate_dict_values(self.policies) - if self.substitution is not None: - self.substitution.validate() - utils.validate_dict_values(self.inputs) - utils.validate_dict_values(self.outputs) - utils.validate_dict_values(self.workflows) - - def coerce_values(self, report_issues): - utils.coerce_dict_values(self.meta_data, report_issues) - utils.coerce_dict_values(self.nodes, report_issues) - utils.coerce_dict_values(self.groups, report_issues) - utils.coerce_dict_values(self.policies, report_issues) - if self.substitution is not None: - self.substitution.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.workflows, 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 in self.nodes.itervalues(): - node.dump() - for group in self.groups.itervalues(): - group.dump() - for policy in self.policies.itervalues(): - policy.dump() - if self.substitution is not None: - self.substitution.dump() - utils.dump_dict_values(self.inputs, 'Inputs') - utils.dump_dict_values(self.outputs, 'Outputs') - utils.dump_dict_values(self.workflows, 'Workflows') - - def dump_graph(self): - for node in self.nodes.itervalues(): - if not self.is_node_a_target(node): - self._dump_graph_node(node) - - def _dump_graph_node(self, node, capability=None): - context = ConsumptionContext.get_thread_local() - console.puts(context.style.node(node.name)) - if capability is not None: - console.puts('{0} ({1})'.format(context.style.property(capability.name), - context.style.type(capability.type.name))) - if node.outbound_relationships: - with context.style.indent: - for relationship_model in node.outbound_relationships: - relationship_name = context.style.property(relationship_model.name) - if relationship_model.type is not None: - console.puts('-> {0} ({1})'.format(relationship_name, - context.style.type( - relationship_model.type.name))) - else: - console.puts('-> {0}'.format(relationship_name)) - with console.indent(3): - self._dump_graph_node(relationship_model.target_node, - relationship_model.target_capability) - class NodeBase(InstanceModelMixin): """ @@ -616,118 +504,6 @@ class NodeBase(InstanceModelMixin): return attribute.value if attribute else None return None - def satisfy_requirements(self): - node_template = self.node_template - satisfied = True - for requirement_template in node_template.requirement_templates: - # Find target template - target_node_template, target_node_capability = \ - requirement_template.find_target(node_template) - if target_node_template is not None: - satisfied = self._satisfy_capability(target_node_capability, - target_node_template, - requirement_template) - else: - context = ConsumptionContext.get_thread_local() - context.validation.report('requirement "{0}" of node "{1}" has no target node ' - 'template'.format(requirement_template.name, self.name), - level=validation.Issue.BETWEEN_INSTANCES) - satisfied = False - return satisfied - - def _satisfy_capability(self, target_node_capability, target_node_template, - requirement_template): - from . import models - context = ConsumptionContext.get_thread_local() - # Find target nodes - target_nodes = target_node_template.nodes - if target_nodes: - target_node = None - target_capability = None - - if target_node_capability is not None: - # Relate to the first target node that has capacity - for node in target_nodes: - a_target_capability = node.capabilities.get(target_node_capability.name) - if a_target_capability.relate(): - target_node = node - target_capability = a_target_capability - break - else: - # Use first target node - target_node = target_nodes[0] - - if target_node is not None: - if requirement_template.relationship_template is not None: - relationship_model = \ - requirement_template.relationship_template.instantiate(self) - else: - relationship_model = models.Relationship() - relationship_model.name = requirement_template.name - relationship_model.requirement_template = requirement_template - relationship_model.target_node = target_node - relationship_model.target_capability = target_capability - self.outbound_relationships.append(relationship_model) - return True - else: - context.validation.report('requirement "{0}" of node "{1}" targets node ' - 'template "{2}" but its instantiated nodes do not ' - 'have enough capacity'.format( - requirement_template.name, - self.name, - target_node_template.name), - level=validation.Issue.BETWEEN_INSTANCES) - return False - else: - context.validation.report('requirement "{0}" of node "{1}" targets node template ' - '"{2}" but it has no instantiated nodes'.format( - requirement_template.name, - self.name, - target_node_template.name), - level=validation.Issue.BETWEEN_INSTANCES) - return False - - def validate_capabilities(self): - context = ConsumptionContext.get_thread_local() - satisfied = False - for capability in self.capabilities.itervalues(): - if not capability.has_enough_relationships: - context.validation.report('capability "{0}" of node "{1}" requires at least {2:d} ' - 'relationships but has {3:d}'.format( - capability.name, - self.name, - capability.min_occurrences, - capability.occurrences), - level=validation.Issue.BETWEEN_INSTANCES) - satisfied = False - return satisfied - - def find_host(self): - def _find_host(node): - if node.type.role == 'host': - return node - for the_relationship in node.outbound_relationships: - if (the_relationship.target_capability is not None) and \ - the_relationship.target_capability.type.role == 'host': - host = _find_host(the_relationship.target_node) - if host is not None: - return host - for the_relationship in node.inbound_relationships: - if (the_relationship.target_capability is not None) and \ - the_relationship.target_capability.type.role == 'feature': - host = _find_host(the_relationship.source_node) - if host is not None: - return host - return None - - self.host = _find_host(self) - - def configure_operations(self): - for interface in self.interfaces.itervalues(): - interface.configure_operations() - for the_relationship in self.outbound_relationships: - the_relationship.configure_operations() - @property def as_raw(self): return collections.OrderedDict(( @@ -740,46 +516,6 @@ class NodeBase(InstanceModelMixin): ('capabilities', formatting.as_raw_list(self.capabilities)), ('relationships', formatting.as_raw_list(self.outbound_relationships)))) - def validate(self): - context = ConsumptionContext.get_thread_local() - if len(self.name) > context.modeling.id_max_length: - context.validation.report('"{0}" has an ID longer than the limit of {1:d} characters: ' - '{2:d}'.format( - self.name, - context.modeling.id_max_length, - len(self.name)), - level=validation.Issue.BETWEEN_INSTANCES) - - # TODO: validate that node template is of type? - - utils.validate_dict_values(self.properties) - utils.validate_dict_values(self.attributes) - utils.validate_dict_values(self.interfaces) - utils.validate_dict_values(self.artifacts) - utils.validate_dict_values(self.capabilities) - utils.validate_list_values(self.outbound_relationships) - - 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.interfaces, report_issues) - utils.coerce_dict_values(self.artifacts, report_issues) - utils.coerce_dict_values(self.capabilities, report_issues) - utils.coerce_list_values(self.outbound_relationships, report_issues) - - def dump(self): - context = ConsumptionContext.get_thread_local() - console.puts('Node: {0}'.format(context.style.node(self.name))) - with context.style.indent: - console.puts('Type: {0}'.format(context.style.type(self.type.name))) - console.puts('Template: {0}'.format(context.style.node(self.node_template.name))) - utils.dump_dict_values(self.properties, 'Properties') - utils.dump_dict_values(self.attributes, 'Attributes') - utils.dump_interfaces(self.interfaces) - utils.dump_dict_values(self.artifacts, 'Artifacts') - utils.dump_dict_values(self.capabilities, 'Capabilities') - utils.dump_list_values(self.outbound_relationships, 'Relationships') - class GroupBase(InstanceModelMixin): """ @@ -885,10 +621,6 @@ class GroupBase(InstanceModelMixin): :type: :obj:`basestring` """) - def configure_operations(self): - for interface in self.interfaces.itervalues(): - interface.configure_operations() - @property def as_raw(self): return collections.OrderedDict(( @@ -896,27 +628,6 @@ class GroupBase(InstanceModelMixin): ('properties', formatting.as_raw_dict(self.properties)), ('interfaces', formatting.as_raw_list(self.interfaces)))) - def validate(self): - utils.validate_dict_values(self.properties) - utils.validate_dict_values(self.interfaces) - - def coerce_values(self, report_issues): - utils.coerce_dict_values(self.properties, report_issues) - utils.coerce_dict_values(self.interfaces, report_issues) - - def dump(self): - context = ConsumptionContext.get_thread_local() - console.puts('Group: {0}'.format(context.style.node(self.name))) - 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.interfaces) - if self.nodes: - console.puts('Member nodes:') - with context.style.indent: - for node in self.nodes: - console.puts(context.style.node(node.name)) - class PolicyBase(InstanceModelMixin): """ @@ -1030,29 +741,6 @@ class PolicyBase(InstanceModelMixin): ('type_name', self.type.name), ('properties', formatting.as_raw_dict(self.properties)))) - 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: {0}'.format(context.style.node(self.name))) - with context.style.indent: - console.puts('Type: {0}'.format(context.style.type(self.type.name))) - utils.dump_dict_values(self.properties, 'Properties') - if self.nodes: - console.puts('Target nodes:') - with context.style.indent: - for node in self.nodes: - console.puts(context.style.node(node.name)) - if self.groups: - console.puts('Target groups:') - with context.style.indent: - for group in self.groups: - console.puts(context.style.node(group.name)) - class SubstitutionBase(InstanceModelMixin): """ @@ -1130,19 +818,6 @@ class SubstitutionBase(InstanceModelMixin): ('node_type_name', self.node_type.name), ('mappings', formatting.as_raw_dict(self.mappings)))) - 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:') - 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 SubstitutionMappingBase(InstanceModelMixin): """ @@ -1238,31 +913,6 @@ class SubstitutionMappingBase(InstanceModelMixin): return collections.OrderedDict(( ('name', self.name),)) - def coerce_values(self, report_issues): - pass - - def validate(self): - context = ConsumptionContext.get_thread_local() - if (self.capability is None) and (self.requirement_template is None): - context.validation.report('mapping "{0}" refers to neither capability nor a requirement' - ' in node: {1}'.format( - self.name, - formatting.safe_repr(self.node.name)), - level=validation.Issue.BETWEEN_TYPES) - - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.capability is not None: - console.puts('{0} -> {1}.{2}'.format( - context.style.node(self.name), - context.style.node(self.capability.node.name), - context.style.node(self.capability.name))) - else: - console.puts('{0} -> {1}.{2}'.format( - context.style.node(self.name), - context.style.node(self.node.name), - context.style.node(self.requirement_template.name))) - class RelationshipBase(InstanceModelMixin): """ @@ -1436,10 +1086,6 @@ class RelationshipBase(InstanceModelMixin): :type: :obj:`int` """) - def configure_operations(self): - for interface in self.interfaces.itervalues(): - interface.configure_operations() - @property def as_raw(self): return collections.OrderedDict(( @@ -1452,33 +1098,6 @@ class RelationshipBase(InstanceModelMixin): ('properties', formatting.as_raw_dict(self.properties)), ('interfaces', formatting.as_raw_list(self.interfaces)))) - def validate(self): - utils.validate_dict_values(self.properties) - utils.validate_dict_values(self.interfaces) - - def coerce_values(self, report_issues): - utils.coerce_dict_values(self.properties, report_issues) - utils.coerce_dict_values(self.interfaces, report_issues) - - def dump(self): - context = ConsumptionContext.get_thread_local() - if self.name: - console.puts('{0} ->'.format(context.style.node(self.name))) - else: - console.puts('->') - with context.style.indent: - console.puts('Node: {0}'.format(context.style.node(self.target_node.name))) - if self.target_capability: - console.puts('Capability: {0}'.format(context.style.node( - self.target_capability.name))) - if self.type is not None: - console.puts('Relationship type: {0}'.format(context.style.type(self.type.name))) - if (self.relationship_template is not None) and self.relationship_template.name: - console.puts('Relationship template: {0}'.format( - context.style.node(self.relationship_template.name))) - utils.dump_dict_values(self.properties, 'Properties') - utils.dump_interfaces(self.interfaces, 'Interfaces') - class CapabilityBase(InstanceModelMixin): """ @@ -1595,25 +1214,6 @@ class CapabilityBase(InstanceModelMixin): ('type_name', self.type.name), ('properties', formatting.as_raw_dict(self.properties)))) - 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)) - with context.style.indent: - console.puts('Type: {0}'.format(context.style.type(self.type.name))) - console.puts('Occurrences: {0:d} ({1:d}{2})'.format( - self.occurrences, - self.min_occurrences or 0, - ' to {0:d}'.format(self.max_occurrences) - if self.max_occurrences is not None - else ' or more')) - utils.dump_dict_values(self.properties, 'Properties') - class InterfaceBase(InstanceModelMixin): """ @@ -1738,10 +1338,6 @@ class InterfaceBase(InstanceModelMixin): :type: :obj:`basestring` """) - def configure_operations(self): - for operation in self.operations.itervalues(): - operation.configure() - @property def as_raw(self): return collections.OrderedDict(( @@ -1751,24 +1347,6 @@ class InterfaceBase(InstanceModelMixin): ('inputs', formatting.as_raw_dict(self.inputs)), ('operations', formatting.as_raw_list(self.operations)))) - def validate(self): - utils.validate_dict_values(self.inputs) - utils.validate_dict_values(self.operations) - - def coerce_values(self, report_issues): - utils.coerce_dict_values(self.inputs, report_issues) - utils.coerce_dict_values(self.operations, 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.operations, 'Operations') - class OperationBase(InstanceModelMixin): """ @@ -1944,45 +1522,6 @@ class OperationBase(InstanceModelMixin): :type: :obj:`float` """) - def configure(self): - if (self.implementation is None) and (self.function is None): - return - - if (self.interface is not None) and (self.plugin is None) and (self.function is None): - # ("interface" is None for workflow operations, which do not currently use "plugin") - # The default (None) plugin is the execution plugin - execution_plugin.instantiation.configure_operation(self) - else: - # In the future plugins may be able to add their own "configure_operation" hook that - # can validate the configuration and otherwise create specially derived arguments. For - # now, we just send all configuration parameters as arguments without validation. - utils.instantiate_dict(self, self.arguments, - utils.dict_as_arguments(self.configurations)) - - if self.interface is not None: - # Send all interface inputs as extra arguments - # ("interface" is None for workflow operations) - # Note that they will override existing arguments of the same names - utils.instantiate_dict(self, self.arguments, - utils.dict_as_arguments(self.interface.inputs)) - - # Send all inputs as extra arguments - # Note that they will override existing arguments of the same names - utils.instantiate_dict(self, self.arguments, utils.dict_as_arguments(self.inputs)) - - # Check for reserved arguments - from ..orchestrator.decorators import OPERATION_DECORATOR_RESERVED_ARGUMENTS - used_reserved_names = \ - OPERATION_DECORATOR_RESERVED_ARGUMENTS.intersection(self.arguments.keys()) - if used_reserved_names: - context = ConsumptionContext.get_thread_local() - context.validation.report('using reserved arguments in operation "{0}": {1}' - .format( - self.name, - formatting.string_list_as_string(used_reserved_names)), - level=validation.Issue.EXTERNAL) - - @property def as_raw(self): return collections.OrderedDict(( @@ -1992,46 +1531,6 @@ class OperationBase(InstanceModelMixin): ('dependencies', self.dependencies), ('inputs', formatting.as_raw_dict(self.inputs)))) - def validate(self): - # TODO must be associated with either interface or service - utils.validate_dict_values(self.inputs) - utils.validate_dict_values(self.configurations) - utils.validate_dict_values(self.arguments) - - def coerce_values(self, report_issues): - utils.coerce_dict_values(self.inputs, report_issues) - utils.coerce_dict_values(self.configurations, report_issues) - utils.coerce_dict_values(self.arguments, 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 is not None: - console.puts('Plugin: {0}'.format( - context.style.literal(self.plugin.name))) - utils.dump_dict_values(self.configurations, 'Configuration') - if self.function is not None: - console.puts('Function: {0}'.format(context.style.literal(self.function))) - utils.dump_dict_values(self.arguments, 'Arguments') - class ArtifactBase(InstanceModelMixin): """ @@ -2150,27 +1649,3 @@ class ArtifactBase(InstanceModelMixin): ('repository_url', self.repository_url), ('repository_credential', formatting.as_agnostic(self.repository_credential)), ('properties', formatting.as_raw_dict(self.properties)))) - - 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') http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/56841a4d/aria/modeling/service_template.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py index 2246340..f2e1e78 100644 --- a/aria/modeling/service_template.py +++ b/aria/modeling/service_template.py @@ -21,8 +21,6 @@ ARIA modeling service template module from __future__ import absolute_import # so we can import standard 'types' -from datetime import datetime - from sqlalchemy import ( Column, Text, @@ -33,15 +31,10 @@ from sqlalchemy import ( ) 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 ..utils import (collections, formatting) from .mixins import TemplateModelMixin from . import ( relationship, - utils, types as modeling_types ) @@ -331,130 +324,6 @@ class ServiceTemplateBase(TemplateModelMixin): ('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 - now = datetime.now() - service = models.Service(created_at=now, - updated_at=now, - description=deepcopy_with_locators(self.description), - service_template=self) - - # TODO: we want to remove this use of the context - context = ConsumptionContext.get_thread_local() - context.modeling.instance = service - - utils.validate_no_undeclared_inputs(declared_inputs=self.inputs, - supplied_inputs=inputs or {}) - utils.validate_required_inputs_are_supplied(declared_inputs=self.inputs, - supplied_inputs=inputs or {}) - - 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.scaling['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): """ @@ -625,114 +494,6 @@ class NodeTemplateBase(TemplateModelMixin): ('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 - node = models.Node(name=self._next_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) \ - and (node.attributes['tosca_name'].type_name == 'string'): - node.attributes['tosca_name'].value = self.name - if 'tosca_id' in node.attributes \ - and (node.attributes['tosca_id'].type_name == 'string'): - node.attributes['tosca_id'].value = node.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))) - 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') - - @property - def scaling(self): - scaling = {} - - def extract_property(properties, name): - if name in scaling: - return - prop = properties.get(name) - if (prop is not None) and (prop.type_name == 'integer') and (prop.value is not None): - scaling[name] = prop.value - - def extract_properties(properties): - extract_property(properties, 'min_instances') - extract_property(properties, 'max_instances') - extract_property(properties, 'default_instances') - - def default_property(name, value): - if name not in scaling: - scaling[name] = value - - # From our scaling capabilities - for capability_template in self.capability_templates.itervalues(): - if capability_template.type.role == 'scaling': - extract_properties(capability_template.properties) - - # From service scaling policies - for policy_template in self.service_template.policy_templates.itervalues(): - if policy_template.type.role == 'scaling': - if policy_template.is_for_node_template(self.name): - extract_properties(policy_template.properties) - - # Defaults - default_property('min_instances', 0) - default_property('max_instances', 1) - default_property('default_instances', 1) - - # Validate - # pylint: disable=too-many-boolean-expressions - if ((scaling['min_instances'] < 0) or - (scaling['max_instances'] < 0) or - (scaling['default_instances'] < 0) or - (scaling['max_instances'] < scaling['min_instances']) or - (scaling['default_instances'] < scaling['min_instances']) or - (scaling['default_instances'] > scaling['max_instances'])): - context = ConsumptionContext.get_thread_local() - context.validation.report('invalid scaling parameters for node template "{0}": ' - 'min={1}, max={2}, default={3}'.format( - self.name, - scaling['min_instances'], - scaling['max_instances'], - scaling['default_instances']), - level=validation.Issue.BETWEEN_TYPES) - - return scaling - def is_target_node_template_valid(self, target_node_template): """ Checks if ``target_node_template`` matches all our ``target_node_template_constraints``. @@ -876,40 +637,6 @@ class GroupTemplateBase(TemplateModelMixin): ('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)))) - def contains_node_template(self, name): for node_template in self.node_templates: if node_template.name == name: @@ -1022,42 +749,6 @@ class PolicyTemplateBase(TemplateModelMixin): ('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)))) - def is_for_node_template(self, name): for node_template in self.node_templates: if node_template.name == name: @@ -1134,26 +825,6 @@ class SubstitutionTemplateBase(TemplateModelMixin): ('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): """ @@ -1233,59 +904,6 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin): 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): """ @@ -1424,56 +1042,6 @@ class RequirementTemplateBase(TemplateModelMixin): :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.itervalues(): - 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(( @@ -1487,43 +1055,6 @@ class RequirementTemplateBase(TemplateModelMixin): ('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): """ @@ -1606,37 +1137,6 @@ class RelationshipTemplateBase(TemplateModelMixin): ('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): """ @@ -1739,29 +1239,6 @@ class CapabilityTemplateBase(TemplateModelMixin): :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(( @@ -1773,42 +1250,6 @@ class CapabilityTemplateBase(TemplateModelMixin): ('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): """ @@ -1938,34 +1379,6 @@ class InterfaceTemplateBase(TemplateModelMixin): # 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): """ @@ -2124,65 +1537,6 @@ class OperationTemplateBase(TemplateModelMixin): ('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): """ @@ -2295,43 +1649,6 @@ class ArtifactTemplateBase(TemplateModelMixin): ('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): """ @@ -2399,24 +1716,3 @@ class PluginSpecificationBase(TemplateModelMixin): ('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