blob: a7e2806a14442d45db22cfdac24acdc84857065e [file] [log] [blame]
# 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.utils.formatting import safe_repr
from aria.parser import implements_specification
from aria.parser.validation import Issue
from aria.parser.presentation import (has_fields, short_form_field, allow_unknown_fields,
primitive_field, primitive_list_field, object_field,
object_list_field, object_dict_field,
object_dict_unknown_fields, field_validator,
field_getter, type_validator, list_type_validator)
from .data_types import Range
from .misc import (Description, ConstraintClause, OperationImplementation, EntrySchema)
from .presentation.extensible import ExtensiblePresentation
from .presentation.field_getters import data_type_class_getter
from .presentation.field_validators import (data_type_validator, data_value_validator,
entry_schema_validator)
from .presentation.types import (convert_name_to_full_type_name, get_type_by_name)
from .modeling.data_types import get_data_type, get_property_constraints
from .modeling.interfaces import (get_and_override_input_definitions_from_type,
get_and_override_operation_definitions_from_type)
@has_fields
@implements_specification('3.5.8', 'tosca-simple-1.0')
class PropertyDefinition(ExtensiblePresentation):
"""
A property definition defines a named, typed value and related data that can be associated with
an entity defined in this specification (e.g., Node Types, Relationship Types, Capability Types,
etc.). Properties are used by template authors to provide input values to TOSCA entities which
indicate their "desired state" when they are instantiated. The value of a property can be
retrieved using the ``get_property`` function within TOSCA Service Templates.
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_DEFN>`__
"""
@field_validator(data_type_validator())
@primitive_field(str, required=True)
def type(self):
"""
The required data type for the property.
:type: :obj:`basestring`
"""
@object_field(Description)
def description(self):
"""
The optional description for the property.
:type: :class:`Description`
"""
@primitive_field(bool, default=True)
def required(self):
"""
An optional key that declares a property as required (true) or not (false).
:type: bool
"""
@field_validator(data_value_validator)
@primitive_field()
def default(self):
"""
An optional key that may provide a value to be used as a default if not provided by another
means.
:type: :obj:`basestring`
"""
@primitive_field(str, default='supported', allowed=('supported', 'unsupported', 'experimental',
'deprecated'))
@implements_specification(section='3.5.8.3', spec='tosca-simple-1.0')
def status(self):
"""
The optional status of the property relative to the specification or implementation.
:type: :obj:`basestring`
"""
@object_list_field(ConstraintClause)
def constraints(self):
"""
The optional list of sequenced constraint clauses for the property.
:type: list of (str, :class:`ConstraintClause`)
"""
@field_validator(entry_schema_validator)
@object_field(EntrySchema)
def entry_schema(self):
"""
The optional key that is used to declare the name of the Datatype definition for entries of
set types such as the TOSCA list or map.
:type: :obj:`basestring`
"""
@cachedmethod
def _get_type(self, context):
return get_data_type(context, self, 'type')
@cachedmethod
def _get_constraints(self, context):
return get_property_constraints(context, self)
@has_fields
@implements_specification('3.5.10', 'tosca-simple-1.0')
class AttributeDefinition(ExtensiblePresentation):
"""
An attribute definition defines a named, typed value that can be associated with an entity
defined in this specification (e.g., a Node, Relationship or Capability Type). Specifically, it
is used to expose the "actual state" of some property of a TOSCA entity after it has been
deployed and instantiated (as set by the TOSCA orchestrator). Attribute values can be retrieved
via the ``get_attribute`` function from the instance model and used as values to other
entities within TOSCA Service Templates.
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_DEFN>`__
"""
@field_validator(data_type_validator())
@primitive_field(str, required=True)
def type(self):
"""
The required data type for the attribute.
:type: :obj:`basestring`
"""
@object_field(Description)
def description(self):
"""
The optional description for the attribute.
:type: :class:`Description`
"""
@field_validator(data_value_validator)
@primitive_field()
def default(self):
"""
An optional key that may provide a value to be used as a default if not provided by another
means.
This value SHALL be type compatible with the type declared by the property definition's type
keyname.
:type: :obj:`basestring`
"""
@primitive_field(str, default='supported', allowed=('supported', 'unsupported', 'experimental',
'deprecated'))
def status(self):
"""
The optional status of the attribute relative to the specification or implementation.
:type: :obj:`basestring`
"""
@field_validator(entry_schema_validator)
@object_field(EntrySchema)
def entry_schema(self):
"""
The optional key that is used to declare the name of the Datatype definition for entries of
set types such as the TOSCA list or map.
:type: :obj:`basestring`
"""
@cachedmethod
def _get_type(self, context):
return get_data_type(context, self, 'type')
@has_fields
@implements_specification('3.5.12-1', 'tosca-simple-1.0')
class InputDefinition(PropertyDefinition):
"""
A parameter definition is essentially a TOSCA property definition; however, it also allows a
value to be assigned to it (as for a TOSCA property assignment). In addition, in the case of
output parameters, it can optionally inherit the data type of the value assigned to it rather
than have an explicit data type defined for it.
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_PARAMETER_DEF>`__
"""
@field_validator(data_value_validator)
@primitive_field()
def value(self):
"""
The type-compatible value to assign to the named parameter. Parameter values may be provided
as the result from the evaluation of an expression or a function.
"""
@has_fields
@implements_specification('3.5.12-2', 'tosca-simple-1.0')
class OutputDefinition(InputDefinition):
@field_validator(data_type_validator())
@primitive_field(str)
def type(self):
"""
The required data type for the parameter.
Note: This keyname is required for a TOSCA Property definition, but is not for a TOSCA
Parameter definition.
ARIA NOTE: the spec must be mistaken: inputs should have this field requires, only outputs
have it as optional.
:type: :obj:`basestring`
"""
@short_form_field('implementation')
@has_fields
@implements_specification('3.5.13-1', 'tosca-simple-1.0')
class OperationDefinition(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(PropertyDefinition)
def inputs(self):
"""
The optional list of input property definitions available to all defined operations for
interface definitions that are within TOSCA Node or Relationship Type definitions. This
includes when interface definitions are included as part of a Requirement definition in a
Node Type.
:type: {:obj:`basestring`: :class:`PropertyDefinition`}
"""
@allow_unknown_fields
@has_fields
@implements_specification('3.5.14-1', 'tosca-simple-1.0')
class InterfaceDefinition(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>`__
"""
@field_validator(type_validator('interface type', convert_name_to_full_type_name,
'interface_types'))
@primitive_field(str, required=True)
def type(self):
"""
ARIA NOTE: This field is not mentioned in the spec, but is implied.
:type: :obj:`basestring`
"""
@object_dict_field(PropertyDefinition)
def inputs(self):
"""
The optional list of input property definitions available to all defined operations for
interface definitions that are within TOSCA Node or Relationship Type definitions. This
includes when interface definitions are included as part of a Requirement definition in a
Node Type.
:type: {:obj:`basestring`: :class:`PropertyDefinition`}
"""
@object_dict_unknown_fields(OperationDefinition)
def operations(self):
"""
:type: {:obj:`basestring`: :class:`OperationDefinition`}
"""
@cachedmethod
def _get_type(self, context):
return get_type_by_name(context, self.type, 'interface_types')
@cachedmethod
def _get_inputs(self, context):
return FrozenDict(get_and_override_input_definitions_from_type(context, self))
@cachedmethod
def _get_operations(self, context):
return FrozenDict(get_and_override_operation_definitions_from_type(context, self))
def _validate(self, context):
super(InterfaceDefinition, self)._validate(context)
self._get_inputs(context)
self._get_operations(context)
@short_form_field('type')
@has_fields
class RelationshipDefinition(ExtensiblePresentation):
"""
Relationship definition.
"""
@field_validator(type_validator('relationship type', convert_name_to_full_type_name,
'relationship_types'))
@primitive_field(str, required=True)
def type(self):
"""
The optional reserved keyname used to provide the name of the Relationship Type for the
requirement definition's relationship keyname.
ARIA NOTE: the spec shows this as a required field.
:type: :obj:`basestring`
"""
@object_dict_field(InterfaceDefinition)
def interfaces(self):
"""
The optional reserved keyname used to reference declared (named) interface definitions of
the corresponding Relationship Type in order to declare additional Property definitions for
these interfaces or operations of these interfaces.
:type: list of :class:`InterfaceDefinition`
"""
@cachedmethod
def _get_type(self, context):
return get_type_by_name(context, self.type, 'relationship_types')
@short_form_field('capability')
@has_fields
@implements_specification('3.6.2', 'tosca-simple-1.0')
class RequirementDefinition(ExtensiblePresentation):
"""
The Requirement definition describes a named requirement (dependencies) of a TOSCA Node Type or
Node template which needs to be fulfilled by a matching Capability definition declared by
another TOSCA modelable entity. The requirement definition may itself include the specific name
of the fulfilling entity (explicitly) or provide an abstract type, along with additional
filtering characteristics, that a TOSCA orchestrator can use to fulfill the capability at
runtime (implicitly).
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_DEF>`__
"""
@field_validator(type_validator('capability type', convert_name_to_full_type_name,
'capability_types'))
@primitive_field(str, required=True)
def capability(self):
"""
The required reserved keyname used that can be used to provide the name of a valid
Capability Type that can fulfill the requirement.
:type: :obj:`basestring`
"""
@field_validator(type_validator('node type', convert_name_to_full_type_name,
'node_types'))
@primitive_field(str)
def node(self):
"""
The optional reserved keyname used to provide the name of a valid Node Type that contains
the capability definition that can be used to fulfill the requirement.
:type: :obj:`basestring`
"""
@object_field(RelationshipDefinition)
def relationship(self):
"""
The optional reserved keyname used to provide the name of a valid Relationship Type to
construct when fulfilling the requirement.
:type: :class:`RelationshipDefinition`
"""
@field_getter(data_type_class_getter(Range))
@primitive_field()
def occurrences(self):
"""
The optional minimum and maximum occurrences for the requirement.
Note: the keyword UNBOUNDED is also supported to represent any positive integer.
:type: :class:`Range`
"""
@cachedmethod
def _get_capability_type(self, context):
return get_type_by_name(context, self.capability, 'capability_types')
@cachedmethod
def _get_node_type(self, context):
return context.presentation.get_from_dict('service_template', 'node_types', self.node)
def _validate(self, context):
super(RequirementDefinition, self)._validate(context)
occurrences = self.occurrences
if (occurrences is not None) and ((occurrences.value[0] < 0) or \
((occurrences.value[1] != 'UNBOUNDED') and (occurrences.value[1] < 0))):
context.validation.report(
'requirements definition "{0}" occurrences range includes negative integers: {1}'
.format(self._name, safe_repr(occurrences)),
locator=self._locator, level=Issue.BETWEEN_TYPES)
@short_form_field('type')
@has_fields
@implements_specification('3.6.1', 'tosca-simple-1.0')
class CapabilityDefinition(ExtensiblePresentation):
"""
A capability definition defines a named, typed set of data that can be associated with Node Type
or Node Template to describe a transparent capability or feature of the software component the
node describes.
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_DEFN>`__
"""
@field_validator(type_validator('capability type', convert_name_to_full_type_name,
'capability_types'))
@primitive_field(str, required=True)
def type(self):
"""
The required name of the Capability Type the capability definition is based upon.
:type: :obj:`basestring`
"""
@object_field(Description)
def description(self):
"""
The optional description of the Capability definition.
:type: :class:`Description`
"""
@object_dict_field(PropertyDefinition)
def properties(self):
"""
An optional list of property definitions for the Capability definition.
:type: {:obj:`basestring`: :class:`PropertyDefinition`}
"""
@object_dict_field(AttributeDefinition)
def attributes(self):
"""
An optional list of attribute definitions for the Capability definition.
:type: {:obj:`basestring`: :class:`AttributeDefinition`}
"""
@field_validator(list_type_validator('node type', convert_name_to_full_type_name,
'node_types'))
@primitive_list_field(str)
def valid_source_types(self):
"""
An optional list of one or more valid names of Node Types that are supported as valid
sources of any relationship established to the declared Capability Type.
:type: [:obj:`basestring`]
"""
@field_getter(data_type_class_getter(Range))
@primitive_field()
def occurrences(self):
"""
The optional minimum and maximum occurrences for the capability. By default, an exported
Capability should allow at least one relationship to be formed with it with a maximum of
``UNBOUNDED`` relationships.
Note: the keyword ``UNBOUNDED`` is also supported to represent any positive integer.
ARIA NOTE: The spec seems wrong here: the implied default should be ``[0,UNBOUNDED]``, not
``[1,UNBOUNDED]``, otherwise it would imply that at 1 least one relationship *must* be
formed.
:type: :class:`Range`
"""
@cachedmethod
def _get_type(self, context):
return get_type_by_name(context, self.type, 'capability_types')
@cachedmethod
def _get_parent(self, context):
container_parent = self._container._get_parent(context)
container_parent_capabilities = container_parent._get_capabilities(context) \
if container_parent is not None else None
return container_parent_capabilities.get(self._name) \
if container_parent_capabilities is not None else None
def _validate(self, context):
super(CapabilityDefinition, self)._validate(context)
occurrences = self.occurrences
if (occurrences is not None) and ((occurrences.value[0] < 0) or \
((occurrences.value[1] != 'UNBOUNDED') and (occurrences.value[1] < 0))):
context.validation.report(
'capability definition "{0}" occurrences range includes negative integers: {1}'
.format(self._name, safe_repr(occurrences)),
locator=self._locator, level=Issue.BETWEEN_TYPES)