def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument str_value = str(value) match = re.match(self.REGEX, str_value) # pylint: disable=no-member if match is None: raise ValueError( 'scalar must be formatted as <scalar> <unit>: %s' % safe_repr(value)) self.factor = float(match.group('scalar')) if self.factor < 0: raise ValueError('scalar is negative: %s' % safe_repr(self.factor)) self.unit = match.group('unit') unit_lower = self.unit.lower() unit_size = None for k, v in self.UNITS.iteritems(): # pylint: disable=no-member if k.lower() == unit_lower: self.unit = k unit_size = v break if unit_size is None: raise ValueError('scalar specified with unsupported unit: %s' % safe_repr(self.unit)) self.value = self.TYPE(self.factor * unit_size) # pylint: disable=no-member
def report(message, constraint): context.validation.report( 'value %s %s per constraint in "%s": %s' % (message, safe_repr(constraint), presentation._name or presentation._container._name, safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_FIELDS)
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 ``node`` field or a general capability type. Used with the :func:`field_validator` decorator for the ``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) capability_variant = presentation._get_capability(context)[1] if capability_variant == 'capability_assignment': capability_definition_validator(field, presentation, context, value, node, node_variant) elif capability_variant == 'capability_type': capability_type_validator(field, presentation, context, value, node, node_variant) else: context.validation.report( 'requirement "%s" refers to an unknown capability definition name or '\ 'type in "%s": %s' % (presentation._name, presentation._container._fullname, safe_repr(value)), locator=presentation._get_child_locator(field.name), level=Issue.BETWEEN_TYPES)
def parse_modelable_entity_name(context, presentation, name, index, value): value = parse_string_expression(context, presentation, name, index, 'the modelable entity name', value) if value == 'SELF': the_self, _ = parse_self(presentation) if the_self is None: raise invalid_modelable_entity_name(name, index, value, presentation._locator, 'a node template or a relationship template') elif value == 'HOST': _, self_variant = parse_self(presentation) if self_variant != 'node_template': raise invalid_modelable_entity_name(name, index, value, presentation._locator, 'a node template') elif (value == 'SOURCE') or (value == 'TARGET'): _, self_variant = parse_self(presentation) if self_variant != 'relationship_template': raise invalid_modelable_entity_name(name, index, value, presentation._locator, 'a relationship template') elif isinstance(value, basestring): node_templates = \ context.presentation.get('service_template', 'topology_template', 'node_templates') \ or {} relationship_templates = \ context.presentation.get('service_template', 'topology_template', 'relationship_templates') \ or {} if (value not in node_templates) and (value not in relationship_templates): raise InvalidValueError( 'function "{0}" parameter {1:d} is not a valid modelable entity name: {2}' .format(name, index + 1, safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_TYPES) return value
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 ``pattern`` field in :class:`ConstraintClause`. """ field.default_validate(presentation, context) value = getattr(presentation, field.name) if value is not None: try: # From TOSCA 1.0 3.5.2.1: # # "Note: Future drafts of this specification will detail the use of regular expressions # and reference an appropriate standardized grammar." # # So we will just use Python's. re.compile(value) except re.error as e: context.validation.report( u'constraint "{0}" is not a valid regular expression in "{1}": {2}' .format(field.name, presentation._fullname, safe_repr(value)), locator=presentation._get_child_locator(field.name), level=Issue.FIELD, exception=e)
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_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
def _report_invalid_mapping_format(context, presentation, field): context.validation.report( u'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)
def __init__(self, context, presentation, argument): self.locator = presentation._locator if (not isinstance( argument, list)) or (len(argument) < 2) or (len(argument) > 4): raise InvalidValueError( u'function "get_artifact" argument must be a list of 2 to 4 parameters: {0}' .format(safe_repr(argument)), locator=self.locator) self.modelable_entity_name = parse_string_expression( context, presentation, 'get_artifact', 0, 'modelable entity name', argument[0]) self.artifact_name = parse_string_expression(context, presentation, 'get_artifact', 1, 'the artifact name', argument[1]) if len(argument) > 2: self.location = parse_string_expression( context, presentation, 'get_artifact', 2, 'the location or "LOCAL_FILE"', argument[2]) else: self.location = None if len(argument) > 3: self.remove = parse_bool(context, presentation, 'get_artifact', 3, 'the removal flag', argument[3]) else: self.remove = None
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 validate_substitution_mappings_requirement(context, presentation): # Validate that the requirement in substitution_mapping is defined in the substitution node type print "Requiremnt presetation -->", presentation.__dict__ print "*******Requirement container -->", presentation._container.__dict__ substitution_node_type = presentation._container._get_type(context) print ("Substitution mapping reqruiement node type -------------------> ", substitution_node_type) print ("Substitution mapping node requirement type dict-------------------> ", substitution_node_type.__dict__) print ("Substitution mapping node requirement type container -------------------> ", substitution_node_type.__dict__['_container']) 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( u'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 if not _validate_mapping_format(presentation): _report_invalid_mapping_format(context, presentation, field='requirement') return # 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 else: context.validation.report( u'substitution mapping requirement "{0}" refers to an unknown requirement of node ' u'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 # 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 substitution_type_requirement_capability_type._is_descendant( context, node_template_requirement_capability_type): context.validation.report( u'substitution mapping requirement "{0}" of capability type "{1}" is not a descendant ' u'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)
def _report_missing_node_template(context, presentation, field): context.validation.report( u'substitution mappings {field} "{node_template_mapping}" ' u'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 invalid_value(name, index, the_type, explanation, value, locator): return InvalidValueError('function "{0}" {1} is not {2}{3}: {4}'.format( name, 'parameter {0:d}'.format(index + 1) if index is not None else 'argument', the_type, ', {0}'.format(explanation) if explanation is not None else '', safe_repr(value)), locator=locator, level=Issue.FIELD)
def invalid_value(name, index, the_type, explanation, value, locator): return InvalidValueError( 'function "%s" %s is not %s%s: %s' % (name, ('parameter %d' % (index + 1)) if index is not None else 'argument', the_type, (', %s' % explanation) if explanation is not None else '', safe_repr(value)), locator=locator, level=Issue.FIELD)
def report_issue_for_bad_format(context, presentation, the_type, value, aspect, e): if aspect == 'default': aspect = '"default" value' elif aspect is not None: aspect = '"%s" aspect' % aspect if aspect is not None: context.validation.report('%s for field "%s" is not a valid "%s": %s' % (aspect, presentation._name or presentation._container._name, get_data_type_name(the_type), safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_FIELDS, exception=e) else: context.validation.report('field "%s" is not a valid "%s": %s' % (presentation._name or presentation._container._name, get_data_type_name(the_type), safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_FIELDS, exception=e)
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 ``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 report_issue_for_bad_format(context, presentation, the_type, value, aspect, e): if aspect == 'default': aspect = '"default" value' elif aspect is not None: aspect = u'"{0}" aspect'.format(aspect) if aspect is not None: context.validation.report(u'{0} for field "{1}" is not a valid "{2}": {3}' .format(aspect, presentation._name or presentation._container._name, get_data_type_name(the_type), safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_FIELDS, exception=e) else: context.validation.report(u'field "{0}" is not a valid "{1}": {2}' .format(presentation._name or presentation._container._name, get_data_type_name(the_type), safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_FIELDS, exception=e)
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)
def validate_data_type_name(context, presentation): """ Makes sure the complex data type's name is not that of a built-in type. """ name = presentation._name if get_primitive_data_type(name) is not None: context.validation.report('data type name is that of a built-in type: %s' % safe_repr(name), locator=presentation._locator, level=Issue.BETWEEN_TYPES)
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) return False return True
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 ``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)
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))
def coerce_value(context, presentation, the_type, entry_schema, constraints, value, aspect=None): # pylint: disable=too-many-return-statements """ Returns the value after it's coerced to its type, reporting validation errors if it cannot be coerced. Supports both complex data types and primitives. Data types can use the ``coerce_value`` extension to hook their own specialized function. If the extension is present, we will delegate to that hook. """ # TODO: should support models as well as presentations is_function, func = get_function(context, presentation, value) if is_function: return func if the_type is None: return value if the_type == None.__class__: if value is not None: context.validation.report( 'field "%s" is of type "null" but has a non-null value: %s' % (presentation._name, safe_repr(value)), locator=presentation._locator, level=Issue.BETWEEN_FIELDS) return None # Delegate to 'coerce_value' extension if hasattr(the_type, '_get_extension'): coerce_value_fn_name = the_type._get_extension('coerce_value') if coerce_value_fn_name is not None: if value is None: return None coerce_value_fn = import_fullname(coerce_value_fn_name) return coerce_value_fn(context, presentation, the_type, entry_schema, constraints, value, aspect) if hasattr(the_type, '_coerce_value'): # Delegate to '_coerce_value' (likely a DataType instance) return the_type._coerce_value(context, presentation, entry_schema, constraints, value, aspect) # Coerce to primitive type return coerce_to_primitive(context, presentation, the_type, constraints, value, aspect)
def __init__(self, entry_schema, constraints, value, aspect): # pylint: disable=unused-argument if not isinstance(value, list): raise ValueError('range value is not a list: %s' % safe_repr(value)) if len(value) != 2: raise ValueError( 'range value does not have exactly 2 elements: %s' % safe_repr(value)) def is_int(v): return isinstance(v, int) and (not isinstance(v, bool) ) # In Python bool is an int if not is_int(value[0]): raise ValueError( 'lower bound of range is not a valid integer: %s' % safe_repr(value[0])) if value[1] != 'UNBOUNDED': if not is_int(value[1]): raise ValueError( 'upper bound of range is not a valid integer or "UNBOUNDED": %s' % safe_repr(value[0])) if value[0] >= value[1]: raise ValueError( 'upper bound of range is not greater than the lower bound: %s >= %s' % (safe_repr(value[0]), safe_repr(value[1]))) self.value = value
def get_node_template(context, presentation, name): 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 __init__(self, context, presentation, argument): self.locator = presentation._locator if (not isinstance(argument, list)) or (len(argument) < 2): raise InvalidValueError( 'function "get_attribute" argument must be a list of at least 2 string expressions:' ' {0}'.format(safe_repr(argument)), locator=self.locator) self.modelable_entity_name = parse_modelable_entity_name( context, presentation, 'get_attribute', 0, argument[0]) # The first of these will be tried as a req-or-cap name: self.nested_attribute_name_or_index = argument[1:]
def getter(field, presentation, context=None): raw = field.default_get(presentation, context) if (raw is None) or (allow_null and (raw is NULL)): return raw try: return cls(None, None, raw, None) except ValueError as e: raise InvalidValueError( u'{0} is not a valid "{1}" in "{2}": {3}'.format( field.full_name, full_type_name(cls), presentation._name, safe_repr(raw)), cause=e, locator=field.get_locator(raw))
def __init__(self, context, presentation, argument): self.locator = presentation._locator self.node_type_name = parse_string_expression(context, presentation, 'get_nodes_of_type', None, 'the node type name', argument) if isinstance(self.node_type_name, basestring): node_types = context.presentation.get('service_template', 'node_types') if (node_types is None) or (self.node_type_name not in node_types): raise InvalidValueError( 'function "get_nodes_of_type" argument is not a valid node type name: {0}' .format(safe_repr(argument)), locator=self.locator)
def __evaluate__(self, container_holder): service = container_holder.service if service is None: raise CannotEvaluateFunctionException() value = service.inputs.get(self.input_property_name) if value is not None: value = value.value return Evaluation(value, False) # We never return final evaluations! raise InvalidValueError( 'function "get_input" argument is not a valid input name: {0}' .format(safe_repr(self.input_property_name)), locator=self.locator)
def __init__(self, context, presentation, argument): self.locator = presentation._locator if not isinstance(argument, list): raise InvalidValueError( 'function "concat" argument must be a list of string expressions: {0}' .format(safe_repr(argument)), locator=self.locator) string_expressions = [] for index, an_argument in enumerate(argument): string_expressions.append(parse_string_expression(context, presentation, 'concat', index, None, an_argument)) self.string_expressions = FrozenList(string_expressions)
def validate_substitution_mappings_capability(context, presentation): # 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 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( u'substitution mapping capability "{0}" ' u'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 if not _validate_mapping_format(presentation): _report_invalid_mapping_format(context, presentation, field='capability') return # 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 node_template_capability is None: context.validation.report( u'substitution mapping capability "{0}" refers to an unknown ' u'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 # 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 substitution_type_capability_type._is_descendant(context, node_template_capability_type): context.validation.report( u'node template capability type "{0}" is not a descendant of substitution mapping ' u'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)