Repository: incubator-ariatosca Updated Branches: refs/heads/ARIA-174-Refactor-instantiation-phase 4b6e51b0a -> 901078467 (forced update)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/aria/parser/consumption/modeling.py ---------------------------------------------------------------------- diff --git a/aria/parser/consumption/modeling.py b/aria/parser/consumption/modeling.py index 44027b9..0afd555 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): @@ -42,7 +43,7 @@ class CoerceServiceTemplateValues(Consumer): """ def consume(self): - self.context.modeling.template.coerce_values(True) + self.topology.coerce(self.context.modeling.template, report_issues=True) class ValidateServiceTemplate(Consumer): @@ -51,7 +52,7 @@ class ValidateServiceTemplate(Consumer): """ def consume(self): - self.context.modeling.template.validate() + self.topology.validate(self.context.modeling.template) class ServiceTemplate(ConsumerChain): @@ -74,7 +75,7 @@ class ServiceTemplate(ConsumerChain): raw = self.context.modeling.template_as_raw self.context.write(json_dumps(raw, indent=indent)) else: - self.context.modeling.template.dump() + self.topology.dump(self.context.modeling.template) class Types(Consumer): @@ -92,7 +93,7 @@ class Types(Consumer): raw = self.context.modeling.types_as_raw self.context.write(json_dumps(raw, indent=indent)) else: - self.context.modeling.template.dump_types() + self.topology.dump_types(self.context, self.context.modeling.template) class InstantiateServiceInstance(Consumer): @@ -105,9 +106,26 @@ class InstantiateServiceInstance(Consumer): self.context.validation.report('InstantiateServiceInstance consumer: missing service ' 'template') return - - self.context.modeling.template.instantiate(None, None, - inputs=dict(self.context.modeling.inputs)) + self.context.modeling.instance = self.topology.instantiate( + 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): @@ -116,7 +134,7 @@ class CoerceServiceInstanceValues(Consumer): """ def consume(self): - self.context.modeling.instance.coerce_values(True) + self.topology.coerce(self.context.modeling.instance, report_issues=True) class ValidateServiceInstance(Consumer): @@ -125,7 +143,7 @@ class ValidateServiceInstance(Consumer): """ def consume(self): - self.context.modeling.instance.validate() + self.topology.validate(self.context.modeling.instance) class SatisfyRequirements(Consumer): @@ -134,7 +152,7 @@ class SatisfyRequirements(Consumer): """ def consume(self): - self.context.modeling.instance.satisfy_requirements() + self.topology.satisfy_requirements(self.context.modeling.instance) class ValidateCapabilities(Consumer): @@ -143,7 +161,7 @@ class ValidateCapabilities(Consumer): """ def consume(self): - self.context.modeling.instance.validate_capabilities() + self.topology.validate_capabilities(self.context.modeling.instance) class FindHosts(Consumer): @@ -152,7 +170,7 @@ class FindHosts(Consumer): """ def consume(self): - self.context.modeling.instance.find_hosts() + self.topology.find_hosts(self.context.modeling.instance) class ConfigureOperations(Consumer): @@ -161,7 +179,7 @@ class ConfigureOperations(Consumer): """ def consume(self): - self.context.modeling.instance.configure_operations() + self.topology.configure_operations(self.context.modeling.instance) class ServiceInstance(ConsumerChain): @@ -193,4 +211,5 @@ class ServiceInstance(ConsumerChain): raw = self.context.modeling.instance_as_raw self.context.write(json_dumps(raw, indent=indent)) else: - self.context.modeling.instance.dump() + str_rep = self.topology.dump(self.context.modeling.instance) + self.context.write(str_rep) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/aria/parser/consumption/style.py ---------------------------------------------------------------------- diff --git a/aria/parser/consumption/style.py b/aria/parser/consumption/style.py deleted file mode 100644 index 72892b9..0000000 --- a/aria/parser/consumption/style.py +++ /dev/null @@ -1,50 +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 ...utils.console import Colored, indent -from ...utils.formatting import safe_repr - - -class Style(object): - def __init__(self, indentation=2): - self.indentation = indentation - - @property - def indent(self): - return indent(self.indentation) - - @staticmethod - def section(value): - return Colored.cyan(value, bold=True) - - @staticmethod - def type(value): - return Colored.blue(value, bold=True) - - @staticmethod - def node(value): - return Colored.red(value, bold=True) - - @staticmethod - def property(value): - return Colored.magenta(value, bold=True) - - @staticmethod - def literal(value): - return Colored.magenta(safe_repr(value)) - - @staticmethod - def meta(value): - return Colored.green(value) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/aria/parser/modeling/context.py ---------------------------------------------------------------------- diff --git a/aria/parser/modeling/context.py b/aria/parser/modeling/context.py index 3d75617..d8a1f7a 100644 --- a/aria/parser/modeling/context.py +++ b/aria/parser/modeling/context.py @@ -19,6 +19,10 @@ from ...utils.collections import StrictDict, prune from ...utils.uuid import generate_uuid +# See: http://www.faqs.org/rfcs/rfc1035.html +ID_MAX_LENGTH = 63 + + class IdType(object): LOCAL_SERIAL = 0 """ @@ -61,7 +65,7 @@ class ModelingContext(object): #self.id_type = IdType.LOCAL_SERIAL #self.id_type = IdType.LOCAL_RANDOM self.id_type = IdType.UNIVERSAL_RANDOM - self.id_max_length = 63 # See: http://www.faqs.org/rfcs/rfc1035.html + self.id_max_length = ID_MAX_LENGTH self.inputs = StrictDict(key_class=basestring) self._serial_id_counter = itertools.count(1) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/aria/parser/reading/__init__.py ---------------------------------------------------------------------- diff --git a/aria/parser/reading/__init__.py b/aria/parser/reading/__init__.py index 065ca56..c110585 100644 --- a/aria/parser/reading/__init__.py +++ b/aria/parser/reading/__init__.py @@ -24,8 +24,6 @@ Reading package. JinjaReader JsonReader Locator - deepcopy_with_locators - copy_locators RawReader Reader ReaderSource @@ -36,7 +34,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 +55,6 @@ __all__ = ( 'ReadingContext', 'RawReader', 'Locator', - 'deepcopy_with_locators', - 'copy_locators', 'YamlReader', 'JsonReader', 'JinjaReader') http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/aria/parser/reading/locator.py ---------------------------------------------------------------------- diff --git a/aria/parser/reading/locator.py b/aria/parser/reading/locator.py index 965164d..57b4d50 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 @@ -120,35 +117,3 @@ class Locator(object): def __str__(self): # Should be in same format as Issue.locator_as_str 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/90107846/aria/parser/validation/context.py ---------------------------------------------------------------------- diff --git a/aria/parser/validation/context.py b/aria/parser/validation/context.py index ef641bd..a245518 100644 --- a/aria/parser/validation/context.py +++ b/aria/parser/validation/context.py @@ -13,15 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .issue import Issue -from ...utils.threading import LockedList -from ...utils.collections import FrozenList -from ...utils.exceptions import print_exception -from ...utils.console import puts, Colored, indent -from ...utils.formatting import as_raw +from . import issue -class ValidationContext(object): +class ValidationContext(issue.Reporter): """ Validation context. @@ -35,53 +30,7 @@ class ValidationContext(object): :vartype max_level: int """ - def __init__(self): + def __init__(self, *args, **kwargs): + super(ValidationContext, self).__init__(*args, **kwargs) self.allow_unknown_fields = False self.allow_primitive_coersion = False - self.max_level = Issue.ALL - - self._issues = LockedList() - - def report(self, message=None, exception=None, location=None, line=None, - column=None, locator=None, snippet=None, level=Issue.PLATFORM, issue=None): - if issue is None: - issue = Issue(message, exception, location, line, column, locator, snippet, level) - - # Avoid duplicate issues - with self._issues: - for i in self._issues: - if str(i) == str(issue): - return - - self._issues.append(issue) - - @property - def has_issues(self): - return len(self._issues) > 0 - - @property - def issues(self): - issues = [i for i in self._issues if i.level <= self.max_level] - issues.sort(key=lambda i: (i.level, i.location, i.line, i.column, i.message)) - return FrozenList(issues) - - @property - def issues_as_raw(self): - return [as_raw(i) for i in self.issues] - - def dump_issues(self): - issues = self.issues - if issues: - puts(Colored.blue('Validation issues:', bold=True)) - with indent(2): - for issue in issues: - puts(Colored.blue(issue.heading_as_str)) - details = issue.details_as_str - if details: - with indent(3): - puts(details) - if issue.exception is not None: - with indent(3): - print_exception(issue.exception) - return True - return False http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/aria/parser/validation/issue.py ---------------------------------------------------------------------- diff --git a/aria/parser/validation/issue.py b/aria/parser/validation/issue.py index db8065d..11ea7f9 100644 --- a/aria/parser/validation/issue.py +++ b/aria/parser/validation/issue.py @@ -15,8 +15,14 @@ from __future__ import absolute_import # so we can import standard 'collections' -from ...utils.collections import OrderedDict -from ...utils.type import full_type_name +from ...utils import ( + collections, + type, + threading, + exceptions, + console, + formatting +) class Issue(object): @@ -82,14 +88,14 @@ class Issue(object): @property def as_raw(self): - return OrderedDict(( + return collections.OrderedDict(( ('level', self.level), ('message', self.message), ('location', self.location), ('line', self.line), ('column', self.column), ('snippet', self.snippet), - ('exception', full_type_name(self.exception) if self.exception else None))) + ('exception', type.full_type_name(self.exception) if self.exception else None))) @property def locator_as_str(self): @@ -124,3 +130,61 @@ class Issue(object): if details: heading_str += ', ' + details return heading_str + + +class Reporter(object): + + Issue = Issue + + def __init__(self, *args, **kwargs): + super(Reporter, self).__init__(*args, **kwargs) + self._issues = threading.LockedList() + self.max_level = self.Issue.ALL + + def report(self, message=None, exception=None, location=None, line=None, + column=None, locator=None, snippet=None, level=Issue.PLATFORM, issue=None): + if issue is None: + issue = self.Issue(message, exception, location, line, column, locator, snippet, level) + + # Avoid duplicate issues + with self._issues: + for i in self._issues: + if str(i) == str(issue): + return + + self._issues.append(issue) + + @property + def has_issues(self): + return len(self._issues) > 0 + + @property + def issues(self): + issues = [i for i in self._issues if i.level <= self.max_level] + issues.sort(key=lambda i: (i.level, i.location, i.line, i.column, i.message)) + return collections.FrozenList(issues) + + @property + def issues_as_raw(self): + return [formatting.as_raw(i) for i in self.issues] + + def extend_issues(self, *issues): + with self._issues: + self._issues.extend(*issues) + + def dump_issues(self): + issues = self.issues + if issues: + console.puts(console.Colored.blue('Validation issues:', bold=True)) + with console.indent(2): + for issue in issues: + console.puts(console.Colored.blue(issue.heading_as_str)) + details = issue.details_as_str + if details: + with console.indent(3): + console.puts(details) + if issue.exception is not None: + with console.indent(3): + exceptions.print_exception(issue.exception) + return True + return False http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/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/90107846/tests/instantiation/test_configuration.py ---------------------------------------------------------------------- diff --git a/tests/instantiation/test_configuration.py b/tests/instantiation/test_configuration.py index 6ac0c9c..a41f0a8 100644 --- a/tests/instantiation/test_configuration.py +++ b/tests/instantiation/test_configuration.py @@ -165,8 +165,11 @@ 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 + ) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/tests/parser/service_templates.py ---------------------------------------------------------------------- diff --git a/tests/parser/service_templates.py b/tests/parser/service_templates.py index 13712df..9338897 100644 --- a/tests/parser/service_templates.py +++ b/tests/parser/service_templates.py @@ -49,11 +49,21 @@ def consume_use_case(use_case_name, consumer_class_name='instance', cache=True): def consume_node_cellar(consumer_class_name='instance', cache=True): + consume_test_case( + get_service_template_uri('tosca-simple-1.0', 'node-cellar', 'node-cellar.yaml'), + consumer_class_name=consumer_class_name, + inputs_uri=get_service_template_uri('tosca-simple-1.0', 'node-cellar', 'inputs.yaml'), + cache=cache + + ) + + +def consume_test_case(uri, inputs_uri=None, consumer_class_name='instance', cache=True): cachedmethod.ENABLED = cache - uri = get_service_template_uri('tosca-simple-1.0', 'node-cellar', 'node-cellar.yaml') + uri = get_service_template_uri(uri) context = create_context(uri) - context.args.append('--inputs=' + get_service_template_uri('tosca-simple-1.0', 'node-cellar', - 'inputs.yaml')) + if inputs_uri: + context.args.append('--inputs=' + get_service_template_uri(inputs_uri)) consumer, dumper = create_consumer(context, consumer_class_name) consumer.consume() context.validation.dump_issues() http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/tests/parser/test_reqs_caps.py ---------------------------------------------------------------------- diff --git a/tests/parser/test_reqs_caps.py b/tests/parser/test_reqs_caps.py new file mode 100644 index 0000000..0af2487 --- /dev/null +++ b/tests/parser/test_reqs_caps.py @@ -0,0 +1,29 @@ +# 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 .service_templates import consume_test_case +from ..helpers import get_service_template_uri + + +def test_satisfy_capability_type(): + consume_reqs_caps_template('instance') + + +def consume_reqs_caps_template(consumer_class_name, cache=True): + consume_test_case( + get_service_template_uri('tosca-simple-1.0', 'reqs_caps', 'reqs_caps1.yaml'), + consumer_class_name=consumer_class_name, + cache=cache + ) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/tests/resources/service-templates/tosca-simple-1.0/reqs_caps/reqs_caps1.yaml ---------------------------------------------------------------------- diff --git a/tests/resources/service-templates/tosca-simple-1.0/reqs_caps/reqs_caps1.yaml b/tests/resources/service-templates/tosca-simple-1.0/reqs_caps/reqs_caps1.yaml new file mode 100644 index 0000000..466a78e --- /dev/null +++ b/tests/resources/service-templates/tosca-simple-1.0/reqs_caps/reqs_caps1.yaml @@ -0,0 +1,40 @@ +# 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. + +tosca_definitions_version: tosca_simple_yaml_1_0 + +capability_types: + Socket: + derived_from: tosca.capabilities.Root + +node_types: + Socket: + derived_from: tosca.nodes.Root + capabilities: + socket: Socket + + Plug: + derived_from: tosca.nodes.Root + requirements: + - plug: + capability: Socket + +topology_template: + node_templates: + socket: + type: Socket + + plug: + type: Plug \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/90107846/tests/storage/__init__.py ---------------------------------------------------------------------- diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py index 8ca1480..8a4d613 100644 --- a/tests/storage/__init__.py +++ b/tests/storage/__init__.py @@ -23,8 +23,6 @@ from sqlalchemy import ( MetaData ) -from aria.modeling import models - class TestFileSystem(object):
