http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py new file mode 100644 index 0000000..291e349 --- /dev/null +++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_getters.py @@ -0,0 +1,36 @@ +# 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.parser import InvalidValueError +from aria.parser.utils import safe_repr + +def data_type_class_getter(cls): + """ + Wraps the field value in a specialized data type class. + + Can be used with the :func:`field_getter` decorator. + """ + + def getter(field, presentation, context=None): + raw = field.default_get(presentation, context) + if raw is not None: + try: + return cls(None, None, raw, None) + except ValueError as e: + raise InvalidValueError( + '%s is not a valid "%s" in "%s": %s' + % (field.full_name, field.full_cls_name, presentation._name, safe_repr(raw)), + cause=e, locator=field.get_locator(raw)) + return getter
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py new file mode 100644 index 0000000..662faab --- /dev/null +++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/field_validators.py @@ -0,0 +1,567 @@ +# 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. + +import re + +from aria.parser import dsl_specification +from aria.parser.presentation import (report_issue_for_unknown_type, derived_from_validator) +from aria.parser.utils import safe_repr +from aria.parser.validation import Issue + +from ..modeling.data_types import (get_primitive_data_type, get_data_type_name, coerce_value, + get_container_data_type) +from .types import get_type_by_full_or_shorthand_name, convert_shorthand_to_full_type_name + +# +# NodeTemplate, RelationshipTemplate +# + +@dsl_specification('3.7.3.3', 'tosca-simple-1.0') +@dsl_specification('3.7.4.3', 'tosca-simple-1.0') +def copy_validator(template_type_name, templates_dict_name): + """ + Makes sure that the field refers to an existing template defined in the root presenter. + + Use with the :func:`field_validator` decorator for the :code:`copy` field in + :class:`NodeTemplate` and :class:`RelationshipTemplate`. + """ + + def validator_fn(field, presentation, context): + field.default_validate(presentation, context) + + # Make sure type exists + value = getattr(presentation, field.name) + if value is not None: + copy = context.presentation.get_from_dict('service_template', 'topology_template', + templates_dict_name, value) + if copy is None: + report_issue_for_unknown_type(context, presentation, template_type_name, field.name) + else: + if copy.copy is not None: + context.validation.report( + '"copy" field refers to a %s that itself is a copy in "%s": %s' + % (template_type_name, presentation._fullname, safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + + return validator_fn + +# +# PropertyDefinition, AttributeDefinition, ParameterDefinition, EntrySchema +# + +def data_type_validator(type_name='data type'): + """ + Makes sure that the field refers to a valid data type, whether complex or primitive. + + Used with the :func:`field_validator` decorator for the :code:`type` fields in + :class:`PropertyDefinition`, :class:`AttributeDefinition`, :class:`ParameterDefinition`, + and :class:`EntrySchema`. + + Extra behavior beyond validation: generated function returns true if field is a complex data + type. + """ + + def validator(field, presentation, context): + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + # Test for circular definitions + container_data_type = get_container_data_type(presentation) + if (container_data_type is not None) and (container_data_type._name == value): + context.validation.report( + 'type of property "%s" creates a circular value hierarchy: %s' + % (presentation._fullname, safe_repr(value)), + locator=presentation._get_child_locator('type'), level=Issue.BETWEEN_TYPES) + + # Can be a complex data type + if get_type_by_full_or_shorthand_name(context, value, 'data_types') is not None: + return True + + # Can be a primitive data type + if get_primitive_data_type(value) is None: + report_issue_for_unknown_type(context, presentation, type_name, field.name) + + return False + + return validator + +# +# PropertyDefinition, AttributeDefinition +# + +def entry_schema_validator(field, presentation, context): + """ + According to whether the data type supports :code:`entry_schema` (e.g., it is or inherits from + list or map), make sure that we either have or don't have a valid data type value. + + Used with the :func:`field_validator` decorator for the :code:`entry_schema` field in + :class:`PropertyDefinition` and :class:`AttributeDefinition`. + """ + + field.default_validate(presentation, context) + + def type_uses_entry_schema(the_type): + use_entry_schema = the_type._get_extension('use_entry_schema', False) \ + if hasattr(the_type, '_get_extension') else False + if use_entry_schema: + return True + parent = the_type._get_parent(context) if hasattr(the_type, '_get_parent') else None + if parent is None: + return False + return type_uses_entry_schema(parent) + + value = getattr(presentation, field.name) + the_type = presentation._get_type(context) + if the_type is None: + return + use_entry_schema = type_uses_entry_schema(the_type) + + if use_entry_schema: + if value is None: + context.validation.report( + '"entry_schema" does not have a value as required by data type "%s" in "%s"' + % (get_data_type_name(the_type), presentation._container._fullname), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + else: + if value is not None: + context.validation.report( + '"entry_schema" has a value but it is not used by data type "%s" in "%s"' + % (get_data_type_name(the_type), presentation._container._fullname), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + +def data_value_validator(field, presentation, context): + """ + Makes sure that the field contains a valid value according to data type and constraints. + + Used with the :func:`field_validator` decorator for the :code:`default` field in + :class:`PropertyDefinition` and :class:`AttributeDefinition`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + the_type = presentation._get_type(context) + entry_schema = presentation.entry_schema + # AttributeDefinition does not have this: + constraints = presentation._get_constraints(context) \ + if hasattr(presentation, '_get_constraints') else None + coerce_value(context, presentation, the_type, entry_schema, constraints, value, field.name) + +# +# DataType +# + +_data_type_validator = data_type_validator() +_data_type_derived_from_validator = derived_from_validator(convert_shorthand_to_full_type_name, + 'data_types') + +def data_type_derived_from_validator(field, presentation, context): + """ + Makes sure that the field refers to a valid parent data type (complex or primitive). + + Used with the :func:`field_validator` decorator for the :code:`derived_from` field in + :class:`DataType`. + """ + + if _data_type_validator(field, presentation, context): + # Validate derivation only if a complex data type (primitive types have no derivation + # hierarchy) + _data_type_derived_from_validator(field, presentation, context) + +def data_type_constraints_validator(field, presentation, context): + """ + Makes sure that we do not have constraints if we are a complex type (with no primitive + ancestor). + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + if presentation._get_primitive_ancestor(context) is None: + context.validation.report( + 'data type "%s" defines constraints but does not have a primitive ancestor' + % presentation._fullname, + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + +def data_type_properties_validator(field, presentation, context): + """ + Makes sure that we do not have properties if we have a primitive ancestor. + + Used with the :func:`field_validator` decorator for the :code:`properties` field in + :class:`DataType`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + if presentation._get_primitive_ancestor(context) is not None: + context.validation.report( + 'data type "%s" defines properties even though it has a primitive ancestor' + % presentation._fullname, + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + +# +# ConstraintClause +# + +def constraint_clause_field_validator(field, presentation, context): + """ + Makes sure that field contains a valid value for the container type. + + Used with the :func:`field_validator` decorator for various field in :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + the_type = presentation._get_type(context) + constraints = the_type._get_constraints(context) \ + if hasattr(the_type, '_get_constraints') else None + coerce_value(context, presentation, the_type, None, constraints, value, field.name) + +def constraint_clause_in_range_validator(field, presentation, context): + """ + Makes sure that the value is a list with exactly two elements, that both lower bound contains a + valid value for the container type, and that the upper bound is either "UNBOUNDED" or a valid + value for the container type. + + Used with the :func:`field_validator` decorator for the :code:`in_range` field in + :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if isinstance(values, list): + # Make sure list has exactly two elements + if len(values) == 2: + lower, upper = values + the_type = presentation._get_type(context) + + # Lower bound must be coercible + lower = coerce_value(context, presentation, the_type, None, None, lower, field.name) + + if upper != 'UNBOUNDED': + # Upper bound be coercible + upper = coerce_value(context, presentation, the_type, None, None, upper, field.name) + + # Second "in_range" value must be greater than first + if (lower is not None) and (upper is not None) and (lower >= upper): + context.validation.report( + 'upper bound of "in_range" constraint is not greater than the lower bound' + ' in "%s": %s <= %s' + % (presentation._container._fullname, safe_repr(lower), safe_repr(upper)), + locator=presentation._locator, level=Issue.FIELD) + else: + context.validation.report( + 'constraint "%s" is not a list of exactly 2 elements in "%s"' + % (field.name, presentation._fullname), + locator=presentation._get_child_locator(field.name), level=Issue.FIELD) + +def constraint_clause_valid_values_validator(field, presentation, context): + """ + Makes sure that the value is a list of valid values for the container type. + + Used with the :func:`field_validator` decorator for the :code:`valid_values` field in + :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if isinstance(values, list): + the_type = presentation._get_type(context) + for value in values: + coerce_value(context, presentation, the_type, None, None, value, field.name) + +def constraint_clause_pattern_validator(field, presentation, context): + """ + Makes sure that the value is a valid regular expression. + + Used with the :func:`field_validator` decorator for the :code:`pattern` field in + :class:`ConstraintClause`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + try: + # Note: the TOSCA 1.0 spec does not specify the regular expression grammar, so we will + # just use Python's + re.compile(value) + except re.error as e: + context.validation.report( + 'constraint "%s" is not a valid regular expression in "%s"' + % (field.name, presentation._fullname), + locator=presentation._get_child_locator(field.name), level=Issue.FIELD, exception=e) + +# +# RequirementAssignment +# + +def node_template_or_type_validator(field, presentation, context): + """ + Makes sure that the field refers to either a node template or a node type. + + Used with the :func:`field_validator` decorator for the :code:`node` field in + :class:`RequirementAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + node_templates = \ + context.presentation.get('service_template', 'topology_template', 'node_templates') \ + or {} + node_types = context.presentation.get('service_template', 'node_types') or {} + if (value not in node_templates) and (value not in node_types): + report_issue_for_unknown_type(context, presentation, 'node template or node type', + field.name) + +def capability_definition_or_type_validator(field, presentation, context): + """ + Makes sure refers to either a capability assignment name in the node template referred to by the + :code:`node` field or a general capability type. + + If the value refers to a capability type, make sure the :code:`node` field was not assigned. + + Used with the :func:`field_validator` decorator for the :code:`capability` field in + :class:`RequirementAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + node, node_variant = presentation._get_node(context) + if node_variant == 'node_template': + capabilities = node._get_capabilities(context) + if value in capabilities: + return + + capability_types = context.presentation.get('service_template', 'capability_types') + if (capability_types is not None) and (value in capability_types): + if node is not None: + context.validation.report( + '"%s" refers to a capability type even though "node" has a value in "%s"' + % (presentation._name, presentation._container._fullname), + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_FIELDS) + return + + if node_variant == 'node_template': + context.validation.report( + 'requirement "%s" refers to an unknown capability definition name or capability' + ' type in "%s": %s' + % (presentation._name, presentation._container._fullname, safe_repr(value)), + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'requirement "%s" refers to an unknown capability type in "%s": %s' + % (presentation._name, presentation._container._fullname, safe_repr(value)), + locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES) + +def node_filter_validator(field, presentation, context): + """ + Makes sure that the field has a value only if "node" refers to a node type. + + Used with the :func:`field_validator` decorator for the :code:`node_filter` field in + :class:`RequirementAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + _, node_type_variant = presentation._get_node(context) + if node_type_variant != 'node_type': + context.validation.report( + 'requirement "%s" has a node filter even though "node" does not refer to a node' + ' type in "%s"' + % (presentation._fullname, presentation._container._fullname), + locator=presentation._locator, level=Issue.BETWEEN_FIELDS) + +# +# RelationshipAssignment +# + +def relationship_template_or_type_validator(field, presentation, context): + """ + Makes sure that the field refers to either a relationship template or a relationship type. + + Used with the :func:`field_validator` decorator for the :code:`type` field in + :class:`RelationshipAssignment`. + """ + + field.default_validate(presentation, context) + + value = getattr(presentation, field.name) + if value is not None: + relationship_templates = \ + context.presentation.get('service_template', 'topology_template', + 'relationship_templates') \ + or {} + relationship_types = \ + context.presentation.get('service_template', 'relationship_types') or {} + if (value not in relationship_templates) and (value not in relationship_types): + report_issue_for_unknown_type(context, presentation, + 'relationship template or relationship type', field.name) + +# +# PolicyType +# + +def list_node_type_or_group_type_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to either node types or a group types. + + Used with the :func:`field_validator` decorator for the :code:`targets` field in + :class:`PolicyType`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + for value in values: + node_types = context.presentation.get('service_template', 'node_types') or {} + group_types = context.presentation.get('service_template', 'group_types') or {} + if (value not in node_types) and (value not in group_types): + report_issue_for_unknown_type(context, presentation, 'node type or group type', + field.name, value) + +# +# PolicyTemplate +# + +def policy_targets_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to either node templates or groups, and that + they match the node types and group types declared in the policy type. + + Used with the :func:`field_validator` decorator for the :code:`targets` field in + :class:`PolicyTemplate`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + for value in values: + node_templates = \ + context.presentation.get('service_template', 'topology_template', + 'node_templates') \ + or {} + groups = context.presentation.get('service_template', 'topology_template', 'groups') \ + or {} + if (value not in node_templates) and (value not in groups): + report_issue_for_unknown_type(context, presentation, 'node template or group', + field.name, value) + + policy_type = presentation._get_type(context) + if policy_type is None: + break + + node_types, group_types = policy_type._get_targets(context) + + is_valid = False + + if value in node_templates: + our_node_type = node_templates[value]._get_type(context) + for node_type in node_types: + if node_type._is_descendant(context, our_node_type): + is_valid = True + break + + elif value in groups: + our_group_type = groups[value]._get_type(context) + for group_type in group_types: + if group_type._is_descendant(context, our_group_type): + is_valid = True + break + + if not is_valid: + context.validation.report( + 'policy definition target does not match either a node type or a group type' + ' declared in the policy type in "%s": %s' + % (presentation._name, safe_repr(value)), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + +# +# NodeFilter +# + +def node_filter_properties_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to defined properties in the target node type. + + Used with the :func:`field_validator` decorator for the :code:`properties` field in + :class:`NodeFilter`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: + node_type = presentation._get_node_type(context) + if node_type is not None: + properties = node_type._get_properties(context) + for name, _ in values: + if name not in properties: + context.validation.report( + 'node filter refers to an unknown property definition in "%s": %s' + % (node_type._name, name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + +def node_filter_capabilities_validator(field, presentation, context): + """ + Makes sure that the field's elements refer to defined capabilities and properties in the target + node type. + + Used with the :func:`field_validator` decorator for the :code:`capabilities` field in + :class:`NodeFilter`. + """ + + field.default_validate(presentation, context) + + values = getattr(presentation, field.name) + if values is not None: # pylint: disable=too-many-nested-blocks + node_type = presentation._get_node_type(context) + if node_type is not None: + capabilities = node_type._get_capabilities(context) + for name, value in values: + capability = capabilities.get(name) + if capability is not None: + properties = value.properties + capability_properties = capability.properties + if (properties is not None) and (capability_properties is not None): + for property_name, _ in properties: + if property_name not in capability_properties: + context.validation.report( + 'node filter refers to an unknown capability definition' + ' property in "%s": %s' + % (node_type._name, property_name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) + else: + context.validation.report( + 'node filter refers to an unknown capability definition in "%s": %s' + % (node_type._name, name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py b/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py new file mode 100644 index 0000000..088a246 --- /dev/null +++ b/extensions/aria_extension_tosca/simple_v1_0/presentation/types.py @@ -0,0 +1,57 @@ +# 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. + +def convert_shorthand_to_full_type_name(context, name, types_dict): # pylint: disable=unused-argument + """ + Converts a shorthand type name to its full type name, or else returns it unchanged. + + Works by checking for :code:`shorthand_name` in the types' :code:`_extensions` field. See also + :class:`aria_extension_tosca.v1_0.presentation.extensible.ExtensiblePresentation`. + + Can be used as the conversion function argument in :code:`type_validator` and + :code:`derived_from_validator`. + """ + + if (name is not None) and types_dict and (name not in types_dict): + for full_name, the_type in types_dict.iteritems(): + if hasattr(the_type, '_extensions') and the_type._extensions \ + and (the_type._extensions.get('shorthand_name') == name): + return full_name + return name + +def get_type_by_full_or_shorthand_name(context, name, *types_dict_names): + """ + Gets a type either by its full name or its shorthand name. + + Works by checking for :code:`shorthand_name` in the types' :code:`_extensions` field. See also + :class:`aria_extension_tosca.v1_0.presentation.extensible.ExtensiblePresentation`. + + The arguments from the third onwards are used to locate a nested field under + :code:`service_template` under the root presenter. + """ + + if name is not None: + types_dict = context.presentation.get('service_template', *types_dict_names) + if types_dict: + the_type = types_dict.get(name) + if the_type is not None: + # Full name + return the_type + for the_type in types_dict.itervalues(): + if hasattr(the_type, '_extensions') and the_type._extensions \ + and (the_type._extensions.get('shorthand_name') == name): + # Shorthand name + return the_type + return None http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/presenter.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/presenter.py b/extensions/aria_extension_tosca/simple_v1_0/presenter.py new file mode 100644 index 0000000..c21c326 --- /dev/null +++ b/extensions/aria_extension_tosca/simple_v1_0/presenter.py @@ -0,0 +1,78 @@ +# 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.parser.presentation import Presenter +from aria.parser.utils import (FrozenList, EMPTY_READ_ONLY_LIST, cachedmethod) + +from .functions import (Concat, Token, GetInput, GetProperty, GetAttribute, GetOperationOutput, + GetNodesOfType, GetArtifact) +from .modeling import create_service_model +from .templates import ServiceTemplate + +class ToscaSimplePresenter1_0(Presenter): # pylint: disable=invalid-name + """ + ARIA presenter for the `TOSCA Simple Profile v1.0 cos01 <http://docs.oasis-open.org/tosca + /TOSCA-Simple-Profile-YAML/v1.0/cos01/TOSCA-Simple-Profile-YAML-v1.0-cos01.html>`__. + + Supported :code:`tosca_definitions_version` values: + + * :code:`tosca_simple_yaml_1_0` + """ + + DSL_VERSIONS = ('tosca_simple_yaml_1_0',) + ALLOWED_IMPORTED_DSL_VERSIONS = ('tosca_simple_yaml_1_0',) + SIMPLE_PROFILE_LOCATION = 'tosca-simple-1.0/tosca-simple-1.0.yaml' + + @property + @cachedmethod + def service_template(self): + return ServiceTemplate(raw=self._raw) + + @property + @cachedmethod + def functions(self): + return { + 'concat': Concat, + 'token': Token, + 'get_input': GetInput, + 'get_property': GetProperty, + 'get_attribute': GetAttribute, + 'get_operation_output': GetOperationOutput, + 'get_nodes_of_type': GetNodesOfType, + 'get_artifact': GetArtifact} + + # Presentation + + def _dump(self, context): + self.service_template._dump(context) + + def _validate(self, context): + self.service_template._validate(context) + + # Presenter + + @cachedmethod + def _get_import_locations(self, context): + import_locations = [] + if context.presentation.import_profile: + import_locations.append(self.SIMPLE_PROFILE_LOCATION) + imports = self._get('service_template', 'imports') + if imports: + import_locations += [i.file for i in imports] + return FrozenList(import_locations) if import_locations else EMPTY_READ_ONLY_LIST + + @cachedmethod + def _get_service_model(self, context): # pylint: disable=no-self-use + return create_service_model(context) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/8ee1470e/extensions/aria_extension_tosca/simple_v1_0/templates.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/templates.py b/extensions/aria_extension_tosca/simple_v1_0/templates.py new file mode 100644 index 0000000..fda95a4 --- /dev/null +++ b/extensions/aria_extension_tosca/simple_v1_0/templates.py @@ -0,0 +1,725 @@ +# 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.parser import dsl_specification +from aria.parser.presentation import (has_fields, primitive_field, primitive_list_field, + object_field, object_list_field, object_dict_field, + object_sequenced_list_field, field_validator, + type_validator, list_type_validator) +from aria.parser.utils import (FrozenDict, FrozenList, cachedmethod) + +from .assignments import (PropertyAssignment, AttributeAssignment, RequirementAssignment, + CapabilityAssignment, InterfaceAssignment, ArtifactAssignment) +from .definitions import ParameterDefinition +from .filters import NodeFilter +from .misc import (Description, MetaData, Repository, Import, SubstitutionMappings) +from .modeling.properties import get_assigned_and_defined_property_values, get_parameter_values +from .modeling.interfaces import get_template_interfaces +from .modeling.requirements import get_template_requirements +from .modeling.capabilities import get_template_capabilities +from .modeling.artifacts import get_inherited_artifact_definitions +from .modeling.policies import get_policy_targets +from .modeling.copy import get_default_raw_from_copy +from .presentation.extensible import ExtensiblePresentation +from .presentation.field_validators import copy_validator, policy_targets_validator +from .presentation.types import (convert_shorthand_to_full_type_name, + get_type_by_full_or_shorthand_name) +from .types import (ArtifactType, DataType, CapabilityType, InterfaceType, RelationshipType, + NodeType, GroupType, PolicyType) + +@has_fields +@dsl_specification('3.7.3', 'tosca-simple-1.0') +class NodeTemplate(ExtensiblePresentation): + """ + A Node Template specifies the occurrence of a manageable software component as part of an + application's topology model which is defined in a TOSCA Service Template. A Node template is an + instance of a specified Node Type and can provide customized properties, constraints or + operations which override the defaults provided by its Node Type and its implementations. + + 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_NODE_TEMPLATE>`__ + """ + + @field_validator(type_validator('node type', convert_shorthand_to_full_type_name, 'node_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the Node Type the Node Template is based upon. + + :rtype: str + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Node Template. + + :rtype: :class:`Description` + """ + + @primitive_list_field(str) + def directives(self): + """ + An optional list of directive values to provide processing instructions to orchestrators and + tooling. + + :rtype: list of str + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property value assignments for the Node Template. + + :rtype: dict of str, :class:`PropertyAssignment` + """ + + @object_dict_field(AttributeAssignment) + def attributes(self): + """ + An optional list of attribute value assignments for the Node Template. + + :rtype: dict of str, :class:`AttributeAssignment` + """ + + @object_sequenced_list_field(RequirementAssignment) + def requirements(self): + """ + An optional sequenced list of requirement assignments for the Node Template. + + :rtype: list of (str, :class:`RequirementAssignment`) + """ + + @object_dict_field(CapabilityAssignment) + def capabilities(self): + """ + An optional list of capability assignments for the Node Template. + + :rtype: dict of str, :class:`CapabilityAssignment` + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + An optional list of named interface definitions for the Node Template. + + :rtype: dict of str, :class:`InterfaceAssignment` + """ + + @object_dict_field(ArtifactAssignment) + def artifacts(self): + """ + An optional list of named artifact definitions for the Node Template. + + :rtype: dict of str, :class:`ArtifactAssignment` + """ + + @object_field(NodeFilter) + def node_filter(self): + """ + The optional filter definition that TOSCA orchestrators would use to select the correct + target node. This keyname is only valid if the directive has the value of "selectable" set. + + :rtype: :class:`NodeFilter` + """ + + @field_validator(copy_validator('node template', 'node_templates')) + @primitive_field(str) + def copy(self): + """ + The optional (symbolic) name of another node template to copy into (all keynames and values) + and use as a basis for this node template. + + :rtype: str + """ + + @cachedmethod + def _get_default_raw(self): + return get_default_raw_from_copy(self, 'node_templates') + + @cachedmethod + def _get_type(self, context): + return get_type_by_full_or_shorthand_name(context, self.type, 'node_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_property_values(context, self)) + + @cachedmethod + def _get_requirements(self, context): + return FrozenList(get_template_requirements(context, self)) + + @cachedmethod + def _get_capabilities(self, context): + return FrozenDict(get_template_capabilities(context, self)) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_template_interfaces(context, self, 'node template')) + + @cachedmethod + def _get_artifacts(self, context): + return FrozenDict(get_inherited_artifact_definitions(context, self)) + + def _validate(self, context): + super(NodeTemplate, self)._validate(context) + self._get_property_values(context) + self._get_requirements(context) + self._get_capabilities(context) + self._get_interfaces(context) + self._get_artifacts(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'type', + 'directives', + 'properties', + 'attributes', + 'requirements', + 'capabilities', + 'interfaces', + 'artifacts', + 'node_filter', + 'copy')) + +@has_fields +@dsl_specification('3.7.4', 'tosca-simple-1.0') +class RelationshipTemplate(ExtensiblePresentation): + """ + A Relationship Template specifies the occurrence of a manageable relationship between node + templates as part of an application's topology model that is defined in a TOSCA Service + Template. A Relationship template is an instance of a specified Relationship Type and can + provide customized properties, constraints or operations which override the defaults provided by + its Relationship Type and its implementations. + + 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_RELATIONSHIP_TEMPLATE>`__ + """ + + @field_validator(type_validator('relationship type', convert_shorthand_to_full_type_name, + 'relationship_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the Relationship Type the Relationship Template is based upon. + + :rtype: str + """ + + @object_field(Description) + def description(self): + """ + An optional description for the Relationship Template. + + :rtype: :class:`Description` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property assignments for the Relationship Template. + + :rtype: dict of str, :class:`PropertyAssignment` + """ + + @object_dict_field(AttributeAssignment) + def attributes(self): + """ + An optional list of attribute assignments for the Relationship Template. + + :rtype: dict of str, :class:`AttributeAssignment` + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + An optional list of named interface definitions for the Node Template. + + ARIA NOTE: Spec is wrong here, should be Relationship Template. + + :rtype: dict of str, :class:`InterfaceAssignment` + """ + + @field_validator(copy_validator('relationship template', 'relationship_templates')) + @primitive_field(str) + def copy(self): + """ + The optional (symbolic) name of another relationship template to copy into (all keynames and + values) and use as a basis for this relationship template. + + :rtype: str + """ + + @cachedmethod + def _get_default_raw(self): + return get_default_raw_from_copy(self, 'relationship_templates') + + @cachedmethod + def _get_type(self, context): + return get_type_by_full_or_shorthand_name(context, self.type, 'relationship_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_property_values(context, self)) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_template_interfaces(context, self, 'relationship template')) + + def _validate(self, context): + super(RelationshipTemplate, self)._validate(context) + self._get_property_values(context) + self._get_interfaces(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'type', + 'properties', + 'attributes', + 'interfaces', + 'copy')) + +@has_fields +@dsl_specification('3.7.5', 'tosca-simple-1.0') +class GroupTemplate(ExtensiblePresentation): + """ + A group definition defines a logical grouping of node templates, typically for management + purposes, but is separate from the application's topology template. + + 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_GROUP_DEF>`__ + """ + + @field_validator(type_validator('group type', convert_shorthand_to_full_type_name, + 'group_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the group type the group definition is based upon. + + :rtype: str + """ + + @object_field(Description) + def description(self): + """ + The optional description for the group definition. + + :rtype: :class:`Description` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property value assignments for the group definition. + + :rtype: dict of str, :class:`PropertyAssignment` + """ + + @field_validator(list_type_validator('node template', 'topology_template', 'node_templates')) + @primitive_list_field(str) + def members(self): + """ + The optional list of one or more node template names that are members of this group + definition. + + :rtype: list of str + """ + + @object_dict_field(InterfaceAssignment) + def interfaces(self): + """ + An optional list of named interface definitions for the group definition. + + :rtype: dict of str, :class:`InterfaceDefinition` + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_full_or_shorthand_name(context, self.type, 'group_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_property_values(context, self)) + + @cachedmethod + def _get_interfaces(self, context): + return FrozenDict(get_template_interfaces(context, self, 'group definition')) + + def _validate(self, context): + super(GroupTemplate, self)._validate(context) + self._get_property_values(context) + self._get_interfaces(context) + +@has_fields +@dsl_specification('3.7.6', 'tosca-simple-1.0') +class PolicyTemplate(ExtensiblePresentation): + """ + A policy definition defines a policy that can be associated with a TOSCA topology or top-level + entity definition (e.g., group definition, node template, etc.). + + 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_POLICY_DEF>`__ + """ + + @field_validator(type_validator('policy type', convert_shorthand_to_full_type_name, + 'policy_types')) + @primitive_field(str, required=True) + def type(self): + """ + The required name of the policy type the policy definition is based upon. + + :rtype: str + """ + + @object_field(Description) + def description(self): + """ + The optional description for the policy definition. + + :rtype: :class:`Description` + """ + + @object_dict_field(PropertyAssignment) + def properties(self): + """ + An optional list of property value assignments for the policy definition. + + :rtype: dict of str, :class:`PropertyAssignment` + """ + + @field_validator(policy_targets_validator) + @primitive_list_field(str) + def targets(self): + """ + An optional list of valid Node Templates or Groups the Policy can be applied to. + + :rtype: list of str + """ + + @cachedmethod + def _get_type(self, context): + return get_type_by_full_or_shorthand_name(context, self.type, 'policy_types') + + @cachedmethod + def _get_property_values(self, context): + return FrozenDict(get_assigned_and_defined_property_values(context, self)) + + @cachedmethod + def _get_targets(self, context): + node_templates, groups = get_policy_targets(context, self) + return FrozenList(node_templates), FrozenList(groups) + + def _validate(self, context): + super(PolicyTemplate, self)._validate(context) + self._get_property_values(context) + +@has_fields +@dsl_specification('3.8', 'tosca-simple-1.0') +class TopologyTemplate(ExtensiblePresentation): + """ + This section defines the topology template of a cloud application. The main ingredients of the + topology template are node templates representing components of the application and relationship + templates representing links between the components. These elements are defined in the nested + :code:`node_templates` section and the nested relationship_templates sections, respectively. + Furthermore, a topology template allows for defining input parameters, output parameters as well + as grouping of node 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_ENTITY_TOPOLOGY_TEMPLATE>`__ + """ + + @object_field(Description) + def description(self): + """ + The optional description for the Topology Template. + + :rtype: :class:`Description` + """ + + @object_dict_field(ParameterDefinition) + def inputs(self): + """ + An optional list of input parameters (i.e., as parameter definitions) for the Topology + Template. + + :rtype: dict of str, :class:`ParameterDefinition` + """ + + @object_dict_field(NodeTemplate) + def node_templates(self): + """ + An optional list of node template definitions for the Topology Template. + + :rtype: dict of str, :class:`NodeTemplate` + """ + + @object_dict_field(RelationshipTemplate) + def relationship_templates(self): + """ + An optional list of relationship templates for the Topology Template. + + :rtype: dict of str, :class:`RelationshipTemplate` + """ + + @object_dict_field(GroupTemplate) + def groups(self): + """ + An optional list of Group definitions whose members are node templates defined within this + same Topology Template. + + :class:`GroupTemplate` + """ + + @object_dict_field(PolicyTemplate) + def policies(self): + """ + An optional list of Policy definitions for the Topology Template. + + :rtype: dict of str, :class:`PolicyTemplate` + """ + + @object_dict_field(ParameterDefinition) + def outputs(self): + """ + An optional list of output parameters (i.e., as parameter definitions) for the Topology + Template. + + :rtype: dict of str, :class:`ParameterDefinition` + """ + + @object_field(SubstitutionMappings) + def substitution_mappings(self): + """ + An optional declaration that exports the topology template as an implementation of a Node + type. + + This also includes the mappings between the external Node Types named capabilities and + requirements to existing implementations of those capabilities and requirements on Node + templates declared within the topology template. + """ + + @cachedmethod + def _get_input_values(self, context): + return FrozenDict(get_parameter_values(context, self, 'inputs')) + + @cachedmethod + def _get_output_values(self, context): + return FrozenDict(get_parameter_values(context, self, 'outputs')) + + def _validate(self, context): + super(TopologyTemplate, self)._validate(context) + self._get_input_values(context) + self._get_output_values(context) + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'inputs', + 'node_templates', + 'relationship_templates', + 'groups', + 'policies', + 'outputs', + 'substitution_mappings')) + +@has_fields +@dsl_specification('3.9', 'tosca-simple-1.0') +class ServiceTemplate(ExtensiblePresentation): + """ + 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_SERVICE_TEMPLATE>`__. + """ + + @primitive_field(str) + @dsl_specification('3.9.3.1', 'tosca-simple-1.0') + def tosca_definitions_version(self): + """ + Defines the version of the TOSCA Simple Profile specification the template (grammar) + complies with. + + 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 + #_Toc379455047>`__ + + :rtype: str + """ + + @object_field(MetaData) + def metadata(self): + """ + Defines a section used to declare additional metadata information. Domain-specific TOSCA + profile specifications may define keynames that are required for their implementations. + + 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 + #_Toc379455048>`__ + + :rtype: :class:`MetaData` + """ + + @object_field(Description) + @dsl_specification('3.9.3.6', 'tosca-simple-1.0') + def description(self): + """ + Declares a description for this Service Template and its contents. + + :rtype: :class:`Description` + """ + + @primitive_field() + @dsl_specification('3.9.3.7', 'tosca-simple-1.0') + def dsl_definitions(self): + """ + Declares optional DSL-specific definitions and conventions. For example, in YAML, this + allows defining reusable YAML macros (i.e., YAML alias anchors) for use throughout the TOSCA + Service Template. + + 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 + #_Toc397688790>`__ + """ + + @object_dict_field(Repository) + @dsl_specification('3.9.3.8', 'tosca-simple-1.0') + def repositories(self): + """ + Declares the list of external repositories which contain artifacts that are referenced in + the service template along with their addresses and necessary credential information used to + connect to them in order to retrieve the artifacts. + + :rtype: dict of str, :class:`Repository` + """ + + @object_list_field(Import) + @dsl_specification('3.9.3.9', 'tosca-simple-1.0') + def imports(self): + """ + Declares import statements external TOSCA Definitions documents. For example, these may be + file location or URIs relative to the service template file within the same TOSCA CSAR file. + + :rtype: list of :class:`Import` + """ + + @object_dict_field(ArtifactType) + @dsl_specification('3.9.3.10', 'tosca-simple-1.0') + def artifact_types(self): + """ + This section contains an optional list of artifact type definitions for use in the service + template. + + :rtype: dict of str, :class:`ArtifactType` + """ + + @object_dict_field(DataType) + @dsl_specification('3.9.3.11', 'tosca-simple-1.0') + def data_types(self): + """ + Declares a list of optional TOSCA Data Type definitions. + + :rtype: dict of str, :class:`DataType` + """ + + @object_dict_field(CapabilityType) + @dsl_specification('3.9.3.12', 'tosca-simple-1.0') + def capability_types(self): + """ + This section contains an optional list of capability type definitions for use in the service + template. + + :rtype: dict of str, :class:`CapabilityType` + """ + + @object_dict_field(InterfaceType) + @dsl_specification('3.9.3.13', 'tosca-simple-1.0') + def interface_types(self): + """ + This section contains an optional list of interface type definitions for use in the service + template. + + :rtype: dict of str, :class:`InterfaceType` + """ + + @object_dict_field(RelationshipType) + @dsl_specification('3.9.3.14', 'tosca-simple-1.0') + def relationship_types(self): + """ + This section contains a set of relationship type definitions for use in the service + template. + + :rtype: dict of str, :class:`RelationshipType` + """ + + @object_dict_field(NodeType) + @dsl_specification('3.9.3.15', 'tosca-simple-1.0') + def node_types(self): + """ + This section contains a set of node type definitions for use in the service template. + + :rtype: dict of str, :class:`NodeType` + """ + + @object_dict_field(GroupType) + @dsl_specification('3.9.3.16', 'tosca-simple-1.0') + def group_types(self): + """ + This section contains a list of group type definitions for use in the service template. + + :rtype: dict of str, :class:`GroupType` + """ + + @object_dict_field(PolicyType) + @dsl_specification('3.9.3.17', 'tosca-simple-1.0') + def policy_types(self): + """ + This section contains a list of policy type definitions for use in the service template. + + :rtype: dict of str, :class:`PolicyType` + """ + + @object_field(TopologyTemplate) + def topology_template(self): + """ + Defines the topology template of an application or service, consisting of node templates + that represent the application's or service's components, as well as relationship templates + representing relations between the components. + + :rtype: :class:`TopologyTemplate` + """ + + def _dump(self, context): + self._dump_content(context, ( + 'description', + 'tosca_definitions_version', + 'metadata', + 'repositories', + 'imports', + 'artifact_types', + 'data_types', + 'capability_types', + 'interface_types', + 'relationship_types', + 'node_types', + 'group_types', + 'policy_types', + 'topology_template'))