Repository: incubator-ariatosca Updated Branches: refs/heads/ARIA-180-convert-parameter-to-one-to-many ee747ef4e -> 33ff7f55c
Add property 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/33ff7f55 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/33ff7f55 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/33ff7f55 Branch: refs/heads/ARIA-180-convert-parameter-to-one-to-many Commit: 33ff7f55cd85eae21a94afd95a2ad2f46b9c5a18 Parents: ee747ef Author: Avia Efrat <a...@gigaspaces.com> Authored: Mon May 22 12:05:30 2017 +0300 Committer: Avia Efrat <a...@gigaspaces.com> Committed: Mon May 22 12:05:30 2017 +0300 ---------------------------------------------------------------------- aria/modeling/models.py | 16 +- aria/modeling/service_common.py | 238 ++++++++++++++++++- aria/modeling/service_instance.py | 24 +- aria/modeling/service_template.py | 24 +- .../simple_v1_0/modeling/__init__.py | 22 +- 5 files changed, 285 insertions(+), 39 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/33ff7f55/aria/modeling/models.py ---------------------------------------------------------------------- diff --git a/aria/modeling/models.py b/aria/modeling/models.py index d7b417b..6d43327 100644 --- a/aria/modeling/models.py +++ b/aria/modeling/models.py @@ -73,8 +73,9 @@ __all__ = ( # Common service models 'Parameter', - 'Input' - 'Output' + 'Input', + 'Output', + 'Property', 'Type', 'Metadata', @@ -214,13 +215,19 @@ 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 Property and Attribute. + # 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 Property and Attribute. + # 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 @@ -293,6 +300,7 @@ models_to_register = [ Parameter, Input, Output, + Property, Type, Metadata, http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/33ff7f55/aria/modeling/service_common.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_common.py b/aria/modeling/service_common.py index 0652a5a..0487cab 100644 --- a/aria/modeling/service_common.py +++ b/aria/modeling/service_common.py @@ -228,7 +228,7 @@ class ParameterBase(TemplateModelMixin, caching.HasCachedMethods): description=description) -# TODO dry this code. currently it is a copy of ParameterBase +# TODO dry this code. currently it is almost a copy of ParameterBase class OutputBase(TemplateModelMixin, caching.HasCachedMethods): """ Represents a typed value. The value can contain nested intrinsic functions. @@ -532,7 +532,7 @@ class TypeBase(InstanceModelMixin): return [self] + (self.parent.hierarchy if self.parent else []) -# TODO dry this code. currently it is a copy of ParameterBase +# TODO dry this code. currently it is almost a copy of ParameterBase class InputBase(TemplateModelMixin, caching.HasCachedMethods): """ Represents a typed value. The value can contain nested intrinsic functions. @@ -765,3 +765,237 @@ class MetadataBase(TemplateModelMixin): console.puts('{0}: {1}'.format( context.style.property(self.name), context.style.literal(self.value))) + + +# TODO dry this code. currently it is almost a copy of ParameterBase +class PropertyBase(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__ = 'property' + + 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 property: 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 property: 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.Property(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: Input name + :type name: basestring + :param value: Input 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.Property(name=name, # pylint: disable=unexpected-keyword-arg + type_name=type_name, + value=value, + description=description) + + +class MetadataBase(TemplateModelMixin): + """ + Custom values associated with the service. + + This model is used by both service template and service instance elements. + + :ivar name: Name + :vartype name: basestring + :ivar value: Value + :vartype value: basestring + """ + + __tablename__ = 'metadata' + + value = Column(Text) + + @property + def as_raw(self): + return collections.OrderedDict(( + ('name', self.name), + ('value', self.value))) + + def coerce_values(self, report_issues): + pass + + def instantiate(self, container): + from . import models + return models.Metadata(name=self.name, + value=self.value) + + def dump(self): + context = ConsumptionContext.get_thread_local() + console.puts('{0}: {1}'.format( + context.style.property(self.name), + context.style.literal(self.value))) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/33ff7f55/aria/modeling/service_instance.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_instance.py b/aria/modeling/service_instance.py index f3f0f99..64e64d3 100644 --- a/aria/modeling/service_instance.py +++ b/aria/modeling/service_instance.py @@ -320,7 +320,7 @@ class NodeBase(InstanceModelMixin): :ivar description: Human-readable description :vartype description: string :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar interfaces: Bundles of operations :vartype interfaces: {basestring: :class:`Interface`} :ivar artifacts: Associated files @@ -511,7 +511,7 @@ class NodeBase(InstanceModelMixin): # region many_to_many relationships @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') @declared_attr def attributes(cls): @@ -712,7 +712,7 @@ class GroupBase(InstanceModelMixin): :ivar nodes: Members of this group :vartype nodes: [:class:`Node`] :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar interfaces: Bundles of operations :vartype interfaces: {basestring: :class:`Interface`} :ivar service: Containing service @@ -784,7 +784,7 @@ class GroupBase(InstanceModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -840,7 +840,7 @@ class PolicyBase(InstanceModelMixin): :ivar groups: Policy will be enacted on all nodes in these groups :vartype groups: [:class:`Group`] :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar service: Containing service :vartype service: :class:`Service` """ @@ -900,7 +900,7 @@ class PolicyBase(InstanceModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') @declared_attr def nodes(cls): @@ -1168,7 +1168,7 @@ class RelationshipBase(InstanceModelMixin): :ivar target_capability: Capability at the target node (optional) :vartype target_capability: :class:`Capability` :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar interfaces: Bundles of operations :vartype interfaces: {basestring: :class:`Interfaces`} :ivar source_position: The position of the relationship in the outbound relationships. @@ -1292,7 +1292,7 @@ class RelationshipBase(InstanceModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -1362,7 +1362,7 @@ class CapabilityBase(InstanceModelMixin): :ivar occurrences: Actual number of requirement matches :vartype occurrences: int :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar node: Containing node :vartype node: :class:`Node` :ivar relationship: Available when we are the target of a relationship @@ -1428,7 +1428,7 @@ class CapabilityBase(InstanceModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -1830,7 +1830,7 @@ class ArtifactBase(InstanceModelMixin): :ivar repository_credential: Credentials for accessing the repository :vartype repository_credential: {basestring: basestring} :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar node: Containing node :vartype node: :class:`Node` """ @@ -1889,7 +1889,7 @@ class ArtifactBase(InstanceModelMixin): # region many_to_many relationships @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion description = Column(Text) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/33ff7f55/aria/modeling/service_template.py ---------------------------------------------------------------------- diff --git a/aria/modeling/service_template.py b/aria/modeling/service_template.py index 3341f5f..0c4ca6b 100644 --- a/aria/modeling/service_template.py +++ b/aria/modeling/service_template.py @@ -417,7 +417,7 @@ class NodeTemplateBase(TemplateModelMixin): :ivar max_instances: Maximum number nodes that will appear in the service :vartype max_instances: int :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar interface_templates: Bundles of operations :vartype interface_templates: {basestring: :class:`InterfaceTemplate`} :ivar artifact_templates: Associated files @@ -501,7 +501,7 @@ class NodeTemplateBase(TemplateModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') @declared_attr def attributes(cls): @@ -634,7 +634,7 @@ class GroupTemplateBase(TemplateModelMixin): :ivar node_templates: All nodes instantiated by these templates will be members of the group :vartype node_templates: [:class:`NodeTemplate`] :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar interface_templates: Bundles of operations :vartype interface_templates: {basestring: :class:`InterfaceTemplate`} :ivar service_template: Containing service template @@ -704,7 +704,7 @@ class GroupTemplateBase(TemplateModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -770,7 +770,7 @@ class PolicyTemplateBase(TemplateModelMixin): :ivar group_templates: Policy will be enacted on all nodes in these groups :vartype group_templates: [:class:`GroupTemplate`] :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar service_template: Containing service template :vartype service_template: :class:`ServiceTemplate` :ivar policies: Instantiated policies @@ -835,7 +835,7 @@ class PolicyTemplateBase(TemplateModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -1348,7 +1348,7 @@ class RelationshipTemplateBase(TemplateModelMixin): :ivar description: Human-readable description :vartype description: basestring :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar interface_templates: Bundles of operations :vartype interface_templates: {basestring: :class:`InterfaceTemplate`} :ivar requirement_template: Containing requirement template @@ -1402,7 +1402,7 @@ class RelationshipTemplateBase(TemplateModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -1467,7 +1467,7 @@ class CapabilityTemplateBase(TemplateModelMixin): :ivar max_occurrences: Maximum number of requirement matches allowed :vartype min_occurrences: int :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar node_template: Containing node template :vartype node_template: :class:`NodeTemplate` :ivar substitution_template_mapping: Our contribution to service substitution @@ -1532,7 +1532,7 @@ class CapabilityTemplateBase(TemplateModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', dict_key='name') # endregion @@ -1969,7 +1969,7 @@ class ArtifactTemplateBase(TemplateModelMixin): :ivar repository_credential: Credentials for accessing the repository :vartype repository_credential: {basestring: basestring} :ivar properties: Associated parameters - :vartype properties: {basestring: :class:`Parameter`} + :vartype properties: {basestring: :class:`Property`} :ivar node_template: Containing node template :vartype node_template: :class:`NodeTemplate` :ivar artifacts: Instantiated artifacts @@ -2027,7 +2027,7 @@ class ArtifactTemplateBase(TemplateModelMixin): @declared_attr def properties(cls): - return relationship.many_to_many(cls, 'parameter', prefix='properties', dict_key='name') + return relationship.many_to_many(cls, 'property', prefix='properties', dict_key='name') # endregion http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/33ff7f55/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 47cb521..18cba47 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,7 @@ from aria.modeling.models import (Type, ServiceTemplate, NodeTemplate, RequirementTemplate, RelationshipTemplate, CapabilityTemplate, GroupTemplate, PolicyTemplate, SubstitutionTemplate, SubstitutionTemplateMapping, InterfaceTemplate, OperationTemplate, - ArtifactTemplate, Metadata, Parameter, Input, Output, + ArtifactTemplate, Metadata, Parameter, Input, Output, Property, PluginSpecification) from .constraints import (Equal, GreaterThan, GreaterOrEqual, LessThan, LessOrEqual, InRange, @@ -170,7 +170,8 @@ def create_node_template_model(context, service_template, node_template): model.description = node_template.description.value create_parameter_models_from_values(model.properties, - node_template._get_property_values(context)) + node_template._get_property_values(context), + model_class=Property) create_parameter_models_from_values(model.attributes, node_template._get_attribute_default_values(context)) create_interface_template_models(context, service_template, model.interface_templates, @@ -217,7 +218,8 @@ def create_group_template_model(context, service_template, group): if group.description: model.description = group.description.value - create_parameter_models_from_values(model.properties, group._get_property_values(context)) + create_parameter_models_from_values(model.properties, group._get_property_values(context), + model_class=Property) create_interface_template_models(context, service_template, model.interface_templates, group._get_interfaces(context)) @@ -240,7 +242,8 @@ def create_policy_template_model(context, service_template, policy): if policy.description: model.description = policy.description.value - create_parameter_models_from_values(model.properties, policy._get_property_values(context)) + create_parameter_models_from_values(model.properties, policy._get_property_values(context), + Property) node_templates, groups = policy._get_targets(context) if node_templates: @@ -431,7 +434,8 @@ def create_artifact_template_model(context, service_template, artifact): for k, v in credential.iteritems(): model.repository_credential[k] = v - create_parameter_models_from_values(model.properties, artifact._get_property_values(context)) + create_parameter_models_from_values(model.properties, artifact._get_property_values(context), + model_class=Property) return model @@ -556,10 +560,10 @@ def create_parameter_models_from_values(properties, source_properties, model_cla def create_parameter_models_from_assignments(properties, source_properties): 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.value.type, - value=prop.value.value, - description=prop.value.description) + properties[property_name] = Property(name=property_name, # pylint: disable=unexpected-keyword-arg + type_name=prop.value.type, + value=prop.value.value, + description=prop.value.description) def create_interface_template_models(context, service_template, interfaces, source_interfaces):