ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a...@apache.org
Subject [3/5] incubator-ariatosca git commit: add output model
Date Wed, 24 May 2017 11:54:27 GMT
add output model


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/155a1db6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/155a1db6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/155a1db6

Branch: refs/heads/ARIA-180-convert-parameter-to-one-to-many
Commit: 155a1db69b6b5fd4ded0c7bfbce251ba9438694a
Parents: 0c98684
Author: Avia Efrat <avia@gigaspaces.com>
Authored: Sun May 21 16:28:30 2017 +0300
Committer: Avia Efrat <avia@gigaspaces.com>
Committed: Wed May 24 13:12:28 2017 +0300

----------------------------------------------------------------------
 aria/modeling/models.py                         |   9 +
 aria/modeling/relationship.py                   |   4 +-
 aria/modeling/service_common.py                 | 197 +++++++++++++++++++
 aria/modeling/service_instance.py               |   4 +-
 aria/modeling/service_template.py               |   4 +-
 examples/hello-world/helloworld.yaml            |   5 +
 .../simple_v1_0/modeling/__init__.py            |  20 +-
 7 files changed, 230 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/aria/modeling/models.py
----------------------------------------------------------------------
diff --git a/aria/modeling/models.py b/aria/modeling/models.py
index 584b877..f3acca6 100644
--- a/aria/modeling/models.py
+++ b/aria/modeling/models.py
@@ -73,6 +73,7 @@ __all__ = (
 
     # Common service models
     'Parameter',
+    'Output'
     'Type',
     'Metadata',
 
@@ -210,6 +211,13 @@ class Parameter(aria_declarative_base, service_common.ParameterBase):
     pass
 
 
+class Output(aria_declarative_base, service_common.OutputBase):
+    # Temporarily, until we will separate the Parameter model into Input, Output, Property
and
+    # Attribute, Parameter will represent Input, Property and Attribute, and Output will
represent
+    # the outputs.
+    pass
+
+
 class Type(aria_declarative_base, service_common.TypeBase):
     pass
 
@@ -277,6 +285,7 @@ models_to_register = [
 
     # Common service models
     Parameter,
+    Output,
     Type,
     Metadata,
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/aria/modeling/relationship.py
----------------------------------------------------------------------
diff --git a/aria/modeling/relationship.py b/aria/modeling/relationship.py
index 40be5b2..c4f4cf3 100644
--- a/aria/modeling/relationship.py
+++ b/aria/modeling/relationship.py
@@ -287,8 +287,8 @@ def many_to_many(model_class,
 
     if prefix is not None:
         secondary_table_name = '{0}_{1}'.format(prefix, secondary_table_name)
-        if other_property is None:
-            other_property = '{0}_{1}'.format(prefix, formatting.pluralize(this_table))
+    if other_property is None:
+        other_property = '{0}_{1}'.format(prefix, formatting.pluralize(this_table))
 
     secondary_table = _get_secondary_table(
         model_class.metadata,

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index e9c96a4..05698b6 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -228,6 +228,203 @@ class ParameterBase(TemplateModelMixin, caching.HasCachedMethods):
                                 description=description)
 
 
+# TODO dry this code. currently it is a copy of ParameterBase
+class OutputBase(TemplateModelMixin, caching.HasCachedMethods):
+    """
+    Represents a typed value. The value can contain nested intrinsic functions.
+
+    This model can be used as the ``container_holder`` argument for :func:`functions.evaluate`.
+
+    :ivar name: Name
+    :vartype name: basestring
+    :ivar type_name: Type name
+    :vartype type_name: basestring
+    :ivar value: Value
+    :ivar description: Description
+    :vartype description: basestring
+    """
+
+    __tablename__ = 'output'
+
+    name = Column(Text)
+    type_name = Column(Text)
+    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
+    @caching.cachedmethod
+    def owner(self):
+        """
+        The sole owner of this parameter, which is another model that relates to it.
+
+        *All* parameters should have an owner model. In case this property method fails to
find
+        it, it will raise a ValueError, which should signify an abnormal, orphaned parameter.
+        """
+
+        # Find first non-null relationship
+        for the_relationship in self.__mapper__.relationships:
+            v = getattr(self, the_relationship.key)
+            if v:
+                return v[0] # because we are many-to-many, the back reference will be a list
+
+        raise ValueError('orphaned output: does not have an owner: {0}'.format(self.name))
+
+
+    @property
+    @caching.cachedmethod
+    def container(self): # pylint: disable=too-many-return-statements,too-many-branches
+        """
+        The logical container for this parameter, which would be another model: service,
node,
+        group, or policy (or their templates).
+
+        The logical container is equivalent to the ``SELF`` keyword used by intrinsic functions
in
+        TOSCA.
+
+        *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.
+        """
+
+        from . import models
+
+        container = self.owner
+
+        # Extract interface from operation
+        if isinstance(container, models.Operation):
+            container = container.interface
+        elif isinstance(container, models.OperationTemplate):
+            container = container.interface_template
+
+        # Extract from other models
+        if isinstance(container, models.Interface):
+            container = container.node or container.group or container.relationship
+        elif isinstance(container, models.InterfaceTemplate):
+            container = container.node_template or container.group_template \
+                or container.relationship_template
+        elif isinstance(container, models.Capability) or isinstance(container, models.Artifact):
+            container = container.node
+        elif isinstance(container, models.CapabilityTemplate) \
+            or isinstance(container, models.ArtifactTemplate):
+            container = container.node_template
+        elif isinstance(container, models.Task):
+            container = container.actor
+
+        # Extract node from relationship
+        if isinstance(container, models.Relationship):
+            container = container.source_node
+        elif isinstance(container, models.RelationshipTemplate):
+            container = container.requirement_template.node_template
+
+        if container is not None:
+            return container
+
+        raise ValueError('orphaned output: does not have a container: {0}'.format(self.name))
+
+    @property
+    @caching.cachedmethod
+    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
+    @caching.cachedmethod
+    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):
+        return collections.OrderedDict((
+            ('name', self.name),
+            ('type_name', self.type_name),
+            ('value', self.value),
+            ('description', self.description)))
+
+    def instantiate(self, container):
+        from . import models
+        return models.Output(name=self.name,  # pylint: disable=unexpected-keyword-arg
+                             type_name=self.type_name,
+                             _value=self._value,
+                             description=self.description)
+
+    def coerce_values(self, report_issues):
+        value = self._value
+        if value is not None:
+            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(formatting.as_raw(self.value)),
+                context.style.type(self.type_name)))
+        else:
+            console.puts('{0}: {1}'.format(
+                context.style.property(self.name),
+                context.style.literal(formatting.as_raw(self.value))))
+        if self.description:
+            console.puts(context.style.meta(self.description))
+
+    def unwrap(self):
+        return self.name, self.value
+
+    @classmethod
+    def wrap(cls, name, value, description=None):
+        """
+        Wraps an arbitrary value as a parameter. The type will be guessed via introspection.
+
+        :param name: Parameter name
+        :type name: basestring
+        :param value: Parameter value
+        :param description: Description (optional)
+        :type description: basestring
+        """
+
+        from . import models
+        type_name = canonical_type_name(value)
+        if type_name is None:
+            type_name = full_type_name(value)
+        return models.Output(name=name, # pylint: disable=unexpected-keyword-arg
+                             type_name=type_name,
+                             value=value,
+                             description=description)
+
+
 class TypeBase(InstanceModelMixin):
     """
     Represents a type and its children.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index 41a388d..4236caa 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -65,7 +65,7 @@ class ServiceBase(InstanceModelMixin):
     :ivar inputs: Externally provided parameters
     :vartype inputs: {basestring: :class:`Parameter`}
     :ivar outputs: These parameters are filled in after service installation
-    :vartype outputs: {basestring: :class:`Parameter`}
+    :vartype outputs: {basestring: :class:`Output`}
     :ivar workflows: Custom workflows that can be performed on the service
     :vartype workflows: {basestring: :class:`Operation`}
     :ivar plugins: Plugins used by the service
@@ -171,7 +171,7 @@ class ServiceBase(InstanceModelMixin):
 
     @declared_attr
     def outputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
+        return relationship.many_to_many(cls, 'output', dict_key='name')
 
     @declared_attr
     def plugins(cls):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 12195a1..91998e3 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -69,7 +69,7 @@ class ServiceTemplateBase(TemplateModelMixin):
     :ivar inputs: Externally provided parameters
     :vartype inputs: {basestring: :class:`Parameter`}
     :ivar outputs: These parameters are filled in after service installation
-    :vartype outputs: {basestring: :class:`Parameter`}
+    :vartype outputs: {basestring: :class:`Output`}
     :ivar workflow_templates: Custom workflows that can be performed on the service
     :vartype workflow_templates: {basestring: :class:`OperationTemplate`}
     :ivar plugin_specifications: Plugins used by the service
@@ -249,7 +249,7 @@ class ServiceTemplateBase(TemplateModelMixin):
 
     @declared_attr
     def outputs(cls):
-        return relationship.many_to_many(cls, 'parameter', prefix='outputs', dict_key='name')
+        return relationship.many_to_many(cls, 'output', dict_key='name')
 
     # endregion
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/examples/hello-world/helloworld.yaml
----------------------------------------------------------------------
diff --git a/examples/hello-world/helloworld.yaml b/examples/hello-world/helloworld.yaml
index 77cef30..55c5030 100644
--- a/examples/hello-world/helloworld.yaml
+++ b/examples/hello-world/helloworld.yaml
@@ -30,3 +30,8 @@ topology_template:
           configure: scripts/configure.sh
           start: scripts/start.sh
           stop: scripts/stop.sh
+
+  outputs:
+    test_output:
+      description: description_of_test_output
+      value: value_of_test_output

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/155a1db6/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 99389e4..1769ce5 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -32,7 +32,8 @@ from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate,
                                   RequirementTemplate, RelationshipTemplate, CapabilityTemplate,
                                   GroupTemplate, PolicyTemplate, SubstitutionTemplate,
                                   SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate,
-                                  ArtifactTemplate, Metadata, Parameter, PluginSpecification)
+                                  ArtifactTemplate, Metadata, Parameter, Output,
+                                  PluginSpecification)
 
 from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange,
                           ValidValues, Length, MinLength, MaxLength, Pattern)
@@ -91,7 +92,8 @@ def create_service_template_model(context): # pylint: disable=too-many-locals,to
         create_parameter_models_from_values(model.inputs,
                                             topology_template._get_input_values(context))
         create_parameter_models_from_values(model.outputs,
-                                            topology_template._get_output_values(context))
+                                            topology_template._get_output_values(context),
+                                            model_class=Output)
 
     # Plugin specifications
     policies = context.presentation.get('service_template', 'topology_template', 'policies')
@@ -537,13 +539,17 @@ def create_types(context, root, types):
                         container.children.append(model)
 
 
-def create_parameter_models_from_values(properties, source_properties):
+def create_parameter_models_from_values(properties, source_properties, model_class=None):
+
+    if model_class is None:
+        model_class = Parameter
+
     if source_properties:
         for property_name, prop in source_properties.iteritems():
-            properties[property_name] = Parameter(name=property_name, # pylint: disable=unexpected-keyword-arg
-                                                  type_name=prop.type,
-                                                  value=prop.value,
-                                                  description=prop.description)
+            properties[property_name] = model_class(name=property_name, # pylint: disable=unexpected-keyword-arg
+                                                    type_name=prop.type,
+                                                    value=prop.value,
+                                                    description=prop.description)
 
 
 def create_parameter_models_from_assignments(properties, source_properties):


Mime
View raw message