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 7169E200C7D for ; Tue, 2 May 2017 00:24:11 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 6FE69160BC1; Mon, 1 May 2017 22:24:11 +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 1C653160BC2 for ; Tue, 2 May 2017 00:24:08 +0200 (CEST) Received: (qmail 33629 invoked by uid 500); 1 May 2017 22:24:08 -0000 Mailing-List: contact dev-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 dev@ariatosca.incubator.apache.org Received: (qmail 33607 invoked by uid 99); 1 May 2017 22:24:08 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd3-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 May 2017 22:24:08 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd3-us-west.apache.org (ASF Mail Server at spamd3-us-west.apache.org) with ESMTP id 8E69118FF2C for ; Mon, 1 May 2017 22:24:07 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd3-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -4.222 X-Spam-Level: X-Spam-Status: No, score=-4.222 tagged_above=-999 required=6.31 tests=[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 (spamd3-us-west.apache.org [10.40.0.10]) (amavisd-new, port 10024) with ESMTP id UhQsl79ONKs9 for ; Mon, 1 May 2017 22:23:55 +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 27F3660D0A for ; Mon, 1 May 2017 22:23:51 +0000 (UTC) Received: (qmail 32228 invoked by uid 99); 1 May 2017 22:23:51 -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; Mon, 01 May 2017 22:23:51 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 2912AE1103; Mon, 1 May 2017 22:23:51 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: emblemparade@apache.org To: dev@ariatosca.incubator.apache.org Date: Mon, 01 May 2017 22:24:02 -0000 Message-Id: In-Reply-To: <8aa4e3e1df5b4612b57a404b496faeb6@git.apache.org> References: <8aa4e3e1df5b4612b57a404b496faeb6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [13/13] incubator-ariatosca git commit: ARIA-139 Support attributes archived-at: Mon, 01 May 2017 22:24:11 -0000 ARIA-139 Support attributes Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/b7e1836d Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/b7e1836d Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/b7e1836d Branch: refs/heads/ARIA-139-attributes Commit: b7e1836d894944ca1ae32fc63bb1b25e2fcaad6a Parents: 0878526 Author: Tal Liron Authored: Wed Apr 19 20:07:33 2017 -0500 Committer: Tal Liron Committed: Mon May 1 17:03:52 2017 -0500 ---------------------------------------------------------------------- aria/core.py | 6 +- aria/modeling/functions.py | 113 ++- aria/modeling/mixins.py | 2 +- aria/modeling/relationship.py | 19 +- aria/modeling/service_common.py | 220 +++++- aria/modeling/service_instance.py | 78 ++- aria/modeling/service_template.py | 126 ++-- aria/modeling/utils.py | 33 +- aria/parser/consumption/__init__.py | 11 +- aria/parser/consumption/modeling.py | 4 +- aria/utils/formatting.py | 4 +- .../block-storage-1/block-storage-1.yaml | 2 +- .../block-storage-2/block-storage-2.yaml | 2 +- .../block-storage-3/block-storage-3.yaml | 2 +- .../block-storage-4/block-storage-4.yaml | 2 +- .../block-storage-5/block-storage-5.yaml | 6 +- .../block-storage-6/block-storage-6.yaml | 4 +- .../use-cases/multi-tier-1/multi-tier-1.yaml | 14 +- .../simple_v1_0/__init__.py | 12 +- .../simple_v1_0/functions.py | 536 --------------- .../simple_v1_0/modeling/__init__.py | 171 ++--- .../simple_v1_0/modeling/data_types.py | 10 +- .../simple_v1_0/modeling/functions.py | 687 +++++++++++++++++++ .../simple_v1_0/modeling/properties.py | 17 +- .../simple_v1_0/presenter.py | 4 +- .../simple_v1_0/templates.py | 7 +- .../node-cellar/node-cellar.yaml | 6 +- 27 files changed, 1248 insertions(+), 850 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/core.py ---------------------------------------------------------------------- diff --git a/aria/core.py b/aria/core.py index af1984a..cc943ef 100644 --- a/aria/core.py +++ b/aria/core.py @@ -77,10 +77,14 @@ class Core(object): consumption.ConsumerChain( context, ( + consumption.CoerceServiceInstanceValues, + consumption.ValidateServiceInstance, consumption.SatisfyRequirements, + consumption.CoerceServiceInstanceValues, consumption.ValidateCapabilities, consumption.FindHosts, - consumption.ConfigureOperations + consumption.ConfigureOperations, + consumption.CoerceServiceInstanceValues )).consume() if context.validation.dump_issues(): raise exceptions.InstantiationError('Failed to instantiate service template') http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/functions.py ---------------------------------------------------------------------- diff --git a/aria/modeling/functions.py b/aria/modeling/functions.py index 02f4454..7c773ed 100644 --- a/aria/modeling/functions.py +++ b/aria/modeling/functions.py @@ -13,20 +13,127 @@ # See the License for the specific language governing permissions and # limitations under the License. +from ..parser.consumption import ConsumptionContext +from ..parser.exceptions import InvalidValueError +from ..utils.collections import OrderedDict +from . import exceptions + + class Function(object): """ - An intrinsic function. + Base class for intrinsic functions. Serves as a placeholder for a value that should eventually + be derived by "evaluating" (calling) the function. - Serves as a placeholder for a value that should eventually be derived by calling the function. + Note that this base class is provided as a convenience and you do not have to inherit it: any + object with an ``__evaluate__`` method would be treated similarly. """ @property def as_raw(self): raise NotImplementedError - def _evaluate(self, context, container): + def __evaluate__(self, container_holder): + """ + Evaluates the function if possible. If impossible, raises + :class:`CannotEvaluateFunctionException` (do not just return None). + + :rtype: Evaluation (or any object with ``value`` and ``final`` properties) + """ + raise NotImplementedError def __deepcopy__(self, memo): # Circumvent cloning in order to maintain our state return self + + +class Evaluation(object): + """ + A wrapper for an evaluated :class:`Function` value. + """ + + def __init__(self, value, final=False): + self.value = value + self.final = final + + +class NodeTemplateConstraint(object): + """ + Used to constrain requirements for node templates. + + Must be serializable. + """ + + def matches(self, source_node_template, target_node_template): + """ + Returns true is the target matches the constraint for the source. + """ + raise NotImplementedError + + +def evaluate(value, container_holder, report_issues=False): # pylint: disable=too-many-branches + """ + Recursively attempts to call ``__evaluate__``. If an evaluation occurred will return an + :class:`Evaluation`, otherwise it will be None. If any evaluation is non-final, then the entire + evaluation will also be non-final. + """ + + evaluated = False + final = True + + if hasattr(value, '__evaluate__'): + try: + evaluation = value.__evaluate__(container_holder) + + # Verify evaluation structure + if (evaluation is None) \ + or (not hasattr(evaluation, 'value')) \ + or (not hasattr(evaluation, 'final')): + raise InvalidValueError('bad __evaluate__ implementation') + + evaluated = True + value = evaluation.value + final = evaluation.final + + # The evaluated value might itself be evaluable + evaluation = evaluate(value, container_holder, report_issues) + if evaluation is not None: + value = evaluation.value + if not evaluation.final: + final = False + except exceptions.CannotEvaluateFunctionException: + pass + except InvalidValueError as e: + if report_issues: + context = ConsumptionContext.get_thread_local() + context.validation.report(e.issue) + + elif isinstance(value, list): + evaluated_list = [] + for v in value: + evaluation = evaluate(v, container_holder, report_issues) + if evaluation is not None: + evaluated_list.append(evaluation.value) + evaluated = True + if not evaluation.final: + final = False + else: + evaluated_list.append(v) + if evaluated: + value = evaluated_list + + elif isinstance(value, dict): + evaluated_dict = OrderedDict() + for k, v in value.iteritems(): + evaluation = evaluate(v, container_holder, report_issues) + if evaluation is not None: + evaluated_dict[k] = evaluation.value + evaluated = True + if not evaluation.final: + final = False + else: + evaluated_dict[k] = v + if evaluated: + value = evaluated_dict + + return Evaluation(value, final) if evaluated else None http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/mixins.py ---------------------------------------------------------------------- diff --git a/aria/modeling/mixins.py b/aria/modeling/mixins.py index e6db5a3..38c812d 100644 --- a/aria/modeling/mixins.py +++ b/aria/modeling/mixins.py @@ -124,7 +124,7 @@ class InstanceModelMixin(ModelMixin): def validate(self): pass - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): pass def dump(self): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/relationship.py ---------------------------------------------------------------------- diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py index 291d08c..40be5b2 100644 --- a/aria/modeling/relationship.py +++ b/aria/modeling/relationship.py @@ -146,13 +146,18 @@ def one_to_one(model_class, false to disable :type back_populates: basestring|bool """ - if back_populates is None: - back_populates = model_class.__tablename__ + backref_kwargs = None + if back_populates is not NO_BACK_POP: + if back_populates is None: + back_populates = model_class.__tablename__ + backref_kwargs = {'name': back_populates, 'uselist': False} + back_populates = None return _relationship(model_class, other_table, fk=fk, back_populates=back_populates, + backref_kwargs=backref_kwargs, other_fk=other_fk) @@ -190,6 +195,7 @@ def one_to_many(model_class, rel_kwargs.setdefault('cascade', 'all') if back_populates is None: back_populates = model_class.__tablename__ + return _relationship( model_class, child_table, @@ -330,10 +336,11 @@ def _relationship(model_class, if backref_kwargs: assert back_populates is None - return relationship(lambda: _get_class_for_table(model_class, other_table_name), - backref=backref(**backref_kwargs), - **relationship_kwargs - ) + return relationship( + lambda: _get_class_for_table(model_class, other_table_name), + backref=backref(**backref_kwargs), + **relationship_kwargs + ) else: if back_populates is not NO_BACK_POP: relationship_kwargs['back_populates'] = back_populates http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/service_common.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py index 1188f34..25ea905 100644 --- a/aria/modeling/service_common.py +++ b/aria/modeling/service_common.py @@ -15,6 +15,8 @@ # pylint: disable=no-self-argument, no-member, abstract-method +import datetime + from sqlalchemy import ( Column, Text, @@ -22,12 +24,13 @@ from sqlalchemy import ( ) from sqlalchemy.ext.declarative import declared_attr +from ..parser import dsl_specification from ..parser.consumption import ConsumptionContext from ..utils import collections, formatting, console from .mixins import InstanceModelMixin, TemplateModelMixin from . import ( relationship, - utils + functions ) @@ -50,8 +53,171 @@ class ParameterBase(TemplateModelMixin): name = Column(Text) type_name = Column(Text) - value = Column(PickleType) description = Column(Text) + _value = Column(PickleType) + + @property + def value(self): + value = self._value + if value is not None: + evaluation = functions.evaluate(value, self) + if evaluation is not None: + value = evaluation.value + return value + + @value.setter + def value(self, value): + self._value = value + + @property + def container(self): # pylint: disable=too-many-return-statements,too-many-branches + """ + The container for this parameter, which would be another model. + + *All* parameters should have a container model. In case this property method fails to find + it, it will raise a ValueError, which should signify an abnormal, orphaned parameter. + """ + + def get_interface_container(interface): + # Node + if interface.node: + return interface.node + elif interface.relationship: + return interface.relationship.source_node + # Group + elif interface.group: + return interface.group + raise ValueError('interface parameter does not have a container: {0}' + .format(self.name)) + + def get_interface_template_container(interface_template): + # NodeTemplate + if interface_template.node_template: + return interface_template.node_template + elif interface_template.relationship_template: + relationship_template = interface_template.relationship_template + requirement_template = relationship_template.requirement_template + return requirement_template.node_template + # GroupTemplate + elif interface_template.group_template: + return interface_template.group_template + raise ValueError('interface_template parameter does not have a container: {0}' + .format(self.name)) + + # Node + if self.properties_nodes: + return self.properties_nodes[0] + elif self.attributes_nodes: + return self.attributes_nodes[0] + elif self.properties_capabilities: + capability = self.properties_capabilities[0] + return capability.node + elif self.properties_artifacts: + artifact = self.properties_artifacts[0] + return artifact.node + elif self.properties_relationships: + relationship = self.properties_relationships[0] # pylint: disable=redefined-outer-name + return relationship.source_node + # Group + elif self.properties_groups: + return self.properties_groups[0] + # Policy + elif self.properties_policies: + return self.properties_policies[0] + # Service + elif self.inputs_services: + return self.inputs_services[0] + elif self.outputs_services: + return self.outputs_services[0] + # Execution + elif self.inputs_executions: + return self.inputs_executions[0] + # Node or Group + elif self.inputs_interfaces: + interface = self.inputs_interfaces[0] + return get_interface_container(interface) + elif self.inputs_operations: + operation = self.inputs_operations[0] + # Node or Group + if operation.interface: + return get_interface_container(operation.interface) + # Service + elif operation.service: + return operation.service + raise ValueError('operation parameter does not have a container: {0}' + .format(self.name)) + + # NodeTemplate + elif self.properties_node_templates: + return self.properties_node_templates[0] + elif self.attributes_node_templates: + return self.attributes_node_templates[0] + elif self.properties_capability_templates: + capability_template = self.properties_capability_templates[0] + return capability_template.node_template + elif self.properties_artifact_templates: + artifact_template = self.properties_artifact_templates[0] + return artifact_template.node_template + elif self.properties_relationship_templates: + relationship_template = self.properties_relationship_templates[0] + requirement_template = relationship_template.requirement_template + return requirement_template.node_template + # GroupTemplate + elif self.properties_group_templates: + return self.properties_group_templates[0] + # PolicyTemplate + elif self.properties_policy_templates: + return self.properties_policy_templates[0] + # ServiceTemplate + elif self.inputs_service_templates: + return self.inputs_service_templates[0] + elif self.outputs_service_templates: + return self.outputs_service_templates[0] + # NodeTemplate or GroupTemplate + elif self.inputs_interface_templates: + interface_template = self.inputs_interface_templates[0] + return get_interface_template_container(interface_template) + elif self.inputs_operation_templates: + operation_template = self.inputs_operation_templates[0] + # NodeTemplate or GroupTemplate + if operation_template.interface_template: + return get_interface_template_container(operation_template.interface_template) + # ServiceTemplate + elif operation_template.service_template: + return operation_template.service_template + raise ValueError('operation_template parameter does not have a container: {0}' + .format(self.name)) + + raise ValueError('parameter does not have a container: {0}'.format(self.name)) + + @property + def service(self): + """ + The :class:`Service` containing this parameter, or None if not contained in a service. + """ + + from . import models + container = self.container + if isinstance(container, models.Service): + return container + elif hasattr(container, 'service'): + return container.service + return None + + @property + def service_template(self): + """ + The :class:`ServiceTemplate` containing this parameter, or None if not contained in a + service template. + """ + + from . import models + container = self.container + if isinstance(container, models.ServiceTemplate): + return container + elif hasattr(container, 'service_template'): + return container.service_template + return None @property def as_raw(self): @@ -65,47 +231,69 @@ class ParameterBase(TemplateModelMixin): from . import models return models.Parameter(name=self.name, type_name=self.type_name, - value=self.value, + _value=self._value, description=self.description) - def coerce_values(self, container, report_issues): - if self.value is not None: - self.value = utils.coerce_value(container, self.value, - report_issues) + def coerce_values(self, report_issues): + value = self._value + if value is not None: + evaluation = functions.evaluate(value, self, report_issues) + if (evaluation is not None) and evaluation.final: + # 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(self.value), + 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(self.value))) + context.style.literal(formatting.as_raw(self.value)))) if self.description: console.puts(context.style.meta(self.description)) def unwrap(self): return self.name, self.value + @dsl_specification('3.2.1-2', 'tosca-simple-1.0') @classmethod def wrap(cls, name, value, description=None): """ Wraps an arbitrary value as a parameter. The type will be guessed via introspection. + For primitive types, we will prefer their TOSCA aliases. See the `TOSCA Simple Profile v1.0 + cos01 specification `__ + :param name: Parameter name :type name: basestring :param value: Parameter value :param description: Description (optional) :type description: basestring """ - return cls(name=name, - type_name=formatting.full_type_name(value) - if value is not None else None, - value=value, - description=description) + from . import models + if value is None: + type_name = 'null' + elif isinstance(value, basestring): + type_name = 'string' + elif isinstance(value, int): + type_name = 'integer' + elif isinstance(value, float): + type_name = 'float' + elif isinstance(value, bool): + type_name = 'boolean' + elif isinstance(value, datetime.datetime): + type_name = 'timestamp' + else: + type_name = formatting.full_type_name(value) + return models.Parameter(name=name, + type_name=type_name, + value=value, + description=description) class TypeBase(InstanceModelMixin): @@ -188,7 +376,7 @@ class TypeBase(InstanceModelMixin): self._append_raw_children(types) return types - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): pass def dump(self): @@ -237,7 +425,7 @@ class MetadataBase(TemplateModelMixin): ('name', self.name), ('value', self.value))) - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): pass def instantiate(self, container): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/service_instance.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py index ad8e7ed..1efe1e1 100644 --- a/aria/modeling/service_instance.py +++ b/aria/modeling/service_instance.py @@ -251,16 +251,16 @@ class ServiceBase(InstanceModelMixin): utils.validate_dict_values(self.outputs) utils.validate_dict_values(self.workflows) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.meta_data, report_issues) - utils.coerce_dict_values(container, self.nodes, report_issues) - utils.coerce_dict_values(container, self.groups, report_issues) - utils.coerce_dict_values(container, self.policies, report_issues) + 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(container, report_issues) - utils.coerce_dict_values(container, self.inputs, report_issues) - utils.coerce_dict_values(container, self.outputs, report_issues) - utils.coerce_dict_values(container, self.workflows, report_issues) + 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() @@ -513,6 +513,10 @@ class NodeBase(InstanceModelMixin): def properties(cls): return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + @declared_attr + def attributes(cls): + return relationship.many_to_many(cls, 'parameter', prefix='attributes', dict_key='name') + # endregion description = Column(Text) @@ -646,6 +650,7 @@ class NodeBase(InstanceModelMixin): ('name', self.name), ('type_name', self.type.name), ('properties', formatting.as_raw_dict(self.properties)), + ('attributes', formatting.as_raw_dict(self.properties)), ('interfaces', formatting.as_raw_list(self.interfaces)), ('artifacts', formatting.as_raw_list(self.artifacts)), ('capabilities', formatting.as_raw_list(self.capabilities)), @@ -664,17 +669,19 @@ class NodeBase(InstanceModelMixin): # 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, container, report_issues): - utils.coerce_dict_values(self, self.properties, report_issues) - utils.coerce_dict_values(self, self.interfaces, report_issues) - utils.coerce_dict_values(self, self.artifacts, report_issues) - utils.coerce_dict_values(self, self.capabilities, report_issues) - utils.coerce_list_values(self, self.outbound_relationships, report_issues) + 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() @@ -683,6 +690,7 @@ class NodeBase(InstanceModelMixin): 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') @@ -797,9 +805,9 @@ class GroupBase(InstanceModelMixin): utils.validate_dict_values(self.properties) utils.validate_dict_values(self.interfaces) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.properties, report_issues) - utils.coerce_dict_values(container, self.interfaces, report_issues) + 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() @@ -916,8 +924,8 @@ class PolicyBase(InstanceModelMixin): def validate(self): utils.validate_dict_values(self.properties) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.properties, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.properties, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1017,8 +1025,8 @@ class SubstitutionBase(InstanceModelMixin): def validate(self): utils.validate_dict_values(self.mappings) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.mappings, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.mappings, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1121,7 +1129,7 @@ class SubstitutionMappingBase(InstanceModelMixin): return collections.OrderedDict(( ('name', self.name))) - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): pass def validate(self): @@ -1311,9 +1319,9 @@ class RelationshipBase(InstanceModelMixin): utils.validate_dict_values(self.properties) utils.validate_dict_values(self.interfaces) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.properties, report_issues) - utils.coerce_dict_values(container, self.interfaces, report_issues) + 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() @@ -1451,8 +1459,8 @@ class CapabilityBase(InstanceModelMixin): def validate(self): utils.validate_dict_values(self.properties) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.properties, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.properties, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1598,9 +1606,9 @@ class InterfaceBase(InstanceModelMixin): utils.validate_dict_values(self.inputs) utils.validate_dict_values(self.operations) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.inputs, report_issues) - utils.coerce_dict_values(container, self.operations, report_issues) + 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() @@ -1765,8 +1773,8 @@ class OperationBase(InstanceModelMixin): # TODO must be associated with interface or service utils.validate_dict_values(self.inputs) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.inputs, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.inputs, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1905,8 +1913,8 @@ class ArtifactBase(InstanceModelMixin): def validate(self): utils.validate_dict_values(self.properties) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.properties, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.properties, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/service_template.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py index 7fab4fc..73025e2 100644 --- a/aria/modeling/service_template.py +++ b/aria/modeling/service_template.py @@ -17,7 +17,6 @@ from __future__ import absolute_import # so we can import standard 'types' -from types import FunctionType from datetime import datetime from sqlalchemy import ( @@ -25,7 +24,8 @@ from sqlalchemy import ( Text, Integer, Boolean, - DateTime + DateTime, + PickleType ) from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.associationproxy import association_proxy @@ -346,16 +346,16 @@ class ServiceTemplateBase(TemplateModelMixin): if self.artifact_types is not None: self.artifact_types.validate() - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.meta_data, report_issues) - utils.coerce_dict_values(container, self.node_templates, report_issues) - utils.coerce_dict_values(container, self.group_templates, report_issues) - utils.coerce_dict_values(container, self.policy_templates, report_issues) + 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(container, report_issues) - utils.coerce_dict_values(container, self.inputs, report_issues) - utils.coerce_dict_values(container, self.outputs, report_issues) - utils.coerce_dict_values(container, self.workflow_templates, report_issues) + 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() @@ -426,7 +426,7 @@ class NodeTemplateBase(TemplateModelMixin): :ivar requirement_templates: Potential relationships with other nodes :vartype requirement_templates: [:class:`RequirementTemplate`] :ivar target_node_template_constraints: Constraints for filtering relationship targets - :vartype target_node_template_constraints: [:class:`FunctionType`] + :vartype target_node_template_constraints: [:class:`NodeTemplateConstraint`] :ivar service_template: Containing service template :vartype service_template: :class:`ServiceTemplate` :ivar group_templates: We are a member of these groups @@ -503,6 +503,10 @@ class NodeTemplateBase(TemplateModelMixin): return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') @declared_attr + def attributes(cls): + return relationship.many_to_many(cls, 'parameter', prefix='attributes', dict_key='name') + + @declared_attr def interface_templates(cls): return relationship.one_to_many(cls, 'interface_template', dict_key='name') @@ -524,12 +528,12 @@ class NodeTemplateBase(TemplateModelMixin): default_instances = Column(Integer, default=1) min_instances = Column(Integer, default=0) max_instances = Column(Integer, default=None) - target_node_template_constraints = Column(modeling_types.StrictList(FunctionType)) + target_node_template_constraints = Column(PickleType) - def is_target_node_valid(self, target_node_template): + def is_target_node_template_valid(self, target_node_template): if self.target_node_template_constraints: - for node_type_constraint in self.target_node_template_constraints: - if not node_type_constraint(target_node_template, self): + for node_template_constraint in self.target_node_template_constraints: + if not node_template_constraint.matches(self, target_node_template): return False return True @@ -543,6 +547,7 @@ class NodeTemplateBase(TemplateModelMixin): ('min_instances', self.min_instances), ('max_instances', self.max_instances), ('properties', formatting.as_raw_dict(self.properties)), + ('attributes', formatting.as_raw_dict(self.properties)), ('interface_templates', formatting.as_raw_list(self.interface_templates)), ('artifact_templates', formatting.as_raw_list(self.artifact_templates)), ('capability_templates', formatting.as_raw_list(self.capability_templates)), @@ -559,24 +564,34 @@ class NodeTemplateBase(TemplateModelMixin): runtime_properties={}, node_template=self) utils.instantiate_dict(node, node.properties, self.properties) + utils.instantiate_dict(node, node.attributes, self.attributes) utils.instantiate_dict(node, node.interfaces, self.interface_templates) utils.instantiate_dict(node, node.artifacts, self.artifact_templates) utils.instantiate_dict(node, node.capabilities, self.capability_templates) + + # Default attributes + if 'tosca_name' in node.attributes: + node.attributes['tosca_name'].value = self.name + if 'tosca_id' in node.attributes: + node.attributes['tosca_id'].value = name + return node def validate(self): utils.validate_dict_values(self.properties) + utils.validate_dict_values(self.attributes) utils.validate_dict_values(self.interface_templates) utils.validate_dict_values(self.artifact_templates) utils.validate_dict_values(self.capability_templates) utils.validate_list_values(self.requirement_templates) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(self, self.properties, report_issues) - utils.coerce_dict_values(self, self.interface_templates, report_issues) - utils.coerce_dict_values(self, self.artifact_templates, report_issues) - utils.coerce_dict_values(self, self.capability_templates, report_issues) - utils.coerce_list_values(self, self.requirement_templates, report_issues) + 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() @@ -592,6 +607,7 @@ class NodeTemplateBase(TemplateModelMixin): if self.max_instances is not None else ' or more')) utils.dump_dict_values(self.properties, 'Properties') + utils.dump_dict_values(self.attributes, 'Attributes') utils.dump_interfaces(self.interface_templates) utils.dump_dict_values(self.artifact_templates, 'Artifact templates') utils.dump_dict_values(self.capability_templates, 'Capability templates') @@ -715,9 +731,9 @@ class GroupTemplateBase(TemplateModelMixin): utils.validate_dict_values(self.properties) utils.validate_dict_values(self.interface_templates) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(self, self.properties, report_issues) - utils.coerce_dict_values(self, self.interface_templates, report_issues) + 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() @@ -846,8 +862,8 @@ class PolicyTemplateBase(TemplateModelMixin): def validate(self): utils.validate_dict_values(self.properties) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(self, self.properties, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.properties, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -940,8 +956,8 @@ class SubstitutionTemplateBase(TemplateModelMixin): def validate(self): utils.validate_dict_values(self.mappings) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(self, self.mappings, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.mappings, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1044,7 +1060,7 @@ class SubstitutionTemplateMappingBase(TemplateModelMixin): return collections.OrderedDict(( ('name', self.name))) - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): pass def instantiate(self, container): @@ -1108,7 +1124,7 @@ class RequirementTemplateBase(TemplateModelMixin): :ivar target_capability_name: Name of capability in target node (optional) :vartype target_capability_name: basestring :ivar target_node_template_constraints: Constraints for filtering relationship targets - :vartype target_node_template_constraints: [:class:`FunctionType`] + :vartype target_node_template_constraints: [:class:`NodeTemplateConstraint`] :ivar relationship_template: Template for relationships (optional) :vartype relationship_template: :class:`RelationshipTemplate` :ivar node_template: Containing node template @@ -1178,9 +1194,7 @@ class RequirementTemplateBase(TemplateModelMixin): @declared_attr def relationship_template(cls): - return relationship.one_to_one(cls, - 'relationship_template', - back_populates=relationship.NO_BACK_POP) + return relationship.one_to_one(cls, 'relationship_template') # endregion @@ -1210,18 +1224,18 @@ class RequirementTemplateBase(TemplateModelMixin): # endregion target_capability_name = Column(Text) - target_node_template_constraints = Column(modeling_types.StrictList(FunctionType)) + target_node_template_constraints = Column(PickleType) 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_valid(self.target_node_template): + 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, + self.target_node_template.name, source_node_template.name), level=validation.Issue.BETWEEN_TYPES) if (self.target_capability_type is not None) \ @@ -1242,7 +1256,7 @@ class RequirementTemplateBase(TemplateModelMixin): if self.target_node_type.get_descendant(target_node_template.type.name) is None: continue - if not source_node_template.is_target_node_valid(target_node_template): + if not source_node_template.is_target_node_template_valid(target_node_template): continue target_node_capability = self.find_target_capability(source_node_template, @@ -1279,9 +1293,9 @@ class RequirementTemplateBase(TemplateModelMixin): if self.relationship_template: self.relationship_template.validate() - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): if self.relationship_template is not None: - self.relationship_template.coerce_values(container, report_issues) + self.relationship_template.coerce_values(report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1412,9 +1426,9 @@ class RelationshipTemplateBase(TemplateModelMixin): utils.validate_dict_values(self.properties) utils.validate_dict_values(self.interface_templates) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(self, self.properties, report_issues) - utils.coerce_dict_values(self, self.interface_templates, report_issues) + 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() @@ -1538,8 +1552,8 @@ class CapabilityTemplateBase(TemplateModelMixin): # Apply requirement constraints if requirement.target_node_template_constraints: - for node_type_constraint in requirement.target_node_template_constraints: - if not node_type_constraint(target_node_template, source_node_template): + 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 @@ -1569,8 +1583,8 @@ class CapabilityTemplateBase(TemplateModelMixin): def validate(self): utils.validate_dict_values(self.properties) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(self, self.properties, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.properties, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -1723,9 +1737,9 @@ class InterfaceTemplateBase(TemplateModelMixin): utils.validate_dict_values(self.inputs) utils.validate_dict_values(self.operation_templates) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.inputs, report_issues) - utils.coerce_dict_values(container, self.operation_templates, report_issues) + 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() @@ -1877,7 +1891,7 @@ class OperationTemplateBase(TemplateModelMixin): plugin = None implementation = None else: - # using the execution plugin + # Using the execution plugin plugin = None implementation = self.implementation @@ -1898,8 +1912,8 @@ class OperationTemplateBase(TemplateModelMixin): def validate(self): utils.validate_dict_values(self.inputs) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.inputs, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.inputs, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -2046,8 +2060,8 @@ class ArtifactTemplateBase(TemplateModelMixin): def validate(self): utils.validate_dict_values(self.properties) - def coerce_values(self, container, report_issues): - utils.coerce_dict_values(container, self.properties, report_issues) + def coerce_values(self, report_issues): + utils.coerce_dict_values(self.properties, report_issues) def dump(self): context = ConsumptionContext.get_thread_local() @@ -2123,7 +2137,7 @@ class PluginSpecificationBase(TemplateModelMixin): ('version', self.version), ('enabled', self.enabled))) - def coerce_values(self, container, report_issues): + def coerce_values(self, report_issues): pass def resolve(self, model_storage): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/modeling/utils.py ---------------------------------------------------------------------- diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py index 91d7b9c..c786965 100644 --- a/aria/modeling/utils.py +++ b/aria/modeling/utils.py @@ -19,9 +19,6 @@ from StringIO import StringIO from . import exceptions from ..parser.consumption import ConsumptionContext -from ..parser.exceptions import InvalidValueError -from ..parser.presentation import Value -from ..utils.collections import OrderedDict from ..utils.console import puts from ..utils.type import validate_value_type @@ -109,39 +106,17 @@ def _merge_and_validate_inputs(inputs, template_inputs): return merged_inputs -def coerce_value(container, value, report_issues=False): - if isinstance(value, Value): - value = value.value - - if isinstance(value, list): - return [coerce_value(container, v, report_issues) for v in value] - elif isinstance(value, dict): - return OrderedDict((k, coerce_value(container, v, report_issues)) - for k, v in value.iteritems()) - elif hasattr(value, '_evaluate'): - context = ConsumptionContext.get_thread_local() - try: - value = value._evaluate(context, container) - value = coerce_value(container, value, report_issues) - except exceptions.CannotEvaluateFunctionException: - pass - except InvalidValueError as e: - if report_issues: - context.validation.report(e.issue) - return value - - -def coerce_dict_values(container, the_dict, report_issues=False): +def coerce_dict_values(the_dict, report_issues=False): if not the_dict: return - coerce_list_values(container, the_dict.itervalues(), report_issues) + coerce_list_values(the_dict.itervalues(), report_issues) -def coerce_list_values(container, the_list, report_issues=False): +def coerce_list_values(the_list, report_issues=False): if not the_list: return for value in the_list: - value.coerce_values(container, report_issues) + value.coerce_values(report_issues) def validate_dict_values(the_dict): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/parser/consumption/__init__.py ---------------------------------------------------------------------- diff --git a/aria/parser/consumption/__init__.py b/aria/parser/consumption/__init__.py index 8f6d2b6..76e73be 100644 --- a/aria/parser/consumption/__init__.py +++ b/aria/parser/consumption/__init__.py @@ -28,9 +28,11 @@ from .modeling import ( Types, ServiceInstance, FindHosts, + ValidateServiceInstance, ConfigureOperations, SatisfyRequirements, - ValidateCapabilities + ValidateCapabilities, + CoerceServiceInstanceValues ) from .inputs import Inputs @@ -45,7 +47,10 @@ __all__ = ( 'ServiceTemplate', 'Types', 'ServiceInstance', - 'Inputs', + 'FindHosts', + 'ValidateServiceInstance', + 'ConfigureOperations', 'SatisfyRequirements', - 'ValidateCapabilities' + 'ValidateCapabilities', + 'CoerceServiceInstanceValues' ) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/parser/consumption/modeling.py ---------------------------------------------------------------------- diff --git a/aria/parser/consumption/modeling.py b/aria/parser/consumption/modeling.py index 771fd7f..44027b9 100644 --- a/aria/parser/consumption/modeling.py +++ b/aria/parser/consumption/modeling.py @@ -42,7 +42,7 @@ class CoerceServiceTemplateValues(Consumer): """ def consume(self): - self.context.modeling.template.coerce_values(None, True) + self.context.modeling.template.coerce_values(True) class ValidateServiceTemplate(Consumer): @@ -116,7 +116,7 @@ class CoerceServiceInstanceValues(Consumer): """ def consume(self): - self.context.modeling.instance.coerce_values(None, True) + self.context.modeling.instance.coerce_values(True) class ValidateServiceInstance(Consumer): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/aria/utils/formatting.py ---------------------------------------------------------------------- diff --git a/aria/utils/formatting.py b/aria/utils/formatting.py index b5e141d..75652a7 100644 --- a/aria/utils/formatting.py +++ b/aria/utils/formatting.py @@ -163,8 +163,8 @@ def as_raw(value): value = value() elif isinstance(value, list): value = list(value) - for i, _ in enumerate(value): - value[i] = as_raw(value[i]) + for i, v in enumerate(value): + value[i] = as_raw(v) elif isinstance(value, dict): value = dict(value) for k, v in value.iteritems(): http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml index ff6dc92..b912fb2 100644 --- a/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml +++ b/examples/tosca-simple-1.0/use-cases/block-storage-1/block-storage-1.yaml @@ -65,4 +65,4 @@ topology_template: value: { get_attribute: [ my_server, private_address ] } volume_id: description: The volume id of the block storage instance. - value: { get_attribute: [ my_storage, volume_id ] } + value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml index 09c30a7..ac475cf 100644 --- a/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml +++ b/examples/tosca-simple-1.0/use-cases/block-storage-2/block-storage-2.yaml @@ -72,4 +72,4 @@ topology_template: volume_id: description: The volume id of the block storage instance. - value: { get_attribute: [ my_storage, volume_id ] } + value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml index 3018fe9..c3f183e 100644 --- a/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml +++ b/examples/tosca-simple-1.0/use-cases/block-storage-3/block-storage-3.yaml @@ -65,4 +65,4 @@ topology_template: value: { get_attribute: [ my_server, private_address ] } volume_id: description: The volume id of the block storage instance. - value: { get_attribute: [ my_storage, volume_id ] } + value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml index 0693ddd..e2bdb9f 100644 --- a/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml +++ b/examples/tosca-simple-1.0/use-cases/block-storage-4/block-storage-4.yaml @@ -93,4 +93,4 @@ topology_template: value: { get_attribute: [ my_web_app_tier_2, private_address ] } volume_id: description: The volume id of the block storage instance. - value: { get_attribute: [ my_storage, volume_id ] } + value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml index 5f5cf71..a0c2229 100644 --- a/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml +++ b/examples/tosca-simple-1.0/use-cases/block-storage-5/block-storage-5.yaml @@ -100,10 +100,10 @@ topology_template: outputs: private_ip_1: description: The private IP address of the application's first tier. - value: { get_attribute: [my_web_app_tier_1, private_address] } + value: { get_attribute: [ my_web_app_tier_1, private_address ] } private_ip_2: description: The private IP address of the application's second tier. - value: { get_attribute: [my_web_app_tier_2, private_address] } + value: { get_attribute: [ my_web_app_tier_2, private_address ] } volume_id: description: The volume id of the block storage instance. - value: { get_attribute: [my_storage, volume_id] } + value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml b/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml index 808245b..534884a 100644 --- a/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml +++ b/examples/tosca-simple-1.0/use-cases/block-storage-6/block-storage-6.yaml @@ -96,7 +96,7 @@ topology_template: value: { get_attribute: [ my_server2, private_address ] } volume_id_1: description: The volume id of the first block storage instance. - value: { get_attribute: [my_storage, volume_id] } + value: { get_property: [ my_storage, volume_id ] } # ARIA NOTE: wrong in spec volume_id_2: description: The volume id of the second block storage instance. - value: { get_attribute: [ my_storage2, volume_id ] } + value: { get_property: [ my_storage2, volume_id ] } # ARIA NOTE: wrong in spec http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml ---------------------------------------------------------------------- diff --git a/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml b/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml index 3485e49..50401ec 100644 --- a/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml +++ b/examples/tosca-simple-1.0/use-cases/multi-tier-1/multi-tier-1.yaml @@ -59,7 +59,7 @@ topology_template: implementation: scripts/nodejs/configure.sh inputs: github_url: { get_property: [ SELF, github_url ] } - mongodb_ip: { get_attribute: [mongo_server, private_address] } + mongodb_ip: { get_attribute: [ mongo_server, private_address ] } start: scripts/nodejs/start.sh nodejs: @@ -90,7 +90,7 @@ topology_template: configure: implementation: scripts/mongodb/config.sh inputs: - mongodb_ip: { get_attribute: [mongo_server, ip_address] } + mongodb_ip: { get_attribute: [ mongo_server, private_address ] } # ARIA NOTE: wrong in spec start: scripts/mongodb/start.sh elasticsearch: @@ -115,7 +115,7 @@ topology_template: pre_configure_source: implementation: python/logstash/configure_elasticsearch.py inputs: - elasticsearch_ip: { get_attribute: [elasticsearch_server, ip_address] } + elasticsearch_ip: { get_attribute: [ elasticsearch_server, private_address ] } # ARIA NOTE: wrong in spec interfaces: Standard: # ARIA NOTE: wrong in spec create: scripts/lostash/create.sh @@ -133,8 +133,8 @@ topology_template: configure: implementation: scripts/kibana/config.sh inputs: - elasticsearch_ip: { get_attribute: [ elasticsearch_server, ip_address ] } - kibana_ip: { get_attribute: [ kibana_server, ip_address ] } + elasticsearch_ip: { get_attribute: [ elasticsearch_server, private_address ] } # ARIA NOTE: wrong in spec + kibana_ip: { get_attribute: [ kibana_server, private_address ] } # ARIA NOTE: wrong in spec start: scripts/kibana/start.sh app_collectd: @@ -155,7 +155,7 @@ topology_template: configure: implementation: python/collectd/config.py inputs: - logstash_ip: { get_attribute: [ logstash_server, ip_address ] } + logstash_ip: { get_attribute: [ logstash_server, private_address ] } # ARIA NOTE: wrong in spec start: scripts/collectd/start.sh app_rsyslog: @@ -176,7 +176,7 @@ topology_template: configure: implementation: scripts/rsyslog/config.sh inputs: - logstash_ip: { get_attribute: [ logstash_server, ip_address ] } + logstash_ip: { get_attribute: [ logstash_server, private_address ] } # ARIA NOTE: wrong in spec start: scripts/rsyslog/start.sh app_server: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/extensions/aria_extension_tosca/simple_v1_0/__init__.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/__init__.py b/extensions/aria_extension_tosca/simple_v1_0/__init__.py index 29df362..d701a1d 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/__init__.py +++ b/extensions/aria_extension_tosca/simple_v1_0/__init__.py @@ -30,8 +30,6 @@ from .types import (ArtifactType, DataType, CapabilityType, InterfaceType, Relat NodeType, GroupType, PolicyType) from .data_types import (Timestamp, Version, Range, List, Map, ScalarSize, ScalarTime, ScalarFrequency) -from .functions import (Concat, Token, GetInput, GetProperty, GetAttribute, GetOperationOutput, - GetNodesOfType, GetArtifact) MODULES = ( 'modeling', @@ -89,12 +87,4 @@ __all__ = ( 'Map', 'ScalarSize', 'ScalarTime', - 'ScalarFrequency', - 'Concat', - 'Token', - 'GetInput', - 'GetProperty', - 'GetAttribute', - 'GetOperationOutput', - 'GetNodesOfType', - 'GetArtifact') + 'ScalarFrequency') \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/b7e1836d/extensions/aria_extension_tosca/simple_v1_0/functions.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/functions.py b/extensions/aria_extension_tosca/simple_v1_0/functions.py deleted file mode 100644 index 405aa8f..0000000 --- a/extensions/aria_extension_tosca/simple_v1_0/functions.py +++ /dev/null @@ -1,536 +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 cStringIO import StringIO - -from aria.utils.collections import FrozenList -from aria.utils.formatting import as_raw, safe_repr -from aria.parser import dsl_specification -from aria.parser.exceptions import InvalidValueError -from aria.parser.validation import Issue -from aria.modeling.exceptions import CannotEvaluateFunctionException -from aria.modeling.functions import Function - -# -# Intrinsic -# - -@dsl_specification('4.3.1', 'tosca-simple-1.0') -class Concat(Function): - """ - The :code:`concat` function is used to concatenate two or more string values within a TOSCA - service template. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - if not isinstance(argument, list): - raise InvalidValueError( - 'function "concat" argument must be a list of string expressions: %s' - % safe_repr(argument), - locator=self.locator) - - string_expressions = [] - for index, an_argument in enumerate(argument): - string_expressions.append(parse_string_expression(context, presentation, 'concat', - index, None, an_argument)) - self.string_expressions = FrozenList(string_expressions) - - @property - def as_raw(self): - string_expressions = [] - for string_expression in self.string_expressions: - if hasattr(string_expression, 'as_raw'): - string_expression = as_raw(string_expression) - string_expressions.append(string_expression) - return {'concat': string_expressions} - - def _evaluate(self, context, container): - value = StringIO() - for e in self.string_expressions: - if hasattr(e, '_evaluate'): - e = e._evaluate(context, container) - value.write(str(e)) - return value.getvalue() - -@dsl_specification('4.3.2', 'tosca-simple-1.0') -class Token(Function): - """ - The :code:`token` function is used within a TOSCA service template on a string to parse out - (tokenize) substrings separated by one or more token characters within a larger string. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - if (not isinstance(argument, list)) or (len(argument) != 3): - raise InvalidValueError('function "token" argument must be a list of 3 parameters: %s' - % safe_repr(argument), - locator=self.locator) - - self.string_with_tokens = parse_string_expression(context, presentation, 'token', 0, - 'the string to tokenize', argument[0]) - self.string_of_token_chars = parse_string_expression(context, presentation, 'token', 1, - 'the token separator characters', - argument[1]) - self.substring_index = parse_int(context, presentation, 'token', 2, - 'the 0-based index of the token to return', argument[2]) - - @property - def as_raw(self): - string_with_tokens = self.string_with_tokens - if hasattr(string_with_tokens, 'as_raw'): - string_with_tokens = as_raw(string_with_tokens) - string_of_token_chars = self.string_with_tokens - if hasattr(string_of_token_chars, 'as_raw'): - string_of_token_chars = as_raw(string_of_token_chars) - return {'token': [string_with_tokens, string_of_token_chars, self.substring_index]} - - def _evaluate(self, context, container): - string_with_tokens = self.string_with_tokens - if hasattr(string_with_tokens, '_evaluate'): - string_with_tokens = string_with_tokens._evaluate(context, container) # pylint: disable=no-member - -# -# Property -# - -@dsl_specification('4.4.1', 'tosca-simple-1.0') -class GetInput(Function): - """ - The :code:`get_input` function is used to retrieve the values of properties declared within the - inputs section of a TOSCA Service Template. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - self.input_property_name = parse_string_expression(context, presentation, 'get_input', - None, 'the input property name', - argument) - - if isinstance(self.input_property_name, basestring): - the_input = context.presentation.get_from_dict('service_template', 'topology_template', - 'inputs', self.input_property_name) - if the_input is None: - raise InvalidValueError( - 'function "get_input" argument is not a valid input name: %s' - % safe_repr(argument), - locator=self.locator) - - @property - def as_raw(self): - return {'get_input': as_raw(self.input_property_name)} - - def _evaluate(self, context, container): # pylint: disable=unused-argument - if not context.modeling.instance: - raise CannotEvaluateFunctionException() - the_input = context.modeling.instance.inputs.get( - self.input_property_name, - context.modeling.template.inputs.get(self.input_property_name)) - return as_raw(the_input.value) if the_input is not None else None - -@dsl_specification('4.4.2', 'tosca-simple-1.0') -class GetProperty(Function): - """ - The :code:`get_property` function is used to retrieve property values between modelable entities - defined in the same service template. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - if (not isinstance(argument, list)) or (len(argument) < 2): - raise InvalidValueError( - 'function "get_property" argument must be a list of at least 2 string expressions: ' - '%s' - % safe_repr(argument), - locator=self.locator) - - self.modelable_entity_name = parse_modelable_entity_name(context, presentation, - 'get_property', 0, argument[0]) - # The first of these will be tried as a req-or-cap name: - self.nested_property_name_or_index = argument[1:] - - @property - def as_raw(self): - return {'get_property': [self.modelable_entity_name] + self.nested_property_name_or_index} - - def _evaluate(self, context, container): - modelable_entities = get_modelable_entities(context, container, self.locator, - self.modelable_entity_name) - req_or_cap_name = self.nested_property_name_or_index[0] - - for modelable_entity in modelable_entities: - properties = None - - if hasattr(modelable_entity, 'requirement_templates') \ - and modelable_entity.requirement_templates \ - and (req_or_cap_name in [v.name for v in modelable_entity.requirement_templates]): - for requirement_template in modelable_entity.requirement_templates: - if requirement_template.name == req_or_cap_name: - # First argument refers to a requirement - # TODO: should follow to matched capability in other node... - raise CannotEvaluateFunctionException() - break - nested_property_name_or_index = self.nested_property_name_or_index[1:] - elif hasattr(modelable_entity, 'capability_templates') \ - and modelable_entity.capability_templates \ - and (req_or_cap_name in modelable_entity.capability_templates): - # First argument refers to a capability - properties = modelable_entity.capability_templates[req_or_cap_name].properties - nested_property_name_or_index = self.nested_property_name_or_index[1:] - else: - properties = modelable_entity.properties - nested_property_name_or_index = self.nested_property_name_or_index - - if properties: - found = True - value = properties - for name in nested_property_name_or_index: - if (isinstance(value, dict) and (name in value)) \ - or (isinstance(value, list) and name < len(list)): - value = value[name] - if hasattr(value, '_evaluate'): - value = value._evaluate(context, modelable_entity) - else: - found = False - break - if found: - return as_raw(value) - - raise InvalidValueError( - 'function "get_property" could not find "%s" in modelable entity "%s"' \ - % ('.'.join(self.nested_property_name_or_index), self.modelable_entity_name), - locator=self.locator) - -# -# Attribute -# - -@dsl_specification('4.5.1', 'tosca-simple-1.0') -class GetAttribute(Function): - """ - The :code:`get_attribute` function is used to retrieve the values of named attributes declared - by the referenced node or relationship template name. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - if (not isinstance(argument, list)) or (len(argument) < 2): - raise InvalidValueError( - 'function "get_attribute" argument must be a list of at least 2 string expressions:' - ' %s' - % safe_repr(argument), - locator=self.locator) - - self.modelable_entity_name = parse_modelable_entity_name(context, presentation, - 'get_attribute', 0, argument[0]) - # The first of these will be tried as a req-or-cap name: - self.nested_property_name_or_index = argument[1:] - - @property - def as_raw(self): - return {'get_attribute': [self.modelable_entity_name] + self.nested_property_name_or_index} - - def _evaluate(self, context, container): # pylint: disable=no-self-use,unused-argument - raise CannotEvaluateFunctionException() - -# -# Operation -# - -@dsl_specification('4.6.1', 'tosca-simple-1.0') -class GetOperationOutput(Function): - """ - The :code:`get_operation_output` function is used to retrieve the values of variables exposed / - exported from an interface operation. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - if (not isinstance(argument, list)) or (len(argument) != 4): - raise InvalidValueError( - 'function "get_operation_output" argument must be a list of 4 parameters: %s' - % safe_repr(argument), - locator=self.locator) - - self.modelable_entity_name = parse_string_expression(context, presentation, - 'get_operation_output', 0, - 'modelable entity name', argument[0]) - self.interface_name = parse_string_expression(context, presentation, 'get_operation_output', - 1, 'the interface name', argument[1]) - self.operation_name = parse_string_expression(context, presentation, 'get_operation_output', - 2, 'the operation name', argument[2]) - self.output_variable_name = parse_string_expression(context, presentation, - 'get_operation_output', 3, - 'the output name', argument[3]) - - @property - def as_raw(self): - interface_name = self.interface_name - if hasattr(interface_name, 'as_raw'): - interface_name = as_raw(interface_name) - operation_name = self.operation_name - if hasattr(operation_name, 'as_raw'): - operation_name = as_raw(operation_name) - output_variable_name = self.output_variable_name - if hasattr(output_variable_name, 'as_raw'): - output_variable_name = as_raw(output_variable_name) - return {'get_operation_output': [self.modelable_entity_name, interface_name, operation_name, - output_variable_name]} - -# -# Navigation -# - -@dsl_specification('4.7.1', 'tosca-simple-1.0') -class GetNodesOfType(Function): - """ - The :code:`get_nodes_of_type` function can be used to retrieve a list of all known instances of - nodes of the declared Node Type. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - self.node_type_name = parse_string_expression(context, presentation, 'get_nodes_of_type', - None, 'the node type name', argument) - - if isinstance(self.node_type_name, basestring): - node_types = context.presentation.get('service_template', 'node_types') - if (node_types is None) or (self.node_type_name not in node_types): - raise InvalidValueError( - 'function "get_nodes_of_type" argument is not a valid node type name: %s' - % safe_repr(argument), - locator=self.locator) - - @property - def as_raw(self): - node_type_name = self.node_type_name - if hasattr(node_type_name, 'as_raw'): - node_type_name = as_raw(node_type_name) - return {'get_nodes_of_type': node_type_name} - - def _evaluate(self, context, container): - pass - -# -# Artifact -# - -@dsl_specification('4.8.1', 'tosca-simple-1.0') -class GetArtifact(Function): - """ - The :code:`get_artifact` function is used to retrieve artifact location between modelable - entities defined in the same service template. - """ - - def __init__(self, context, presentation, argument): - self.locator = presentation._locator - - if (not isinstance(argument, list)) or (len(argument) < 2) or (len(argument) > 4): - raise InvalidValueError( - 'function "get_artifact" argument must be a list of 2 to 4 parameters: %s' - % safe_repr(argument), - locator=self.locator) - - self.modelable_entity_name = parse_string_expression(context, presentation, 'get_artifact', - 0, 'modelable entity name', - argument[0]) - self.artifact_name = parse_string_expression(context, presentation, 'get_artifact', 1, - 'the artifact name', argument[1]) - self.location = parse_string_expression(context, presentation, 'get_artifact', 2, - 'the location or "LOCAL_FILE"', argument[2]) - self.remove = parse_bool(context, presentation, 'get_artifact', 3, 'the removal flag', - argument[3]) - - @property - def as_raw(self): - artifact_name = self.artifact_name - if hasattr(artifact_name, 'as_raw'): - artifact_name = as_raw(artifact_name) - location = self.location - if hasattr(location, 'as_raw'): - location = as_raw(location) - return {'get_artifacts': [self.modelable_entity_name, artifact_name, location, self.remove]} - -# -# Utils -# - -def get_function(context, presentation, value): - functions = context.presentation.presenter.functions - if isinstance(value, dict) and (len(value) == 1): - key = value.keys()[0] - if key in functions: - try: - return True, functions[key](context, presentation, value[key]) - except InvalidValueError as e: - context.validation.report(issue=e.issue) - return True, None - return False, None - -def parse_string_expression(context, presentation, name, index, explanation, value): # pylint: disable=unused-argument - is_function, func = get_function(context, presentation, value) - if is_function: - return func - else: - value = str(value) - return value - -def parse_int(context, presentation, name, index, explanation, value): # pylint: disable=unused-argument - if not isinstance(value, int): - try: - value = int(value) - except ValueError: - raise invalid_value(name, index, 'an integer', explanation, value, - presentation._locator) - return value - -def parse_bool(context, presentation, name, index, explanation, value): # pylint: disable=unused-argument - if not isinstance(value, bool): - raise invalid_value(name, index, 'a boolean', explanation, value, presentation._locator) - return value - -def parse_modelable_entity_name(context, presentation, name, index, value): - value = parse_string_expression(context, presentation, name, index, 'the modelable entity name', - value) - if value == 'SELF': - the_self, _ = parse_self(presentation) - if the_self is None: - raise invalid_modelable_entity_name(name, index, value, presentation._locator, - 'a node template or a relationship template') - elif value == 'HOST': - _, self_variant = parse_self(presentation) - if self_variant != 'node_template': - raise invalid_modelable_entity_name(name, index, value, presentation._locator, - 'a node template') - elif (value == 'SOURCE') or (value == 'TARGET'): - _, self_variant = parse_self(presentation) - if self_variant != 'relationship_template': - raise invalid_modelable_entity_name(name, index, value, presentation._locator, - 'a relationship template') - elif isinstance(value, basestring): - node_templates = \ - context.presentation.get('service_template', 'topology_template', 'node_templates') \ - or {} - relationship_templates = \ - context.presentation.get('service_template', 'topology_template', - 'relationship_templates') \ - or {} - if (value not in node_templates) and (value not in relationship_templates): - raise InvalidValueError( - 'function "%s" parameter %d is not a valid modelable entity name: %s' - % (name, index + 1, safe_repr(value)), - locator=presentation._locator, level=Issue.BETWEEN_TYPES) - return value - -def parse_self(presentation): - from .templates import NodeTemplate, RelationshipTemplate - from .types import NodeType, RelationshipType - - if presentation is None: - return None, None - elif isinstance(presentation, NodeTemplate) or isinstance(presentation, NodeType): - return presentation, 'node_template' - elif isinstance(presentation, RelationshipTemplate) \ - or isinstance(presentation, RelationshipType): - return presentation, 'relationship_template' - else: - return parse_self(presentation._container) - -@dsl_specification('4.1', 'tosca-simple-1.0') -def get_modelable_entities(context, container, locator, modelable_entity_name): - """ - The following keywords MAY be used in some TOSCA function in place of a TOSCA Node or - Relationship Template name. - """ - - if modelable_entity_name == 'SELF': - return get_self(context, container) - elif modelable_entity_name == 'HOST': - return get_host(context, container) - elif modelable_entity_name == 'SOURCE': - return get_source(context, container) - elif modelable_entity_name == 'TARGET': - return get_target(context, container) - elif isinstance(modelable_entity_name, basestring): - node_templates = \ - context.presentation.get('service_template', 'topology_template', 'node_templates') \ - or {} - if modelable_entity_name in node_templates: - return [node_templates[modelable_entity_name]] - relationship_templates = \ - context.presentation.get('service_template', 'topology_template', - 'relationship_templates') \ - or {} - if modelable_entity_name in relationship_templates: - return [relationship_templates[modelable_entity_name]] - - raise InvalidValueError('function "get_property" could not find modelable entity "%s"' - % modelable_entity_name, - locator=locator) - -def get_self(context, container): # pylint: disable=unused-argument - """ - A TOSCA orchestrator will interpret this keyword as the Node or Relationship Template instance - that contains the function at the time the function is evaluated. - """ - - return [container] - -def get_host(context, container): # pylint: disable=unused-argument - """ - A TOSCA orchestrator will interpret this keyword to refer to the all nodes that "host" the node - using this reference (i.e., as identified by its HostedOn relationship). - - Specifically, TOSCA orchestrators that encounter this keyword when evaluating the get_attribute - or :code:`get_property` functions SHALL search each node along the "HostedOn" relationship chain - starting at the immediate node that hosts the node where the function was evaluated (and then - that node's host node, and so forth) until a match is found or the "HostedOn" relationship chain - ends. - """ - - return [] - -def get_source(context, container): # pylint: disable=unused-argument - """ - A TOSCA orchestrator will interpret this keyword as the Node Template instance that is at the - source end of the relationship that contains the referencing function. - """ - - return [] - -def get_target(context, container): # pylint: disable=unused-argument - """ - A TOSCA orchestrator will interpret this keyword as the Node Template instance that is at the - target end of the relationship that contains the referencing function. - """ - -def invalid_modelable_entity_name(name, index, value, locator, contexts): - return InvalidValueError('function "%s" parameter %d can be "%s" only in %s' - % (name, index + 1, value, contexts), - locator=locator, level=Issue.FIELD) - -def invalid_value(name, index, the_type, explanation, value, locator): - return InvalidValueError( - 'function "%s" %s is not %s%s: %s' - % (name, ('parameter %d' % (index + 1)) if index is not None else 'argument', - the_type, (', %s' % explanation) if explanation is not None else '', safe_repr(value)), - locator=locator, level=Issue.FIELD)