| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| from aria.utils.collections import FrozenDict |
| from aria.utils.caching import cachedmethod |
| from aria.parser import implements_specification |
| from aria.parser.presentation import (AsIsPresentation, has_fields, allow_unknown_fields, |
| short_form_field, primitive_field, object_field, |
| object_dict_field, object_dict_unknown_fields, |
| field_validator, type_validator) |
| |
| from .filters import NodeFilter |
| from .misc import Description, OperationImplementation |
| from .modeling.parameters import get_assigned_and_defined_parameter_values |
| from .presentation.extensible import ExtensiblePresentation |
| from .presentation.field_validators import (node_template_or_type_validator, |
| relationship_template_or_type_validator, |
| capability_definition_or_type_validator, |
| node_filter_validator) |
| from .presentation.types import (convert_name_to_full_type_name, get_type_by_name) |
| |
| |
| |
| @implements_specification('3.5.9', 'tosca-simple-1.0') |
| class PropertyAssignment(AsIsPresentation): |
| """ |
| This section defines the grammar for assigning values to named properties within TOSCA Node and |
| Relationship templates that are defined in their corresponding named types. |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ELEMENT_PROPERTY_VALUE_ASSIGNMENT>`__ |
| """ |
| |
| |
| @short_form_field('implementation') |
| @has_fields |
| @implements_specification('3.5.13-2', 'tosca-simple-1.0') |
| class OperationAssignment(ExtensiblePresentation): |
| """ |
| An operation definition defines a named function or procedure that can be bound to an |
| implementation artifact (e.g., a script). |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ELEMENT_OPERATION_DEF>`__ |
| """ |
| |
| @object_field(Description) |
| def description(self): |
| """ |
| The optional description string for the associated named operation. |
| |
| :type: :class:`Description` |
| """ |
| |
| @object_field(OperationImplementation) |
| def implementation(self): |
| """ |
| The optional implementation artifact name (e.g., a script file name within a TOSCA CSAR |
| file). |
| |
| :type: :class:`OperationImplementation` |
| """ |
| |
| @object_dict_field(PropertyAssignment) |
| def inputs(self): |
| """ |
| The optional list of input property assignments (i.e., parameters assignments) for operation |
| definitions that are within TOSCA Node or Relationship Template definitions. This includes |
| when operation definitions are included as part of a Requirement assignment in a Node |
| Template. |
| |
| :type: {:obj:`basestring`: :class:`PropertyAssignment`} |
| """ |
| |
| @cachedmethod |
| def _get_extensions(self, context): |
| def update_inherited_extensions(extensions, interface_type): |
| parent = interface_type._get_parent(context) |
| if parent is not None: |
| update_inherited_extensions(extensions, parent) |
| operation_definition = interface_type.operations.get(self._name) |
| if operation_definition is not None: |
| if operation_definition._extensions: |
| extensions.update(operation_definition._extensions) |
| |
| extensions = {} |
| update_inherited_extensions(extensions, self._container._get_type(context)) |
| if self._container._extensions: |
| extensions.update(self._container._extensions) |
| if self._extensions: |
| extensions.update(self._extensions) |
| return extensions |
| |
| |
| @allow_unknown_fields |
| @has_fields |
| @implements_specification('3.5.14-2', 'tosca-simple-1.0') |
| class InterfaceAssignment(ExtensiblePresentation): |
| """ |
| An interface definition defines a named interface that can be associated with a Node or |
| Relationship Type. |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ELEMENT_INTERFACE_DEF>`__ |
| """ |
| |
| @object_dict_field(PropertyAssignment) |
| def inputs(self): |
| """ |
| The optional list of input property assignments (i.e., parameters assignments) for interface |
| definitions that are within TOSCA Node or Relationship Template definitions. This includes |
| when interface definitions are referenced as part of a Requirement assignment in a Node |
| Template. |
| |
| :type: {:obj:`basestring`: :class:`PropertyAssignment`} |
| """ |
| |
| @object_dict_unknown_fields(OperationAssignment) |
| def operations(self): |
| """ |
| :type: {:obj:`basestring`: :class:`OperationAssignment`} |
| """ |
| |
| @cachedmethod |
| def _get_type(self, context): |
| the_type = self._container._get_type(context) |
| |
| if isinstance(the_type, tuple): |
| # In RelationshipAssignment |
| the_type = the_type[0] # This could be a RelationshipTemplate |
| |
| if isinstance(self._container._container, RequirementAssignment): |
| # In RequirementAssignment |
| relationship_definition = \ |
| self._container._container._get_relationship_definition(context) |
| interface_definitions = relationship_definition.interfaces \ |
| if relationship_definition is not None else None |
| if (interface_definitions is not None) and (self._name in interface_definitions): |
| return interface_definitions[self._name]._get_type(context) |
| |
| interface_definitions = the_type._get_interfaces(context) \ |
| if the_type is not None else None |
| interface_definition = interface_definitions.get(self._name) \ |
| if interface_definitions is not None else None |
| return interface_definition._get_type(context) \ |
| if interface_definition is not None else None |
| |
| def _validate(self, context): |
| super(InterfaceAssignment, self)._validate(context) |
| if self.operations: |
| for operation in self.operations.itervalues(): # pylint: disable=no-member |
| operation._validate(context) |
| |
| |
| @short_form_field('type') |
| @has_fields |
| class RelationshipAssignment(ExtensiblePresentation): |
| """ |
| Relationship assignment. |
| """ |
| |
| @field_validator(relationship_template_or_type_validator) |
| @primitive_field(str) |
| def type(self): |
| """ |
| The optional reserved keyname used to provide the name of the Relationship Type for the |
| requirement assignment's relationship keyname. |
| |
| ARIA NOTE: this can also be a relationship template name. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @object_dict_field(PropertyAssignment) |
| def properties(self): |
| """ |
| ARIA NOTE: This field is not mentioned in the spec, but is implied. |
| |
| :type: {:obj:`basestring`: :class:`PropertyAssignment`} |
| """ |
| |
| @object_dict_field(InterfaceAssignment) |
| def interfaces(self): |
| """ |
| The optional reserved keyname used to reference declared (named) interface definitions of |
| the corresponding Relationship Type in order to provide Property assignments for these |
| interfaces or operations of these interfaces. |
| |
| :type: {:obj:`basestring`: :class:`InterfaceAssignment`} |
| """ |
| |
| @cachedmethod |
| def _get_type(self, context): |
| type_name = self.type |
| if type_name is not None: |
| the_type = context.presentation.get_from_dict('service_template', 'topology_template', |
| 'relationship_templates', type_name) |
| if the_type is not None: |
| return the_type, 'relationship_template' |
| the_type = get_type_by_name(context, type_name, 'relationship_types') |
| if the_type is not None: |
| return the_type, 'relationship_type' |
| return None, None |
| |
| |
| @short_form_field('node') |
| @has_fields |
| @implements_specification('3.7.2', 'tosca-simple-1.0') |
| class RequirementAssignment(ExtensiblePresentation): |
| """ |
| A Requirement assignment allows template authors to provide either concrete names of TOSCA |
| templates or provide abstract selection criteria for providers to use to find matching TOSCA |
| templates that are used to fulfill a named requirement's declared TOSCA Node Type. |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ELEMENT_REQUIREMENT_ASSIGNMENT>`__ |
| """ |
| |
| # The example in 3.7.2.2.2 shows unknown fields in addition to these, but is this a mistake? |
| |
| @field_validator(capability_definition_or_type_validator) |
| @primitive_field(str) |
| def capability(self): |
| """ |
| The optional reserved keyname used to provide the name of either a: |
| |
| * Capability definition within a target node template that can fulfill the requirement. |
| * Capability Type that the provider will use to select a type-compatible target node |
| template to fulfill the requirement at runtime. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @field_validator(node_template_or_type_validator) |
| @primitive_field(str) |
| def node(self): |
| """ |
| The optional reserved keyname used to identify the target node of a relationship. |
| Specifically, it is used to provide either a: |
| |
| * Node Template name that can fulfill the target node requirement. |
| * Node Type name that the provider will use to select a type-compatible node template to |
| fulfill the requirement at runtime. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @object_field(RelationshipAssignment) |
| def relationship(self): |
| """ |
| The optional reserved keyname used to provide the name of either a: |
| |
| * Relationship Template to use to relate the source node to the (capability in the) target |
| node when fulfilling the requirement. |
| * Relationship Type that the provider will use to select a type-compatible relationship |
| template to relate the source node to the target node at runtime. |
| |
| :type: :class:`RelationshipAssignment` |
| """ |
| |
| @field_validator(node_filter_validator) |
| @object_field(NodeFilter) |
| def node_filter(self): |
| """ |
| The optional filter definition that TOSCA orchestrators or providers would use to select a |
| type-compatible target node that can fulfill the associated abstract requirement at runtime. |
| |
| :type: :class:`NodeFilter` |
| """ |
| |
| @cachedmethod |
| def _get_node(self, context): |
| node = self.node |
| |
| if node is not None: |
| node_template = context.presentation.get_from_dict('service_template', |
| 'topology_template', |
| 'node_templates', node) |
| if node_template is not None: |
| return node_template, 'node_template' |
| node_type = get_type_by_name(context, node, 'node_types') |
| if node_type is not None: |
| return node_type, 'node_type' |
| |
| return None, None |
| |
| @cachedmethod |
| def _get_definition(self, context): |
| node_type = self._container._get_type(context) |
| if (node_type is not None) and (node_type.requirements is not None): |
| for name, requirement in node_type.requirements: |
| if name == self._name: |
| return requirement |
| return None |
| |
| @cachedmethod |
| def _get_relationship_definition(self, context): |
| requirement_definition = self._get_definition(context) |
| return requirement_definition.relationship if requirement_definition is not None else None |
| |
| @cachedmethod |
| def _get_capability(self, context): |
| capability = self.capability |
| |
| if capability is not None: |
| node, node_variant = self._get_node(context) |
| if node_variant == 'node_template': |
| capabilities = node._get_capabilities(context) |
| if capability in capabilities: |
| return capabilities[capability], 'capability_assignment' |
| capability_type = get_type_by_name(context, capability, 'capability_types') |
| if capability_type is not None: |
| return capability_type, 'capability_type' |
| |
| return None, None |
| |
| |
| @implements_specification('3.5.11', 'tosca-simple-1.0') |
| class AttributeAssignment(AsIsPresentation): |
| """ |
| This section defines the grammar for assigning values to named attributes within TOSCA Node and |
| Relationship templates which are defined in their corresponding named types. |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ELEMENT_ATTRIBUTE_VALUE_ASSIGNMENT>`__ |
| """ |
| |
| |
| @has_fields |
| @implements_specification('3.7.1', 'tosca-simple-1.0') |
| class CapabilityAssignment(ExtensiblePresentation): |
| """ |
| A capability assignment allows node template authors to assign values to properties and |
| attributes for a named capability definition that is part of a Node Template's type definition. |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ELEMENT_CAPABILITY_ASSIGNMENT>`__ |
| """ |
| |
| @object_dict_field(PropertyAssignment) |
| def properties(self): |
| """ |
| An optional list of property definitions for the Capability definition. |
| |
| :type: {:obj:`basestring`: :class:`PropertyAssignment`} |
| """ |
| |
| @object_dict_field(AttributeAssignment) |
| def attributes(self): |
| """ |
| An optional list of attribute definitions for the Capability definition. |
| |
| :type: {:obj:`basestring`: :class:`AttributeAssignment`} |
| """ |
| |
| @cachedmethod |
| def _get_definition(self, context): |
| node_type = self._container._get_type(context) |
| capability_definitions = node_type._get_capabilities(context) \ |
| if node_type is not None else None |
| return capability_definitions.get(self._name) \ |
| if capability_definitions is not None else None |
| |
| @cachedmethod |
| def _get_type(self, context): |
| capability_definition = self._get_definition(context) |
| return capability_definition._get_type(context) \ |
| if capability_definition is not None else None |
| |
| |
| @has_fields |
| @implements_specification('3.5.6', 'tosca-simple-1.0') |
| class ArtifactAssignmentForType(ExtensiblePresentation): |
| """ |
| An artifact definition defines a named, typed file that can be associated with Node Type or Node |
| Template and used by orchestration engine to facilitate deployment and implementation of |
| interface operations. |
| |
| ARIA NOTE: section 3.5.6.2.1 in the spec refers to a short notation for "file", but that |
| notation would be impossible because the "type" field is required. |
| |
| See the `TOSCA Simple Profile v1.0 cos01 specification <http://docs.oasis-open.org/tosca |
| /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html |
| #DEFN_ENTITY_ARTIFACT_DEF>`__ |
| """ |
| |
| @field_validator(type_validator('artifact type', convert_name_to_full_type_name, |
| 'artifact_types')) |
| @primitive_field(str, required=True) |
| def type(self): |
| """ |
| The required artifact type for the artifact definition. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @primitive_field(str, required=True) |
| def file(self): |
| """ |
| The required URI string (relative or absolute) which can be used to locate the artifact's |
| file. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @field_validator(type_validator('repository', 'repositories')) |
| @primitive_field(str) |
| def repository(self): |
| """ |
| The optional name of the repository definition which contains the location of the external |
| repository that contains the artifact. The artifact is expected to be referenceable by its |
| file URI within the repository. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @object_field(Description) |
| def description(self): |
| """ |
| The optional description for the artifact definition. |
| |
| :type: :class:`Description` |
| """ |
| |
| @primitive_field(str) |
| def deploy_path(self): |
| """ |
| The file path the associated file would be deployed into within the target node's container. |
| |
| :type: :obj:`basestring` |
| """ |
| |
| @object_dict_field(PropertyAssignment) |
| def properties(self): |
| """ |
| ARIA NOTE: This field is not mentioned in the spec, but is implied. |
| |
| :type: {:obj:`basestring`: :class:`PropertyAssignment`} |
| """ |
| |
| @cachedmethod |
| def _get_type(self, context): |
| return get_type_by_name(context, self.type, 'artifact_types') |
| |
| @cachedmethod |
| def _get_repository(self, context): |
| return context.presentation.get_from_dict('service_template', 'repositories', |
| self.repository) |
| |
| @cachedmethod |
| def _get_property_values(self, context): |
| return FrozenDict(get_assigned_and_defined_parameter_values(context, self, 'property')) |
| |
| @cachedmethod |
| def _validate(self, context): |
| super(ArtifactAssignmentForType, self)._validate(context) |
| |
| |
| class ArtifactAssignment(ArtifactAssignmentForType): |
| @cachedmethod |
| def _validate(self, context): |
| super(ArtifactAssignment, self)._validate(context) |
| self._get_property_values(context) |