You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by av...@apache.org on 2017/06/01 14:10:29 UTC
[13/16] incubator-ariatosca git commit: Add attribute model and
attribute many-to-one relationships
Add attribute model and attribute many-to-one relationships
To node template and node.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/93c01b9e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/93c01b9e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/93c01b9e
Branch: refs/heads/ARIA-180-convert-parameter-to-one-to-many
Commit: 93c01b9e672f5588b0a5dfeca0e060086d19df2d
Parents: 3e56278
Author: Avia Efrat <av...@gigaspaces.com>
Authored: Thu May 25 01:04:11 2017 +0300
Committer: Avia Efrat <av...@gigaspaces.com>
Committed: Thu Jun 1 12:05:17 2017 +0300
----------------------------------------------------------------------
aria/modeling/models.py | 12 +-
aria/modeling/service_common.py | 221 +++++++++++++++++++
aria/modeling/service_instance.py | 14 +-
aria/modeling/service_template.py | 12 +-
.../simple_v1_0/modeling/__init__.py | 10 +-
5 files changed, 240 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c01b9e/aria/modeling/models.py
----------------------------------------------------------------------
diff --git a/aria/modeling/models.py b/aria/modeling/models.py
index 6d43327..9b7e776 100644
--- a/aria/modeling/models.py
+++ b/aria/modeling/models.py
@@ -76,6 +76,7 @@ __all__ = (
'Input',
'Output',
'Property',
+ 'Attribute',
'Type',
'Metadata',
@@ -214,20 +215,18 @@ class Parameter(aria_declarative_base, service_common.ParameterBase):
class Input(aria_declarative_base, service_common.InputBase):
- # Temporarily, until we will separate the Parameter model into Input, Output, Property and
- # Attribute, Parameter will represent only Attribute.
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 only Attribute.
pass
class Property(aria_declarative_base, service_common.PropertyBase):
- # Temporarily, until we will separate the Parameter model into Input, Output, Property and
- # Attribute, Parameter will represent only Attribute.
+ pass
+
+
+class Attribute(aria_declarative_base, service_common.AttributeBase):
pass
@@ -301,6 +300,7 @@ models_to_register = [
Input,
Output,
Property,
+ Attribute,
Type,
Metadata,
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c01b9e/aria/modeling/service_common.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py
index 11f9d01..0a452dc 100644
--- a/aria/modeling/service_common.py
+++ b/aria/modeling/service_common.py
@@ -1150,6 +1150,227 @@ class PropertyBase(TemplateModelMixin, caching.HasCachedMethods):
description=description)
+class AttributeBase(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__ = 'attribute'
+
+ 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
+
+ # region foreign keys
+
+ @declared_attr
+ def node_template_fk(cls):
+ """For Attribute many-to-one to NodeTemplate"""
+ return relationship.foreign_key('node_template', nullable=True)
+
+ @declared_attr
+ def node_fk(cls):
+ """For Attribute many-to-one to Node"""
+ return relationship.foreign_key('node', nullable=True)
+
+ # endregion
+
+ # region many_to_one relationships
+
+ @declared_attr
+ def node_template(cls):
+ return relationship.many_to_one(cls, 'node_template')
+
+ @declared_attr
+ def node(cls):
+ return relationship.many_to_one(cls, 'node')
+
+ # endregion
+
+ @property
+ @caching.cachedmethod
+ def owner(self):
+ """
+ The sole owner of this attribute, 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 # because we are many-to-many, the back reference will be a list
+
+ raise ValueError('orphaned attribute: 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 attribute, 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 attribute: 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.Attribute(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.Attribute(name=name, # pylint: disable=unexpected-keyword-arg
+ type_name=type_name,
+ value=value,
+ description=description)
+
+
class MetadataBase(TemplateModelMixin):
"""
Custom values associated with the service.
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c01b9e/aria/modeling/service_instance.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py
index e6fbc6c..6a6fa86 100644
--- a/aria/modeling/service_instance.py
+++ b/aria/modeling/service_instance.py
@@ -338,7 +338,7 @@ class NodeBase(InstanceModelMixin):
:ivar host: Host node (can be self)
:vartype host: :class:`Node`
:ivar state: The state of the node, according to to the TOSCA-defined node states
- :vartype state: string
+ :vartype stateg: string
:ivar version: Used by `aria.storage.instrumentation`
:vartype version: int
:ivar service: Containing service
@@ -469,6 +469,10 @@ class NodeBase(InstanceModelMixin):
return relationship.one_to_many(cls, 'property', dict_key='name')
@declared_attr
+ def attributes(cls):
+ return relationship.one_to_many(cls, 'attribute', dict_key='name')
+
+ @declared_attr
def artifacts(cls):
return relationship.one_to_many(cls, 'artifact', dict_key='name')
@@ -514,14 +518,6 @@ class NodeBase(InstanceModelMixin):
# endregion
- # region many_to_many relationships
-
- @declared_attr
- def attributes(cls):
- return relationship.many_to_many(cls, 'parameter', prefix='attributes', dict_key='name')
-
- # endregion
-
description = Column(Text)
state = Column(Enum(*STATES, name='node_state'), nullable=False, default=INITIAL)
version = Column(Integer, default=1)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c01b9e/aria/modeling/service_template.py
----------------------------------------------------------------------
diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py
index 9ddaae8..663e75b 100644
--- a/aria/modeling/service_template.py
+++ b/aria/modeling/service_template.py
@@ -499,6 +499,10 @@ class NodeTemplateBase(TemplateModelMixin):
def properties(cls):
return relationship.one_to_many(cls, 'property', dict_key='name')
+ @declared_attr
+ def attributes(cls):
+ return relationship.one_to_many(cls, 'attribute', dict_key='name')
+
# endregion
# region many_to_one relationships
@@ -513,14 +517,6 @@ class NodeTemplateBase(TemplateModelMixin):
# endregion
- # region many_to_many relationships
-
- @declared_attr
- def attributes(cls):
- return relationship.many_to_many(cls, 'parameter', prefix='attributes', dict_key='name')
-
- # endregion
-
description = Column(Text)
default_instances = Column(Integer, default=1)
min_instances = Column(Integer, default=0)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/93c01b9e/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 dec5f26..c09a2e7 100644
--- a/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
+++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/__init__.py
@@ -37,7 +37,7 @@ from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate,
GroupTemplate, PolicyTemplate, SubstitutionTemplate,
SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate,
ArtifactTemplate, Metadata, Parameter, Input, Output, Property,
- PluginSpecification)
+ Attribute, PluginSpecification)
from .parameters import coerce_parameter_value
from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange,
@@ -178,7 +178,8 @@ def create_node_template_model(context, service_template, node_template):
node_template._get_property_values(context),
model_class=Property)
create_parameter_models_from_values(model.attributes,
- node_template._get_attribute_default_values(context))
+ node_template._get_attribute_default_values(context),
+ model_class=Attribute)
create_interface_template_models(context, service_template, model.interface_templates,
node_template._get_interfaces(context))
@@ -248,7 +249,7 @@ def create_policy_template_model(context, service_template, policy):
model.description = policy.description.value
create_parameter_models_from_values(model.properties, policy._get_property_values(context),
- Property)
+ model_class=Property)
node_templates, groups = policy._get_targets(context)
if node_templates:
@@ -579,9 +580,6 @@ def create_types(context, root, types):
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] = model_class(name=property_name, # pylint: disable=unexpected-keyword-arg