You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by em...@apache.org on 2017/04/27 02:17:29 UTC
incubator-ariatosca git commit: Progress on new function mechanism
Repository: incubator-ariatosca
Updated Branches:
refs/heads/ARIA-139-attributes d9cc24dce -> 6f349dd72
Progress on new function mechanism
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/6f349dd7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/6f349dd7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/6f349dd7
Branch: refs/heads/ARIA-139-attributes
Commit: 6f349dd723c82b9a889edbe3bb5a7e9d0b137c62
Parents: d9cc24d
Author: Tal Liron <ta...@gmail.com>
Authored: Wed Apr 26 21:16:55 2017 -0500
Committer: Tal Liron <ta...@gmail.com>
Committed: Wed Apr 26 21:16:55 2017 -0500
----------------------------------------------------------------------
aria/core.py | 6 +-
aria/modeling/functions.py | 99 ++++++++++-
aria/modeling/mixins.py | 2 +-
aria/modeling/service_common.py | 178 +++++++++++++++++--
aria/modeling/service_instance.py | 72 ++++----
aria/modeling/service_template.py | 80 ++++-----
aria/modeling/utils.py | 45 +----
aria/parser/consumption/__init__.py | 9 +-
aria/parser/consumption/modeling.py | 4 +-
.../simple_v1_0/functions.py | 103 ++++++-----
.../simple_v1_0/modeling/__init__.py | 4 +-
.../simple_v1_0/modeling/data_types.py | 2 +
12 files changed, 417 insertions(+), 187 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/6f349dd7/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/6f349dd7/aria/modeling/functions.py
----------------------------------------------------------------------
diff --git a/aria/modeling/functions.py b/aria/modeling/functions.py
index 02f4454..f0d6c81 100644
--- a/aria/modeling/functions.py
+++ b/aria/modeling/functions.py
@@ -13,20 +13,113 @@
# 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
+
+
+def evaluate(value, container_holder, report_issues=False):
+ """
+ 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/6f349dd7/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/6f349dd7/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 01458ad..9539979 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -30,7 +30,7 @@ from ..utils import collections, formatting, console
from .mixins import InstanceModelMixin, TemplateModelMixin
from . import (
relationship,
- utils
+ functions
)
@@ -53,10 +53,165 @@ class ParameterBase(TemplateModelMixin):
name = Column(Text)
type_name = Column(Text)
- value = Column(PickleType)
+ _value = Column(PickleType)
description = Column(Text)
@property
+ def value(self):
+ value = self._value
+ if value is not None:
+ evaluation = functions.evaluate(value, self)
+ if evaluation is not None:
+ print '>>> EVALUATED'
+ value = evaluation.value
+ return value
+
+ @value.setter
+ def value(self, value):
+ self._value = value
+
+ @property
+ def container(self):
+ """
+ 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 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]
+ 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):
+ 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):
+ 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):
return collections.OrderedDict((
('name', self.name),
@@ -68,15 +223,16 @@ 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:
- final, value = utils.coerce_value(container, self.value,
- report_issues)
- # TODO: final?
- self.value = value
+ 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()
@@ -212,7 +368,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):
@@ -261,7 +417,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/6f349dd7/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index b293535..3ef91d6 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -261,16 +261,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()
@@ -678,13 +678,13 @@ class NodeBase(InstanceModelMixin):
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.attributes, 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()
@@ -808,9 +808,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()
@@ -927,8 +927,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()
@@ -1028,8 +1028,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()
@@ -1132,7 +1132,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):
@@ -1320,9 +1320,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()
@@ -1460,8 +1460,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()
@@ -1607,9 +1607,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()
@@ -1774,8 +1774,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()
@@ -1914,8 +1914,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/6f349dd7/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 48eeb83..ec9bed1 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -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()
@@ -585,13 +585,13 @@ class NodeTemplateBase(TemplateModelMixin):
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.attributes, 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()
@@ -731,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()
@@ -862,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()
@@ -956,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()
@@ -1060,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):
@@ -1295,9 +1295,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()
@@ -1428,9 +1428,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()
@@ -1585,8 +1585,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()
@@ -1739,9 +1739,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()
@@ -1893,7 +1893,7 @@ class OperationTemplateBase(TemplateModelMixin):
plugin = None
implementation = None
else:
- # using the execution plugin
+ # Using the execution plugin
plugin = None
implementation = self.implementation
@@ -1914,8 +1914,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()
@@ -2062,8 +2062,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()
@@ -2139,7 +2139,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/6f349dd7/aria/modeling/utils.py
----------------------------------------------------------------------
diff --git a/aria/modeling/utils.py b/aria/modeling/utils.py
index 7be20d6..c786965 100644
--- a/aria/modeling/utils.py
+++ b/aria/modeling/utils.py
@@ -19,8 +19,6 @@ from StringIO import StringIO
from . import exceptions
from ..parser.consumption import ConsumptionContext
-from ..parser.exceptions import InvalidValueError
-from ..utils.collections import OrderedDict
from ..utils.console import puts
from ..utils.type import validate_value_type
@@ -108,52 +106,17 @@ def _merge_and_validate_inputs(inputs, template_inputs):
return merged_inputs
-def coerce_value(container, value, report_issues=False):
- final = True
-
- if isinstance(value, list):
- coerced_list = []
- for v in value:
- child_final, v = coerce_value(container, v, report_issues)
- if not child_final:
- final = False
- coerced_list.append(v)
- value = coerced_list
- elif isinstance(value, dict):
- coerced_dict = OrderedDict()
- for k, v in value.iteritems():
- child_final, v = coerce_value(container, v, report_issues)
- if not child_final:
- final = False
- coerced_dict[k] = v
- value = coerced_dict
- elif hasattr(value, '_evaluate'):
- context = ConsumptionContext.get_thread_local()
- try:
- final, value = value._evaluate(context, container)
- child_final, value = coerce_value(container, value, report_issues)
- if not child_final:
- final = False
- except exceptions.CannotEvaluateFunctionException:
- final = False
- except InvalidValueError as e:
- if report_issues:
- context.validation.report(e.issue)
-
- return final, 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/6f349dd7/aria/parser/consumption/__init__.py
----------------------------------------------------------------------
diff --git a/aria/parser/consumption/__init__.py b/aria/parser/consumption/__init__.py
index 8f6d2b6..97b3db4 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'
+ 'CoerceServiceInstanceValues'
)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/6f349dd7/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/6f349dd7/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
index 125452e..c698953 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/functions.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/functions.py
@@ -18,10 +18,12 @@ 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.consumption import ConsumptionContext
from aria.parser.exceptions import InvalidValueError
from aria.parser.validation import Issue
from aria.modeling.exceptions import CannotEvaluateFunctionException
-from aria.modeling.functions import Function
+from aria.modeling.models import Parameter
+from aria.modeling.functions import (Function, Evaluation)
#
@@ -59,16 +61,16 @@ class Concat(Function):
string_expressions.append(string_expression)
return {'concat': string_expressions}
- def _evaluate(self, context, container):
+ def __evaluate__(self, container_holder):
final = True
value = StringIO()
for e in self.string_expressions:
- if hasattr(e, '_evaluate'):
- child_final, e = e._evaluate(context, container)
- if not child_final:
+ if hasattr(e, '__evaluate__'):
+ e = e.__evaluate__(container_holder)
+ if not e.final:
final = False
value.write(str(e))
- return final, value.getvalue()
+ return Evaluation(value.getvalue(), final)
@dsl_specification('4.3.2', 'tosca-simple-1.0')
@@ -104,10 +106,10 @@ class Token(Function):
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):
+ def __evaluate__(self, container_holder):
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
+ if hasattr(string_with_tokens, '__evaluate__'):
+ string_with_tokens = string_with_tokens.__evaluate__(container_holder) # pylint: disable=no-member
# TODO
#
@@ -141,13 +143,18 @@ class GetInput(Function):
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:
+ def __evaluate__(self, container_holder):
+ if not isinstance(container_holder, Parameter):
raise CannotEvaluateFunctionException()
- the_input = context.modeling.instance.inputs.get(
- self.input_property_name,
- context.modeling.template.inputs.get(self.input_property_name))
- return True, (as_raw(the_input.value) if the_input is not None else None)
+
+ service = container_holder.service
+ if service is None:
+ raise CannotEvaluateFunctionException()
+
+ the_input = service.inputs.get(self.input_property_name)
+ if the_input is not None:
+ the_input = as_raw(the_input.value)
+ return Evaluation(the_input, False)
@dsl_specification('4.4.2', 'tosca-simple-1.0')
@@ -175,8 +182,9 @@ class GetProperty(Function):
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,
+ def __evaluate__(self, container_holder):
+ context = ConsumptionContext.get_thread_local()
+ modelable_entities = get_modelable_entities(context, container_holder, self.locator,
self.modelable_entity_name)
req_or_cap_name = self.nested_property_name_or_index[0]
@@ -203,10 +211,10 @@ class GetProperty(Function):
properties = modelable_entity.properties
nested_property_name_or_index = self.nested_property_name_or_index
- found, final, value = get_modelable_entity_parameter(context, modelable_entity, properties,
- nested_property_name_or_index)
- if found:
- return final, as_raw(value.value)
+ evaluation = get_modelable_entity_parameter(context, modelable_entity, properties,
+ nested_property_name_or_index)
+ if evaluation is not None:
+ return evaluation
raise InvalidValueError(
'function "get_property" could not find "{0}" in modelable entity "{1}"'
@@ -243,25 +251,24 @@ class GetAttribute(Function):
def as_raw(self):
return {'get_attribute': [self.modelable_entity_name] + self.nested_attribute_name_or_index}
- def _evaluate(self, context, container): # pylint: disable=no-self-use,unused-argument
- raise CannotEvaluateFunctionException()
-
- modelable_entities = get_modelable_entities(context, container, self.locator,
+ def __evaluate__(self, container_holder):
+ modelable_entities = get_modelable_entities(container_holder, self.locator,
self.modelable_entity_name)
for modelable_entity in modelable_entities:
attributes = modelable_entity.attributes
nested_attribute_name_or_index = self.nested_attribute_name_or_index
-
- found, value = get_modelable_entity_parameter(context, modelable_entity, attributes,
- nested_attribute_name_or_index)
- if found:
- return False, as_raw(value.value)
+ evaluation = get_modelable_entity_parameter(modelable_entity, attributes,
+ nested_attribute_name_or_index)
+ if evaluation is not None:
+ evaluation.final = False # We never return final evaluations!
+ return evaluation
raise InvalidValueError(
'function "get_attribute" could not find "{0}" in modelable entity "{1}"'
.format('.'.join(self.nested_attribute_name_or_index), self.modelable_entity_name),
locator=self.locator)
+
#
# Operation
#
@@ -340,7 +347,7 @@ class GetNodesOfType(Function):
node_type_name = as_raw(node_type_name)
return {'get_nodes_of_type': node_type_name}
- def _evaluate(self, context, container):
+ def __evaluate__(self, container):
pass
@@ -477,20 +484,20 @@ def parse_self(presentation):
@dsl_specification('4.1', 'tosca-simple-1.0')
-def get_modelable_entities(context, container, locator, modelable_entity_name):
+def get_modelable_entities(container_holder, 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)
+ return get_self(container_holder)
elif modelable_entity_name == 'HOST':
- return get_hosts(context, container)
+ return get_hosts(container_holder)
elif modelable_entity_name == 'SOURCE':
- return get_source(context, container)
+ return get_source(container_holder)
elif modelable_entity_name == 'TARGET':
- return get_target(context, container)
+ return get_target(container_holder)
elif isinstance(modelable_entity_name, basestring):
node_templates = \
context.presentation.get('service_template', 'topology_template', 'node_templates') \
@@ -509,16 +516,16 @@ def get_modelable_entities(context, container, locator, modelable_entity_name):
locator=locator)
-def get_self(context, container): # pylint: disable=unused-argument
+def get_self(container_holder):
"""
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]
+ return [container_holder.container]
-def get_hosts(context, container): # pylint: disable=unused-argument
+def get_hosts(container_holder): # 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).
@@ -533,7 +540,7 @@ def get_hosts(context, container): # pylint: disable=unused-argument
return []
-def get_source(context, container): # pylint: disable=unused-argument
+def get_source(container_holder): # 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.
@@ -542,15 +549,14 @@ def get_source(context, container): # pylint: disable=unused-argument
return []
-def get_target(context, container): # pylint: disable=unused-argument
+def get_target(container_holder): # 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 get_modelable_entity_parameter(context, modelable_entity, parameters,
- nested_parameter_name_or_index):
+def get_modelable_entity_parameter(modelable_entity, parameters, nested_parameter_name_or_index):
if not parameters:
return False, True, None
@@ -561,16 +567,17 @@ def get_modelable_entity_parameter(context, modelable_entity, parameters,
for name in nested_parameter_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'):
- child_final, value = value._evaluate(context, modelable_entity)
- if not child_final:
+ value = value[name].value
+ if hasattr(value, '__evaluate__'):
+ evaluation = value.__evaluate__(modelable_entity)
+ value = evaluation.value
+ if not evaluation.final:
final = False
else:
found = False
break
- return found, final, value
+ return Evaluation(value, final) if found else None
def invalid_modelable_entity_name(name, index, value, locator, contexts):
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/6f349dd7/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 945f795..c7e1a58 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -591,8 +591,8 @@ def create_constraint_clause_lambda(context, node_filter, constraint_clause, pro
def coerce_constraint(constraint, container):
constraint = coerce_value(context, node_filter, the_type, None, None, constraint,
constraint_key) if the_type is not None else constraint
- if hasattr(constraint, '_evaluate'):
- constraint = constraint._evaluate(context, container)
+ if hasattr(constraint, '__evaluate__'):
+ constraint = constraint.__evaluate__(container).value
return constraint
def get_value(node_type):
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/6f349dd7/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
----------------------------------------------------------------------
diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
index 6c7b780..8bf45e0 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/data_types.py
@@ -371,6 +371,8 @@ def coerce_value(context, presentation, the_type, entry_schema, constraints, val
If the extension is present, we will delegate to that hook.
"""
+ # TODO: should support models as well as presentations
+
is_function, func = get_function(context, presentation, value)
if is_function:
return func