ARIA-348 Validate substitution_mapping field
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/a048f704 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/a048f704 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/a048f704 Branch: refs/heads/ARIA-321-clearwater Commit: a048f70491ff0dfa3a6f0d41be6d1294e2ee7061 Parents: a5b450a Author: Avia Efrat <a...@gigaspaces.com> Authored: Wed Aug 16 18:54:57 2017 +0300 Committer: Avia Efrat <a...@gigaspaces.com> Committed: Thu Aug 24 11:30:48 2017 +0300 ---------------------------------------------------------------------- .travis.yml | 1 + .../aria_extension_tosca/simple_v1_0/misc.py | 8 +- .../modeling/substitution_mappings.py | 175 +++++++++++-------- .../aria_extension_tosca/simple_v1_0/types.py | 9 +- 4 files changed, 116 insertions(+), 77 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a048f704/.travis.yml ---------------------------------------------------------------------- diff --git a/.travis.yml b/.travis.yml index c8b7645..a7362e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ sudo: false language: python +dist: precise python: - '2.7' http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a048f704/extensions/aria_extension_tosca/simple_v1_0/misc.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/misc.py b/extensions/aria_extension_tosca/simple_v1_0/misc.py index a65ff41..221163c 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/misc.py +++ b/extensions/aria_extension_tosca/simple_v1_0/misc.py @@ -25,8 +25,8 @@ from aria.parser.presentation import (AsIsPresentation, has_fields, allow_unknow from .modeling.data_types import (get_data_type, get_data_type_value, get_property_constraints, apply_constraint_to_value) -from .modeling.substitution_mappings import (validate_subtitution_mappings_requirement, - validate_subtitution_mappings_capability) +from .modeling.substitution_mappings import (validate_substitution_mappings_requirement, + validate_substitution_mappings_capability) from .presentation.extensible import ExtensiblePresentation from .presentation.field_validators import (constraint_clause_field_validator, constraint_clause_in_range_validator, @@ -380,7 +380,7 @@ class SubstitutionMappingsRequirement(AsIsPresentation): def _validate(self, context): super(SubstitutionMappingsRequirement, self)._validate(context) - validate_subtitution_mappings_requirement(context, self) + validate_substitution_mappings_requirement(context, self) class SubstitutionMappingsCapability(AsIsPresentation): @@ -400,7 +400,7 @@ class SubstitutionMappingsCapability(AsIsPresentation): def _validate(self, context): super(SubstitutionMappingsCapability, self)._validate(context) - validate_subtitution_mappings_capability(context, self) + validate_substitution_mappings_capability(context, self) @has_fields http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a048f704/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py b/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py index 8f7ec4c..e2af4b8 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py +++ b/extensions/aria_extension_tosca/simple_v1_0/modeling/substitution_mappings.py @@ -17,88 +17,113 @@ from aria.utils.formatting import safe_repr from aria.parser.validation import Issue -def validate_subtitution_mappings_requirement(context, presentation): - if not validate_format(context, presentation, 'requirement'): - return +def validate_substitution_mappings_requirement(context, presentation): - node_template = get_node_template(context, presentation, 'requirement') - if node_template is None: + # validate that the requirement in substitution_mapping is defined in the substitution node type + substitution_node_type = presentation._container._get_type(context) + if substitution_node_type is None: + return + for req_name, req in substitution_node_type._get_requirements(context): + if req_name == presentation._name: + substitution_type_requirement = req + break + else: + context.validation.report( + 'substitution mapping requirement "{0}" is not declared in node type "{1}"'.format( + presentation._name, substitution_node_type._name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) return - node_type = presentation._container._get_type(context) - if node_type is None: + if not _validate_mapping_format(presentation): + _report_invalid_mapping_format(context, presentation, field='requirement') return - requirements = node_type._get_requirements(context) - type_requirement = None - for name, the_requirement in requirements: - if name == presentation._name: - type_requirement = the_requirement + # validate that the mapped requirement is defined in the corresponding node template + node_template = _get_node_template(context, presentation) + if node_template is None: + _report_missing_node_template(context, presentation, field='requirement') + return + mapped_requirement_name = presentation._raw[1] + for req_name, req in node_template._get_requirements(context): + if req_name == mapped_requirement_name: + node_template_requirement = req break - if type_requirement is None: + else: context.validation.report( - 'substitution mappings requirement "%s" is not declared in node type "%s"' - % (presentation._name, node_type._name), + 'substitution mapping requirement "{0}" refers to an unknown requirement of node ' + 'template "{1}": {mapped_requirement_name}'.format( + presentation._name, node_template._name, + mapped_requirement_name=safe_repr(mapped_requirement_name)), locator=presentation._locator, level=Issue.BETWEEN_TYPES) return - requirement_name = presentation._raw[1] - requirements = node_template._get_requirements(context) - requirement = None - for name, the_requirement in requirements: - if name == requirement_name: - requirement = the_requirement - break - - if requirement is None: + # validate that the requirement's capability type in substitution_mapping is derived from the + # requirement's capability type in the corresponding node template + substitution_type_requirement_capability_type = \ + substitution_type_requirement._get_capability_type(context) + node_template_requirement_capability_type = \ + node_template_requirement._get_capability(context)[0] + if not node_template_requirement_capability_type._is_descendant( + context, substitution_type_requirement_capability_type): context.validation.report( - 'substitution mappings requirement "%s" refers to an unknown requirement of node ' - 'template "%s": %s' - % (presentation._name, node_template._name, safe_repr(requirement_name)), + 'substitution mapping requirement "{0}" of capability type "{1}" is not a descendant ' + 'of the mapped node template capability type "{2}"'.format( + presentation._name, + substitution_type_requirement_capability_type._name, + node_template_requirement_capability_type._name), locator=presentation._locator, level=Issue.BETWEEN_TYPES) - return -def validate_subtitution_mappings_capability(context, presentation): - if not validate_format(context, presentation, 'capability'): - return +def validate_substitution_mappings_capability(context, presentation): - node_template = get_node_template(context, presentation, 'capability') - if node_template is None: + # validate that the capability in substitution_mapping is defined in the substitution node type + substitution_node_type = presentation._container._get_type(context) + if substitution_node_type is None: return - - node_type = presentation._container._get_type(context) - if node_type is None: + substitution_type_capabilities = substitution_node_type._get_capabilities(context) + substitution_type_capability = substitution_type_capabilities.get(presentation._name) + if substitution_type_capability is None: + context.validation.report( + 'substitution mapping capability "{0}" ' + 'is not declared in node type "{substitution_type}"'.format( + presentation._name, substitution_type=substitution_node_type._name), + locator=presentation._locator, level=Issue.BETWEEN_TYPES) return - capabilities = node_type._get_capabilities(context) - type_capability = capabilities.get(presentation._name) - if type_capability is None: - context.validation.report( - 'substitution mappings capability "%s" is not declared in node type "%s"' - % (presentation._name, node_type._name), locator=presentation._locator, - level=Issue.BETWEEN_TYPES) + if not _validate_mapping_format(presentation): + _report_invalid_mapping_format(context, presentation, field='capability') return - capability_name = presentation._raw[1] - capabilities = node_template._get_capabilities(context) - capability = capabilities.get(capability_name) + # validate that the capability in substitution_mapping is declared in the corresponding + # node template + node_template = _get_node_template(context, presentation) + if node_template is None: + _report_missing_node_template(context, presentation, field='capability') + return + mapped_capability_name = presentation._raw[1] + node_template_capability = node_template._get_capabilities(context).get(mapped_capability_name) - if capability is None: + if node_template_capability is None: context.validation.report( - 'substitution mappings capability "%s" refers to an unknown capability of node template' - ' "%s": %s' - % (presentation._name, node_template._name, safe_repr(capability_name)), + 'substitution mapping capability "{0}" refers to an unknown ' + 'capability of node template "{1}": {mapped_capability_name}'.format( + presentation._name, node_template._name, + mapped_capability_name=safe_repr(mapped_capability_name)), locator=presentation._locator, level=Issue.BETWEEN_TYPES) return - type_capability_type = type_capability._get_type(context) - capability_type = capability._get_type(context) + # validate that the capability type in substitution_mapping is derived from the capability type + # in the corresponding node template + substitution_type_capability_type = substitution_type_capability._get_type(context) + node_template_capability_type = node_template_capability._get_type(context) - if not type_capability_type._is_descendant(context, capability_type): + if not substitution_type_capability_type._is_descendant(context, node_template_capability_type): context.validation.report( - 'type "%s" of substitution mappings capability "%s" is not a descendant of "%s"' - % (capability_type._name, presentation._name, type_capability_type._name), + 'node template capability type "{0}" is not a descendant of substitution mapping ' + 'capability "{1}" of type "{2}"'.format( + node_template_capability_type._name, + presentation._name, + substitution_type_capability_type._name), locator=presentation._locator, level=Issue.BETWEEN_TYPES) @@ -106,25 +131,37 @@ def validate_subtitution_mappings_capability(context, presentation): # Utils # -def validate_format(context, presentation, name): - if (not isinstance(presentation._raw, list)) or (len(presentation._raw) != 2) \ - or (not isinstance(presentation._raw[0], basestring)) \ - or (not isinstance(presentation._raw[1], basestring)): - context.validation.report( - 'substitution mappings %s "%s" is not a list of 2 strings: %s' - % (name, presentation._name, safe_repr(presentation._raw)), - locator=presentation._locator, level=Issue.FIELD) +def _validate_mapping_format(presentation): + """Validate that the mapping is a list of 2 strings""" + if not isinstance(presentation._raw, list) or \ + len(presentation._raw) != 2 or \ + not isinstance(presentation._raw[0], basestring) or \ + not isinstance(presentation._raw[1], basestring): return False return True -def get_node_template(context, presentation, name): +def _get_node_template(context, presentation): node_template_name = presentation._raw[0] node_template = context.presentation.get_from_dict('service_template', 'topology_template', 'node_templates', node_template_name) - if node_template is None: - context.validation.report( - 'substitution mappings %s "%s" refers to an unknown node template: %s' - % (name, presentation._name, safe_repr(node_template_name)), - locator=presentation._locator, level=Issue.FIELD) return node_template + + +def _report_missing_node_template(context, presentation, field): + context.validation.report( + 'substitution mappings {field} "{node_template_mapping}" ' + 'refers to an unknown node template: {node_template_name}'.format( + field=field, + node_template_mapping=presentation._name, + node_template_name=safe_repr(presentation._raw[0])), + locator=presentation._locator, level=Issue.FIELD) + + +def _report_invalid_mapping_format(context, presentation, field): + context.validation.report( + 'substitution mapping {field} "{field_name}" is not a list of 2 strings: {value}'.format( + field=field, + field_name=presentation._name, + value=safe_repr(presentation._raw)), + locator=presentation._locator, level=Issue.FIELD) http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/a048f704/extensions/aria_extension_tosca/simple_v1_0/types.py ---------------------------------------------------------------------- diff --git a/extensions/aria_extension_tosca/simple_v1_0/types.py b/extensions/aria_extension_tosca/simple_v1_0/types.py index 787aac2..0241917 100644 --- a/extensions/aria_extension_tosca/simple_v1_0/types.py +++ b/extensions/aria_extension_tosca/simple_v1_0/types.py @@ -300,12 +300,13 @@ class CapabilityType(ExtensiblePresentation): 'capability_types') @cachedmethod - def _is_descendant(self, context, the_type): - if the_type is None: + def _is_descendant(self, context, other_type): + """returns True iff `other_type` is a descendant of the represented capability type""" + if other_type is None: return False - elif the_type._name == self._name: + elif other_type._name == self._name: return True - return self._is_descendant(context, the_type._get_parent(context)) + return self._is_descendant(context, other_type._get_parent(context)) @cachedmethod def _get_properties(self, context):