Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id E155B200CCE for ; Sun, 23 Jul 2017 13:38:59 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id DFA74164584; Sun, 23 Jul 2017 11:38:59 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 34CEF16457A for ; Sun, 23 Jul 2017 13:38:58 +0200 (CEST) Received: (qmail 67554 invoked by uid 500); 23 Jul 2017 11:38:57 -0000 Mailing-List: contact commits-help@ariatosca.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ariatosca.incubator.apache.org Delivered-To: mailing list commits@ariatosca.incubator.apache.org Received: (qmail 67545 invoked by uid 99); 23 Jul 2017 11:38:57 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 23 Jul 2017 11:38:57 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id B610FC024C for ; Sun, 23 Jul 2017 11:38:56 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -4.221 X-Spam-Level: X-Spam-Status: No, score=-4.221 tagged_above=-999 required=6.31 tests=[HK_RANDOM_FROM=0.001, KAM_ASCII_DIVIDERS=0.8, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.001, SPF_PASS=-0.001] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id 8X6XCkRaLS8o for ; Sun, 23 Jul 2017 11:38:51 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id 82E865FB40 for ; Sun, 23 Jul 2017 11:38:49 +0000 (UTC) Received: (qmail 67204 invoked by uid 99); 23 Jul 2017 11:38:48 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 23 Jul 2017 11:38:48 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 966A4DFD82; Sun, 23 Jul 2017 11:38:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mxmrlv@apache.org To: commits@ariatosca.incubator.apache.org Message-Id: <06d740799b774594b74d17096b019b0b@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: incubator-ariatosca git commit: fixed small bugs, moved topolgy to orchestrator [Forced Update!] Date: Sun, 23 Jul 2017 11:38:48 +0000 (UTC) archived-at: Sun, 23 Jul 2017 11:39:00 -0000 Repository: incubator-ariatosca Updated Branches: refs/heads/ARIA-174-Refactor-instantiation-phase 67e7f4d74 -> 609d305d7 (forced update) fixed small bugs, moved topolgy to orchestrator Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/609d305d Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/609d305d Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/609d305d Branch: refs/heads/ARIA-174-Refactor-instantiation-phase Commit: 609d305d75c07af6d3028ba0cb9a2f98cbe87830 Parents: f31e3ea Author: max-orlov Authored: Sun Jul 23 14:33:23 2017 +0300 Committer: max-orlov Committed: Sun Jul 23 14:38:43 2017 +0300 ---------------------------------------------------------------------- aria/core.py | 4 +- aria/modeling/service_instance.py | 14 +- aria/modeling/service_template.py | 3 - aria/orchestrator/topology/__init__.py | 16 + aria/orchestrator/topology/topology.py | 293 +++++++++++++++++ aria/orchestrator/topology/utils.py | 48 +++ aria/parser/consumption/modeling.py | 31 +- aria/parser/reading/__init__.py | 4 +- aria/parser/reading/locator.py | 33 -- aria/parser/topology/__init__.py | 16 - aria/parser/topology/topology.py | 319 ------------------- .../simple_v1_0/modeling/__init__.py | 4 +- tests/instantiation/test_configuration.py | 11 +- 13 files changed, 400 insertions(+), 396 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/core.py ---------------------------------------------------------------------- diff --git a/aria/core.py b/aria/core.py index a12554e..c3fe96f 100644 --- a/aria/core.py +++ b/aria/core.py @@ -17,8 +17,9 @@ ARIA core module. """ +from aria.orchestrator import topology from . import exceptions -from .parser import consumption, topology +from .parser import consumption from .parser.loading.location import UriLocation @@ -67,7 +68,6 @@ 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): - import pydevd; pydevd.settrace('localhost', suspend=False) service_template = self.model_storage.service_template.get(service_template_id) storage_session = self.model_storage._all_api_kwargs['session'] http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/modeling/service_instance.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py index c34ace0..2eaead2 100644 --- a/aria/modeling/service_instance.py +++ b/aria/modeling/service_instance.py @@ -30,6 +30,11 @@ from sqlalchemy import DateTime from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.orderinglist import ordering_list +from . import ( + relationship, + utils, + types as modeling_types +) from .mixins import InstanceModelMixin from ..orchestrator import execution_plugin from ..parser import validation @@ -39,11 +44,6 @@ from ..utils import ( formatting, console ) -from . import ( - relationship, - utils, - types as modeling_types -) class ServiceBase(InstanceModelMixin): @@ -659,7 +659,7 @@ class NodeBase(InstanceModelMixin): if target_node is not None: if requirement_template.relationship_template is not None: - from ..parser import topology + from aria.orchestrator import topology relationship_model = topology.initiator.instantiate(requirement_template.relationship_template) else: relationship_model = models.Relationship() @@ -1945,7 +1945,7 @@ class OperationBase(InstanceModelMixin): """) def configure(self): - from ..parser import topology + from aria.orchestrator import topology if (self.implementation is None) and (self.function is None): return http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/modeling/service_template.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py index 8b26d15..0cbfdb6 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, @@ -35,7 +33,6 @@ 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 http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/orchestrator/topology/__init__.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/topology/__init__.py b/aria/orchestrator/topology/__init__.py new file mode 100644 index 0000000..ae9c900 --- /dev/null +++ b/aria/orchestrator/topology/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .topology import Instantiation, initiator http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/orchestrator/topology/topology.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/topology/topology.py b/aria/orchestrator/topology/topology.py new file mode 100644 index 0000000..abe8cd6 --- /dev/null +++ b/aria/orchestrator/topology/topology.py @@ -0,0 +1,293 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from datetime import datetime +from functools import partial +from contextlib import contextmanager + + +from ...modeling import ( + utils as modeling_utils, + models +) +from ...parser import validation, consumption +from . import utils + + +class Instantiation(object): + + def __init__(self, context): + self._context = context or consumption.ConsumptionContext() + self._initiators = { + 'meta_data': self._instantiate_metadata, + 'node_template': self._instantiate_node, + 'substitution_template': self._instantiate_substitution, + 'workflow_templates': self._instantiate_operation, + 'operation_templates': self._instantiate_operation, + 'interface_templates': self._instantiate_interface, + 'artifact_templates': self._instantiate_artifact, + 'capability_templates': self._instantiate_capability, + 'group_templates': self._instantiate_group, + 'policy_templates': self._instantiate_policy, + 'relationship_template': self._instantiate_relationship, + + # Parameter-Based instantiations + 'argument': partial(self._instantiate_parameter, model_cls=models.Argument), + + 'inputs': partial(self._instantiate_parameter, model_cls=models.Input), + 'outputs': partial(self._instantiate_parameter, model_cls=models.Output), + 'properties': partial(self._instantiate_parameter, model_cls=models.Property), + 'attributes': partial(self._instantiate_parameter, model_cls=models.Attribute), + 'configurations': partial(self._instantiate_parameter, model_cls=models.Configuration), + + } + self._model_storage = None + + @property + def _has_model_storage(self): + return self._model_storage is not None + + @contextmanager + def push_model_storage(self, model_storage): + original_model_storage = self._model_storage + self._model_storage = model_storage + yield self + self._model_storage = original_model_storage + + def instantiate_service(self, service_template, inputs=None): + + now = datetime.now() + service = models.Service( + created_at=now, + updated_at=now, + description=utils.deepcopy_with_locators(service_template.description), + service_template=service_template + ) + + self._context.modeling.instance = service + + service.inputs = modeling_utils.merge_parameter_values(inputs, service_template.inputs) + # TODO: now that we have inputs, we should scan properties and inputs and evaluate functions + + for plugin_specification in service_template.plugin_specifications.itervalues(): + if plugin_specification.enabled: + if plugin_specification.resolve(self._model_storage): + plugin = plugin_specification.plugin + service.plugins[plugin.name] = plugin + else: + self._context.validation.report('specified plugin not found: {0}'.format( + plugin_specification.name), level=validation.Issue.EXTERNAL) + + service.meta_data = self.instantiate(service_template.meta_data) + + for node_template in service_template.node_templates.itervalues(): + for _ in range(node_template.scaling['default_instances']): + node = self.instantiate(node_template) + service.nodes[node.name] = node + + service.groups = self.instantiate(service_template.group_templates) + service.policies = self.instantiate(service_template.policy_templates) + service.workflows = self.instantiate(service_template.workflow_templates) + + if service_template.substitution_template is not None: + service.substitution = self.instantiate(service_template.substitution_template) + service.outputs = self.instantiate(service_template.outputs) + + return service + + def instantiate(self, source_template): + if isinstance(source_template, (dict, list)): + initiator = self._initiators[source_template._sa_adapter.attr.key] + if isinstance(source_template, dict): + dict_ = {} + for name, value in source_template.iteritems(): + value = initiator(value) + if value is not None: + dict_[name] = value + return dict_ + elif isinstance(source_template, list): + list_ = [] + for value in source_template: + value = initiator(value) + if value is not None: + list_.append(value) + return list_ + else: + return self._initiators[source_template.__tablename__](source_template) + + @staticmethod + def _instantiate_artifact(artifact_template): + artifact = models.Artifact( + name=artifact_template.name, + type=artifact_template.type, + description=utils.deepcopy_with_locators(artifact_template.description), + source_path=artifact_template.source_path, + target_path=artifact_template.target_path, + repository_url=artifact_template.repository_url, + repository_credential=artifact_template.repository_credential, + artifact_template=artifact_template) + return artifact + + @staticmethod + def _instantiate_capability(capability_template): + capability = models.Capability(name=capability_template.name, + type=capability_template.type, + min_occurrences=capability_template.min_occurrences, + max_occurrences=capability_template.max_occurrences, + occurrences=0, + capability_template=capability_template) + return capability + + def _instantiate_group(self, group_template): + group = models.Group(name=group_template.name, + type=group_template.type, + description=utils.deepcopy_with_locators(group_template.description), + group_template=group_template) + group.properties = self.instantiate(group_template.properties) + group.interfaces = self.instantiate(group_template.interface_templates) + if group_template.node_templates: + for node_template in group_template.node_templates: + group.nodes += node_template.nodes + return group + + def _instantiate_interface(self, interface_template): + interface = models.Interface( + name=interface_template.name, + type=interface_template.type, + description=utils.deepcopy_with_locators(interface_template.description), + interface_template=interface_template) + interface.inputs = self.instantiate(interface_template.inputs) + interface.operations = self.instantiate(interface_template.operation_templates) + return interface + + def _instantiate_node(self, node_template): + node = models.Node( + name=node_template._next_name, + type=node_template.type, + description=utils.deepcopy_with_locators(node_template.description), + state=models.Node.INITIAL, + node_template=node_template + ) + node.properties = self.instantiate(node_template.properties) + node.attributes = self.instantiate(node_template.attributes) + node.interfaces = self.instantiate(node_template.interface_templates) + node.artifacts = self.instantiate(node_template.artifact_templates) + node.capabilities = self.instantiate(node_template.capability_templates) + + # Default attributes + if ('tosca_name' in node.attributes) \ + and (node.attributes['tosca_name'].type_name == 'string'): + node.attributes['tosca_name'].value = node_template.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 _instantiate_policy(self, policy_template): + policy = models.Policy( + name=policy_template.name, + type=policy_template.type, + description=utils.deepcopy_with_locators(policy_template.description), + policy_template=policy_template) + policy.properties = self.instantiate(policy_template.properties) + if policy_template.node_templates: + for node_template in policy_template.node_templates: + policy.nodes += node_template.nodes + if policy_template.group_templates: + for group_template in policy_template.group_templates: + policy.groups += group_template.groups + return policy + + @staticmethod + def _instantiate_parameter(parameter_template, model_cls): + return model_cls( + name=parameter_template.name, # pylint: disable=unexpected-keyword-arg + type_name=parameter_template.type_name, + _value=parameter_template._value, + description=parameter_template.description + ) + + @staticmethod + def _instantiate_substitution(substitution_template): + substitution = models.Substitution(node_type=substitution_template.node_type, + substitution_template=substitution_template) + return substitution + + @staticmethod + def _instantiate_metadata(metadata_template): + return models.Metadata(name=metadata_template.name, value=metadata_template.value) + + def _instantiate_substitution_mapping(self, substitution_mapping): + if substitution_mapping.capability_template is not None: + node_template = substitution_mapping.capability_template.node_template + else: + node_template = substitution_mapping.requirement_template.node_template + nodes = node_template.nodes + if len(nodes) == 0: + self._context.validation.report( + 'mapping "{0}" refers to node template "{1}" but there are no node instances'. + format(substitution_mapping.mapped_name, + substitution_mapping.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 substitution_mapping.capability_template: + for a_capability in node.capabilities.itervalues(): + if a_capability.capability_template.name == \ + substitution_mapping.capability_template.name: + capability = a_capability + return models.SubstitutionMapping( + name=substitution_mapping.name, + capability=capability, + requirement_template=substitution_mapping.requirement_template, + node=node) + + def _instantiate_relationship(self, relationship_template): + relationship_model = models.Relationship(name=relationship_template.name, + type=relationship_template.type, + relationship_template=relationship_template) + relationship_model.properties = self.instantiate(relationship_template.properties) + relationship_model.interfaces = self.instantiate(relationship_template.interface_templates) + return relationship_model + + def _instantiate_operation(self, operation_template): + plugin = None + if (operation_template.plugin_specification is not None and + operation_template.plugin_specification.enabled): + plugin = operation_template.plugin_specification.plugin + + operation = models.Operation( + name=operation_template.name, + description=utils.deepcopy_with_locators(operation_template.description), + relationship_edge=operation_template.relationship_edge, + implementation=operation_template.implementation, + dependencies=operation_template.dependencies, + executor=operation_template.executor, + plugin=plugin, + function=operation_template.function, + max_attempts=operation_template.max_attempts, + retry_interval=operation_template.retry_interval, + operation_template=operation_template) + + operation.inputs = self.instantiate(operation_template.inputs) + operation.configurations = self.instantiate(operation_template.configurations) + + return operation + + +initiator = Instantiation(consumption.ConsumptionContext.get_thread_local()) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/orchestrator/topology/utils.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/topology/utils.py b/aria/orchestrator/topology/utils.py new file mode 100644 index 0000000..ec74391 --- /dev/null +++ b/aria/orchestrator/topology/utils.py @@ -0,0 +1,48 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from copy import deepcopy + + +def deepcopy_with_locators(value): + """ + Like :func:`deepcopy`, but also copies over locators. + """ + + res = deepcopy(value) + copy_locators(res, value) + return res + + +def copy_locators(target, source): + """ + Copies over ``_locator`` for all elements, recursively. + + Assumes that target and source have exactly the same list/dict structure. + """ + + locator = getattr(source, '_locator', None) + if locator is not None: + try: + setattr(target, '_locator', locator) + except AttributeError: + pass + + if isinstance(target, list) and isinstance(source, list): + for i, _ in enumerate(target): + copy_locators(target[i], source[i]) + elif isinstance(target, dict) and isinstance(source, dict): + for k, v in target.items(): + copy_locators(v, source[k]) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/parser/consumption/modeling.py ---------------------------------------------------------------------- diff --git a/aria/parser/consumption/modeling.py b/aria/parser/consumption/modeling.py index 8c46abf..e142327 100644 --- a/aria/parser/consumption/modeling.py +++ b/aria/parser/consumption/modeling.py @@ -13,8 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ...utils.formatting import json_dumps, yaml_dumps from .consumer import Consumer, ConsumerChain +from ...utils.formatting import json_dumps, yaml_dumps +from ... import exceptions class DeriveServiceTemplate(Consumer): @@ -105,11 +106,29 @@ class InstantiateServiceInstance(Consumer): self.context.validation.report('InstantiateServiceInstance consumer: missing service ' 'template') return - from .. import topology - topology.initiator.instantiate_service(self.context.modeling.template, - inputs=dict(self.context.modeling.inputs)) - # TODO: fix this, it looks bad. - self.context.modeling.instance = self.context.modeling.template.services[None] + from aria.orchestrator import topology + + self.context.modeling.instance = topology.Instantiation(self.context).instantiate_service( + self.context.modeling.template, + inputs=dict(self.context.modeling.inputs) + ) + + ConsumerChain( + self.context, + ( + CoerceServiceInstanceValues, + ValidateServiceInstance, + SatisfyRequirements, + CoerceServiceInstanceValues, + ValidateCapabilities, + FindHosts, + ConfigureOperations, + CoerceServiceInstanceValues + )).consume() + + if self.context.validation.dump_issues(): + raise exceptions.InstantiationError('Failed to instantiate service template `{0}`' + .format(self.context.modeling.template.name)) class CoerceServiceInstanceValues(Consumer): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/parser/reading/__init__.py ---------------------------------------------------------------------- diff --git a/aria/parser/reading/__init__.py b/aria/parser/reading/__init__.py index 065ca56..9fab5df 100644 --- a/aria/parser/reading/__init__.py +++ b/aria/parser/reading/__init__.py @@ -36,7 +36,7 @@ Reading package. from .raw import RawReader from .reader import Reader from .yaml import YamlReader -from .locator import (Locator, deepcopy_with_locators, copy_locators) +from .locator import Locator from .json import JsonReader from .jinja import JinjaReader from .context import ReadingContext @@ -57,8 +57,6 @@ __all__ = ( 'ReadingContext', 'RawReader', 'Locator', - 'deepcopy_with_locators', - 'copy_locators', 'YamlReader', 'JsonReader', 'JinjaReader') http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/parser/reading/locator.py ---------------------------------------------------------------------- diff --git a/aria/parser/reading/locator.py b/aria/parser/reading/locator.py index 965164d..8bbb178 100644 --- a/aria/parser/reading/locator.py +++ b/aria/parser/reading/locator.py @@ -10,9 +10,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from copy import deepcopy - - from ...utils.console import puts, Colored, indent @@ -122,33 +119,3 @@ class Locator(object): return '"%s":%d:%d' % (self.location, self.line, self.column) -def deepcopy_with_locators(value): - """ - Like :func:`deepcopy`, but also copies over locators. - """ - - res = deepcopy(value) - copy_locators(res, value) - return res - - -def copy_locators(target, source): - """ - Copies over ``_locator`` for all elements, recursively. - - Assumes that target and source have exactly the same list/dict structure. - """ - - locator = getattr(source, '_locator', None) - if locator is not None: - try: - setattr(target, '_locator', locator) - except AttributeError: - pass - - if isinstance(target, list) and isinstance(source, list): - for i, _ in enumerate(target): - copy_locators(target[i], source[i]) - elif isinstance(target, dict) and isinstance(source, dict): - for k, v in target.items(): - copy_locators(v, source[k]) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/parser/topology/__init__.py ---------------------------------------------------------------------- diff --git a/aria/parser/topology/__init__.py b/aria/parser/topology/__init__.py deleted file mode 100644 index 7bc09e7..0000000 --- a/aria/parser/topology/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .topology import initiator http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/aria/parser/topology/topology.py ---------------------------------------------------------------------- diff --git a/aria/parser/topology/topology.py b/aria/parser/topology/topology.py deleted file mode 100644 index d91a96f..0000000 --- a/aria/parser/topology/topology.py +++ /dev/null @@ -1,319 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from contextlib import contextmanager -from datetime import datetime -from functools import partial - -from aria import exceptions - -from ... modeling import ( - utils, - models -) -from .. import ( - reading, - consumption, - validation, -) - - -class _Instantiation(object): - - def __init__(self): - self._initiators = { - 'meta_data': self._instantiate_metadata, - 'node_template': self._instantiate_node, - 'substitution_template': self._instantiate_substitution, - 'workflow_templates': self._instantiate_operation, - 'operation_templates': self._instantiate_operation, - 'interface_templates': self._instantiate_interface, - 'artifact_templates': self._instantiate_artifact, - 'capability_templates': self._instantiate_capability, - 'group_templates': self._instantiate_group, - 'policy_templates': self._instantiate_policy, - 'relationship_template': self._instantiate_relationship, - - # Parameter-Based instantiations - 'argument': partial(self._instantiate_parameter, model_cls=models.Argument), - - 'inputs': partial(self._instantiate_parameter, model_cls=models.Input), - 'outputs': partial(self._instantiate_parameter, model_cls=models.Output), - 'properties': partial(self._instantiate_parameter, model_cls=models.Property), - 'attributes': partial(self._instantiate_parameter, model_cls=models.Attribute), - 'configurations': partial(self._instantiate_parameter, model_cls=models.Configuration), - - } - self._model_storage = None - - @property - def _has_model_storage(self): - return self._model_storage is not None - - @contextmanager - def push_model_storage(self, model_storage): - original_model_storage = self._model_storage - self._model_storage = model_storage - yield self - self._model_storage = original_model_storage - - def instantiate_service(self, service_template, inputs=None): - - # creating an empty ConsumptionContext, initiating a threadlocal context - context = consumption.ConsumptionContext(set_thread_local=True) - - now = datetime.now() - service = models.Service( - created_at=now, - updated_at=now, - description=reading.deepcopy_with_locators(service_template.description), - service_template=service_template - ) - - context.modeling.instance = service - - service.inputs = utils.merge_parameter_values(inputs, service_template.inputs) - # TODO: now that we have inputs, we should scan properties and inputs and evaluate functions - - for plugin_specification in service_template.plugin_specifications.itervalues(): - if plugin_specification.enabled: - if plugin_specification.resolve(self._model_storage): - plugin = plugin_specification.plugin - service.plugins[plugin.name] = plugin - else: - context = consumption.ConsumptionContext.get_thread_local() - context.validation.report('specified plugin not found: {0}'.format( - plugin_specification.name), level=validation.Issue.EXTERNAL) - - service.meta_data = self.instantiate(service_template.meta_data) - - for node_template in service_template.node_templates.itervalues(): - for _ in range(node_template.scaling['default_instances']): - node = self.instantiate(node_template) - service.nodes[node.name] = node - - service.groups = self.instantiate(service_template.group_templates) - service.policies = self.instantiate(service_template.policy_templates) - service.workflows = self.instantiate(service_template.workflow_templates) - - if service_template.substitution_template is not None: - service.substitution = self.instantiate(service_template.substitution_template) - service.outputs = self.instantiate(service_template.outputs) - - 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(): - raise exceptions.InstantiationError('Failed to instantiate service template `{0}`' - .format(service_template.name)) - - return service - - def instantiate(self, source_template): - if isinstance(source_template, (dict, list)): - initiator = self._initiators[source_template._sa_adapter.attr.key] - if isinstance(source_template, dict): - dict_ = utils.OrderedDict() - for name, value in source_template.iteritems(): - value = initiator(value) - if value is not None: - dict_[name] = value - return dict_ - elif isinstance(source_template, list): - list_ = [] - for value in source_template: - value = initiator(value) - if value is not None: - list_.append(value) - return list_ - else: - return self._initiators[source_template.__tablename__](source_template) - - @staticmethod - def _instantiate_artifact(artifact_template): - artifact = models.Artifact( - name=artifact_template.name, - type=artifact_template.type, - description=reading.deepcopy_with_locators(artifact_template.description), - source_path=artifact_template.source_path, - target_path=artifact_template.target_path, - repository_url=artifact_template.repository_url, - repository_credential=artifact_template.repository_credential, - artifact_template=artifact_template) - return artifact - - @staticmethod - def _instantiate_capability(capability_template): - capability = models.Capability(name=capability_template.name, - type=capability_template.type, - min_occurrences=capability_template.min_occurrences, - max_occurrences=capability_template.max_occurrences, - occurrences=0, - capability_template=capability_template) - return capability - - def _instantiate_group(self, group_template): - group = models.Group(name=group_template.name, - type=group_template.type, - description=reading.deepcopy_with_locators(group_template.description), - group_template=group_template) - group.properties = self.instantiate(group_template.properties) - group.interfaces = self.instantiate(group_template.interface_templates) - if group_template.node_templates: - for node_template in group_template.node_templates: - group.nodes += node_template.nodes - return group - - def _instantiate_interface(self, interface_template): - interface = models.Interface( - name=interface_template.name, - type=interface_template.type, - description=reading.deepcopy_with_locators(interface_template.description), - interface_template=interface_template) - interface.inputs = self.instantiate(interface_template.inputs) - interface.operations = self.instantiate(interface_template.operation_templates) - return interface - - def _instantiate_node(self, node_template): - node = models.Node( - name=node_template._next_name, - type=node_template.type, - description=reading.deepcopy_with_locators(node_template.description), - state=models.Node.INITIAL, - node_template=node_template - ) - node.properties = self.instantiate(node_template.properties) - node.attributes = self.instantiate(node_template.attributes) - node.interfaces = self.instantiate(node_template.interface_templates) - node.artifacts = self.instantiate(node_template.artifact_templates) - node.capabilities = self.instantiate(node_template.capability_templates) - - # Default attributes - if ('tosca_name' in node.attributes) \ - and (node.attributes['tosca_name'].type_name == 'string'): - node.attributes['tosca_name'].value = node_template.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 _instantiate_policy(self, policy_template): - policy = models.Policy( - name=policy_template.name, - type=policy_template.type, - description=reading.deepcopy_with_locators(policy_template.description), - policy_template=policy_template) - policy.properties = self.instantiate(policy_template.properties) - if policy_template.node_templates: - for node_template in policy_template.node_templates: - policy.nodes += node_template.nodes - if policy_template.group_templates: - for group_template in policy_template.group_templates: - policy.groups += group_template.groups - return policy - - @staticmethod - def _instantiate_parameter(parameter_template, model_cls): - return model_cls( - name=parameter_template.name, # pylint: disable=unexpected-keyword-arg - type_name=parameter_template.type_name, - _value=parameter_template._value, - description=parameter_template.description - ) - - @staticmethod - def _instantiate_substitution(substitution_template): - substitution = models.Substitution(node_type=substitution_template.node_type, - substitution_template=substitution_template) - return substitution - - @staticmethod - def _instantiate_metadata(metadata_template): - return models.Metadata(name=metadata_template.name, value=metadata_template.value) - - @staticmethod - def _instantiate_substitution_mapping(substitution_mapping): - context = consumption.ConsumptionContext.get_thread_local() - if substitution_mapping.capability_template is not None: - node_template = substitution_mapping.capability_template.node_template - else: - node_template = substitution_mapping.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(substitution_mapping.mapped_name, - substitution_mapping.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 substitution_mapping.capability_template: - for a_capability in node.capabilities.itervalues(): - if a_capability.capability_template.name == \ - substitution_mapping.capability_template.name: - capability = a_capability - return models.SubstitutionMapping( - name=substitution_mapping.name, - capability=capability, - requirement_template=substitution_mapping.requirement_template, - node=node) - - def _instantiate_relationship(self, relationship_template): - relationship_model = models.Relationship(name=relationship_template.name, - type=relationship_template.type, - relationship_template=relationship_template) - relationship_model.properties = self.instantiate(relationship_template.properties) - relationship_model.interfaces = self.instantiate(relationship_template.interface_templates) - return relationship_model - - def _instantiate_operation(self, operation_template): - plugin = None - if (operation_template.plugin_specification is not None and - operation_template.plugin_specification.enabled): - plugin = operation_template.plugin_specification.plugin - - operation = models.Operation( - name=operation_template.name, - description=reading.deepcopy_with_locators(operation_template.description), - relationship_edge=operation_template.relationship_edge, - implementation=operation_template.implementation, - dependencies=operation_template.dependencies, - executor=operation_template.executor, - plugin=plugin, - function=operation_template.function, - max_attempts=operation_template.max_attempts, - retry_interval=operation_template.retry_interval, - operation_template=operation_template) - - operation.inputs = self.instantiate(operation_template.inputs) - operation.configurations = self.instantiate(operation_template.configurations) - - return operation - - -initiator = _Instantiation() http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py index 4d8e1db..4704f1b 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py @@ -515,8 +515,8 @@ def create_plugin_specification_model(context, policy): def create_workflow_operation_template_model(context, service_template, policy): - model = OperationTemplate(name=policy._name, - service_template=service_template) + model = OperationTemplate(name=policy._name) + service_template.workflow_templates[model.name] = model if policy.description: model.description = policy.description.value http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/609d305d/tests/instantiation/test_configuration.py ---------------------------------------------------------------------- diff --git a/tests/instantiation/test_configuration.py b/tests/instantiation/test_configuration.py index 6ac0c9c..659e334 100644 --- a/tests/instantiation/test_configuration.py +++ b/tests/instantiation/test_configuration.py @@ -165,8 +165,9 @@ def test_remote(service): def test_reserved_arguments(broken_service_issues): - assert len(broken_service_issues) == 1 - message = broken_service_issues[0].message - assert message.startswith('using reserved arguments in operation "operation":') - assert '"ctx"' in message - assert '"toolbelt"' in message + assert len(broken_service_issues) == 2 + assert any( + all([issue.message.startswith('using reserved arguments in operation "operation":'), + 'ctx' in issue.message, + 'toolbelt' in issue.message]) + for issue in broken_service_issues)