Пример #1
0
    def __init__(self, data_type, description=None,
                 default=None, schema=None,
                 required=False, constraints=None, label=None):
        self._len = None
        self.label = label
        self.type = data_type
        if self.type not in self.TYPES:
            raise exception.InvalidSchemaError(
                message=_('Invalid type (%s)') % self.type)

        self.description = description
        self.required = required

        if isinstance(schema, type(self)):
            if self.type != self.LIST:
                msg = _('Single schema valid only for '
                        '%(ltype)s, not %(utype)s') % dict(ltype=self.LIST,
                                                           utype=self.type)
                raise exception.InvalidSchemaError(message=msg)

            self.schema = AnyIndexDict(schema)
        else:
            self.schema = schema
        if self.schema is not None and self.type not in (self.LIST,
                                                         self.MAP):
            msg = _('Schema valid only for %(ltype)s or '
                    '%(mtype)s, not %(utype)s') % dict(ltype=self.LIST,
                                                       mtype=self.MAP,
                                                       utype=self.type)
            raise exception.InvalidSchemaError(message=msg)

        self.constraints = constraints or []
        self.default = default
Пример #2
0
    def from_legacy(cls, schema_dict):
        """
        Return a Property Schema object from a legacy schema dictionary.
        """

        # Check for fully-fledged Schema objects
        if isinstance(schema_dict, cls):
            return schema_dict

        unknown = [k for k in schema_dict if k not in SCHEMA_KEYS]
        if unknown:
            raise exception.InvalidSchemaError(message=_('Unknown key(s) %s') %
                                               unknown)

        def constraints():
            def get_num(key):
                val = schema_dict.get(key)
                if val is not None:
                    val = Schema.str_to_num(val)
                return val

            if MIN_VALUE in schema_dict or MAX_VALUE in schema_dict:
                yield constr.Range(get_num(MIN_VALUE), get_num(MAX_VALUE))
            if MIN_LENGTH in schema_dict or MAX_LENGTH in schema_dict:
                yield constr.Length(get_num(MIN_LENGTH), get_num(MAX_LENGTH))
            if ALLOWED_VALUES in schema_dict:
                yield constr.AllowedValues(schema_dict[ALLOWED_VALUES])
            if ALLOWED_PATTERN in schema_dict:
                yield constr.AllowedPattern(schema_dict[ALLOWED_PATTERN])

        try:
            data_type = schema_dict[TYPE]
        except KeyError:
            raise exception.InvalidSchemaError(message=_('No %s specified') %
                                               TYPE)

        if SCHEMA in schema_dict:
            if data_type == Schema.LIST:
                ss = cls.from_legacy(schema_dict[SCHEMA])
            elif data_type == Schema.MAP:
                schema_dicts = schema_dict[SCHEMA].items()
                ss = dict((n, cls.from_legacy(sd)) for n, sd in schema_dicts)
            else:
                raise exception.InvalidSchemaError(
                    message=_('%(schema)s supplied for %(type)s %(data)s') %
                    dict(schema=SCHEMA, type=TYPE, data=data_type))
        else:
            ss = None

        return cls(data_type,
                   description=schema_dict.get(DESCRIPTION),
                   default=schema_dict.get(DEFAULT),
                   schema=ss,
                   required=schema_dict.get(REQUIRED, False),
                   constraints=list(constraints()),
                   implemented=schema_dict.get(IMPLEMENTED, True),
                   update_allowed=schema_dict.get(UPDATE_ALLOWED, False),
                   immutable=schema_dict.get(IMMUTABLE, False))
Пример #3
0
 def _check_dict(schema_dict, allowed_keys, entity):
     if not isinstance(schema_dict, dict):
         raise exception.InvalidSchemaError(
             message=_("Invalid %s, expected a mapping") % entity)
     for key in schema_dict:
         if key not in allowed_keys:
             raise exception.InvalidSchemaError(
                 message=_("Invalid key '%(key)s' for %(entity)s") % {
                     "key": key, "entity": entity})
Пример #4
0
    def __init__(self, min=None, max=None, description=None):
        if min is max is None:
            raise exception.InvalidSchemaError(
                message=_('A length constraint must have a min value and/or '
                          'a max value specified.'))

        super(Length, self).__init__(min, max, description)

        for param in (min, max):
            if not isinstance(param, (six.integer_types, type(None))):
                msg = _('min/max length must be integral')
                raise exception.InvalidSchemaError(message=msg)
Пример #5
0
    def _validate_dict(cls, param_name, schema_dict):
        cls._check_dict(schema_dict, cls.PARAMETER_KEYS,
                        "parameter (%s)" % param_name)

        if cls.TYPE not in schema_dict:
            raise exception.InvalidSchemaError(
                message=_("Missing parameter type for parameter: %s") %
                param_name)

        if not isinstance(schema_dict.get(cls.TAGS, []), list):
            raise exception.InvalidSchemaError(
                message=_("Tags property should be a list for parameter: %s") %
                param_name)
Пример #6
0
    def __init__(self, min=None, max=None, description=None):
        super(Range, self).__init__(description)
        self.min = min
        self.max = max

        for param in (min, max):
            if not isinstance(param, (float, six.integer_types, type(None))):
                raise exception.InvalidSchemaError(
                    message=_('min/max must be numeric'))

        if min is max is None:
            raise exception.InvalidSchemaError(
                message=_('A range constraint must have a min value and/or '
                          'a max value specified.'))
Пример #7
0
 def _constraint_from_def(cls, constraint):
     desc = constraint.get(DESCRIPTION)
     if RANGE in constraint:
         cdef = constraint.get(RANGE)
         cls._check_dict(cdef, RANGE_KEYS, 'range constraint')
         return constr.Range(parameters.Schema.get_num(MIN, cdef),
                             parameters.Schema.get_num(MAX, cdef),
                             desc)
     elif LENGTH in constraint:
         cdef = constraint.get(LENGTH)
         cls._check_dict(cdef, RANGE_KEYS, 'length constraint')
         return constr.Length(parameters.Schema.get_num(MIN, cdef),
                              parameters.Schema.get_num(MAX, cdef),
                              desc)
     elif ALLOWED_VALUES in constraint:
         cdef = constraint.get(ALLOWED_VALUES)
         return constr.AllowedValues(cdef, desc)
     elif ALLOWED_PATTERN in constraint:
         cdef = constraint.get(ALLOWED_PATTERN)
         return constr.AllowedPattern(cdef, desc)
     elif CUSTOM_CONSTRAINT in constraint:
         cdef = constraint.get(CUSTOM_CONSTRAINT)
         return constr.CustomConstraint(cdef, desc)
     else:
         raise exception.InvalidSchemaError(
             message=_("No constraint expressed"))
Пример #8
0
    def validate(self, with_value=True):
        for (key, prop) in self.props.items():
            # check that update_allowed and immutable
            # do not contradict each other
            if prop.update_allowed() and prop.immutable():
                msg = _("Property %(prop)s: %(ua)s and %(im)s "
                        "cannot both be True") % {
                            'prop': key,
                            'ua': prop.schema.UPDATE_ALLOWED,
                            'im': prop.schema.IMMUTABLE
                        }
                raise exception.InvalidSchemaError(message=msg)

            if with_value:
                try:
                    self._get_property_value(key, validate=True)
                except ValueError as e:
                    msg = _("Property error : %s") % e
                    raise exception.StackValidationFailed(message=msg)

            # are there unimplemented Properties
            if not prop.implemented() and key in self.data:
                msg = _("Property %s not implemented yet") % key
                raise exception.StackValidationFailed(message=msg)

        for key in self.data:
            if key not in self.props:
                msg = _("Unknown Property %s") % key
                raise exception.StackValidationFailed(message=msg)
Пример #9
0
 def __init__(self, allowed, description=None):
     super(AllowedValues, self).__init__(description)
     if (not isinstance(allowed, collections.Sequence)
             or isinstance(allowed, six.string_types)):
         raise exception.InvalidSchemaError(
             message=_('AllowedValues must be a list'))
     self.allowed = tuple(allowed)
Пример #10
0
 def __init__(self, pattern, description=None):
     super(AllowedPattern, self).__init__(description)
     if not isinstance(pattern, six.string_types):
         raise exception.InvalidSchemaError(
             message=_('AllowedPattern must be a string'))
     self.pattern = pattern
     self.match = re.compile(pattern).match
Пример #11
0
    def validate(self, validate_value=True, context=None):
        """Validates the parameter.

        This method validates if the parameter's schema is valid,
        and if the default value - if present - or the user-provided
        value for the parameter comply with the schema.
        """
        err_msg = _("Parameter '%(name)s' is invalid: %(exp)s")

        try:
            self.schema.validate(context)

            if not validate_value:
                return

            if self.user_value is not None:
                self._validate(self.user_value, context)
            elif self.has_default():
                self._validate(self.default(), context)
            else:
                raise exception.UserParameterMissing(key=self.name)
        except exception.StackValidationFailed as ex:
            msg = err_msg % dict(name=self.name, exp=six.text_type(ex))
            raise exception.StackValidationFailed(message=msg)
        except exception.InvalidSchemaError as ex:
            msg = err_msg % dict(name=self.name, exp=six.text_type(ex))
            raise exception.InvalidSchemaError(message=msg)
Пример #12
0
    def _validate_dict(cls, param_name, schema_dict):
        cls._check_dict(schema_dict, cls.PARAMETER_KEYS,
                        "parameter (%s)" % param_name)

        if cls.TYPE not in schema_dict:
            raise exception.InvalidSchemaError(
                message=_("Missing parameter type for parameter: %s") %
                param_name)
Пример #13
0
 def _validate_default(self, context):
     if self.default is not None:
         default_value = self.default
         if self.type == self.LIST and not isinstance(self.default, list):
             try:
                 default_value = self.default.split(',')
             except (KeyError, AttributeError) as err:
                 raise exception.InvalidSchemaError(
                     message=_('Default must be a comma-delimited list '
                               'string: %s') % err)
         try:
             self.validate_constraints(default_value, context)
         except (ValueError, TypeError,
                 exception.StackValidationFailed) as exc:
             raise exception.InvalidSchemaError(
                 message=_('Invalid default %(default)s (%(exc)s)') %
                 dict(default=self.default, exc=exc))
Пример #14
0
 def validate_with_client(self, client, resource_id):
     if self.resource_client_name and self.resource_getter_name:
         getattr(client.client_plugin(self.resource_client_name),
                 self.resource_getter_name)(resource_id)
     else:
         raise exception.InvalidSchemaError(
             message=_('Client name and resource getter name must be '
                       'specified.'))
Пример #15
0
 def _validate_default(self, context):
     if self.default is not None:
         try:
             self.validate_constraints(self.default, context)
         except (ValueError, TypeError) as exc:
             raise exception.InvalidSchemaError(
                 message=_('Invalid default %(default)s (%(exc)s)') %
                 dict(default=self.default, exc=exc))
Пример #16
0
    def __init__(self,
                 data_type,
                 description=None,
                 default=None,
                 schema=None,
                 required=False,
                 constraints=None,
                 label=None,
                 immutable=False):
        self._len = None
        self.label = label
        self.type = data_type
        if self.type not in self.TYPES:
            raise exception.InvalidSchemaError(message=_('Invalid type (%s)') %
                                               self.type)

        if required and default is not None:
            LOG.warning(
                "Option 'required=True' should not be used with "
                "any 'default' value (%s)", default)

        self.description = description
        self.required = required
        self.immutable = immutable

        if isinstance(schema, type(self)):
            if self.type != self.LIST:
                msg = _('Single schema valid only for '
                        '%(ltype)s, not %(utype)s') % dict(ltype=self.LIST,
                                                           utype=self.type)
                raise exception.InvalidSchemaError(message=msg)

            self.schema = AnyIndexDict(schema)
        else:
            self.schema = schema
        if self.schema is not None and self.type not in (self.LIST, self.MAP):
            msg = _('Schema valid only for %(ltype)s or '
                    '%(mtype)s, not %(utype)s') % dict(
                        ltype=self.LIST, mtype=self.MAP, utype=self.type)
            raise exception.InvalidSchemaError(message=msg)

        self.constraints = constraints or []
        self.default = default
Пример #17
0
 def validate(self, context=None):
     super(Schema, self).validate()
     # check that update_allowed and immutable
     # do not contradict each other
     if self.update_allowed and self.immutable:
         msg = _("Options %(ua)s and %(im)s "
                 "cannot both be True") % {
                     'ua': UPDATE_ALLOWED,
                     'im': IMMUTABLE}
         raise exception.InvalidSchemaError(message=msg)
Пример #18
0
    def __init__(self, step=None, offset=None, description=None):
        super(Modulo, self).__init__(description)
        self.step = step
        self.offset = offset

        if step is None or offset is None:
            raise exception.InvalidSchemaError(
                message=_('A modulo constraint must have a step value and '
                          'an offset value specified.'))

        for param in (step, offset):
            if not isinstance(param, (float, six.integer_types, type(None))):
                raise exception.InvalidSchemaError(
                    message=_('step/offset must be numeric'))

            if not int(param) == param:
                raise exception.InvalidSchemaError(
                    message=_('step/offset must be integer'))

        step, offset = int(step), int(offset)

        if step == 0:
            raise exception.InvalidSchemaError(message=_('step cannot be 0.'))

        if abs(offset) >= abs(step):
            raise exception.InvalidSchemaError(
                message=_('offset must be smaller (by absolute value) '
                          'than step.'))

        if step * offset < 0:
            raise exception.InvalidSchemaError(
                message=_('step and offset must be both positive or both '
                          'negative.'))
Пример #19
0
    def validate_schema(self, current_schema):
        msg = _('Properties group schema incorrectly specified.')
        if not isinstance(current_schema, dict):
            msg = _('%(msg)s Schema should be a mapping, found '
                    '%(t)s instead.') % dict(msg=msg, t=type(current_schema))
            raise exception.InvalidSchemaError(message=msg)
        if len(current_schema.keys()) > 1:
            msg = _("%(msg)s Schema should be one-key dict.") % dict(msg=msg)
            raise exception.InvalidSchemaError(message=msg)

        current_key = next(iter(current_schema))
        if current_key not in OPERATORS:
            msg = _('%(msg)s Properties group schema key should be one of the '
                    'operators: %(op)s.') % dict(msg=msg,
                                                 op=', '.join(OPERATORS))
            raise exception.InvalidSchemaError(message=msg)
        if not isinstance(current_schema[current_key], list):
            msg = _("%(msg)s Schemas' values should be lists of properties "
                    "names or nested schemas.") % dict(msg=msg)
            raise exception.InvalidSchemaError(message=msg)
        next_msg = _('%(msg)s List items should be properties list-type names '
                     'with format "[prop, prop_child, prop_sub_child, ...]" '
                     'or nested properties group schemas.') % dict(msg=msg)
        for item in current_schema[current_key]:
            if isinstance(item, dict):
                self.validate_schema(item)
            elif isinstance(item, list):
                for name in item:
                    if not isinstance(name, six.string_types):
                        raise exception.InvalidSchemaError(message=next_msg)
            else:
                raise exception.InvalidSchemaError(message=next_msg)
Пример #20
0
        def constraints():
            constraints = schema_dict.get(cls.CONSTRAINTS)
            if constraints is None:
                return

            if not isinstance(constraints, list):
                raise exception.InvalidSchemaError(
                    message=_("Invalid parameter constraints for parameter "
                              "%s, expected a list") % param_name)

            for constraint in constraints:
                cls._check_dict(constraint, PARAM_CONSTRAINTS,
                                'parameter constraints')
                desc = constraint.get(DESCRIPTION)
                if RANGE in constraint:
                    cdef = constraint.get(RANGE)
                    cls._check_dict(cdef, RANGE_KEYS, 'range constraint')
                    yield constr.Range(parameters.Schema.get_num(MIN, cdef),
                                       parameters.Schema.get_num(MAX, cdef),
                                       desc)
                elif LENGTH in constraint:
                    cdef = constraint.get(LENGTH)
                    cls._check_dict(cdef, RANGE_KEYS, 'length constraint')
                    yield constr.Length(parameters.Schema.get_num(MIN, cdef),
                                        parameters.Schema.get_num(MAX, cdef),
                                        desc)
                elif ALLOWED_VALUES in constraint:
                    cdef = constraint.get(ALLOWED_VALUES)
                    yield constr.AllowedValues(cdef, desc)
                elif ALLOWED_PATTERN in constraint:
                    cdef = constraint.get(ALLOWED_PATTERN)
                    yield constr.AllowedPattern(cdef, desc)
                elif CUSTOM_CONSTRAINT in constraint:
                    cdef = constraint.get(CUSTOM_CONSTRAINT)
                    yield constr.CustomConstraint(cdef, desc)
                else:
                    raise exception.InvalidSchemaError(
                        message=_("No constraint expressed"))
Пример #21
0
        def constraints():
            constraints = schema_dict.get(cls.CONSTRAINTS)
            if constraints is None:
                return

            if not isinstance(constraints, list):
                raise exception.InvalidSchemaError(
                    message=_("Invalid parameter constraints for parameter "
                              "%s, expected a list") % param_name)

            for constraint in constraints:
                cls._check_dict(constraint, PARAM_CONSTRAINTS,
                                'parameter constraints')
                yield cls._constraint_from_def(constraint)
Пример #22
0
    def validate(self, with_value=True):
        try:
            for key in self.data:
                if key not in self.props:
                    msg = _("Unknown Property %s") % key
                    raise exception.StackValidationFailed(message=msg)

            for (key, prop) in self.props.items():
                # check that update_allowed and immutable
                # do not contradict each other
                if prop.update_allowed() and prop.immutable():
                    msg = _("Property %(prop)s: %(ua)s and %(im)s "
                            "cannot both be True") % {
                                'prop': key,
                                'ua': prop.schema.UPDATE_ALLOWED,
                                'im': prop.schema.IMMUTABLE
                            }
                    raise exception.InvalidSchemaError(message=msg)

                if with_value:
                    try:
                        self._get_property_value(key, validate=True)
                    except exception.StackValidationFailed as ex:
                        path = [key]
                        path.extend(ex.path)
                        raise exception.StackValidationFailed(
                            path=path, message=ex.error_message)
                    except ValueError as e:
                        if prop.required() and key not in self.data:
                            path = []
                        else:
                            path = [key]
                        raise exception.StackValidationFailed(
                            path=path, message=six.text_type(e))

                # are there unimplemented Properties
                if not prop.implemented() and key in self.data:
                    msg = _("Property %s not implemented yet") % key
                    raise exception.StackValidationFailed(message=msg)
        except exception.StackValidationFailed as ex:
            # NOTE(prazumovsky): should reraise exception for adding specific
            # error name and error_prefix to path for correct error message
            # building.
            path = self.error_prefix
            path.extend(ex.path)
            raise exception.StackValidationFailed(error=ex.error
                                                  or 'Property error',
                                                  path=path,
                                                  message=ex.error_message)
Пример #23
0
    def validate(self, context=None):
        """Validates the schema.

        This method checks if the schema itself is valid, and if the
        default value - if present - complies to the schema's constraints.
        """
        for c in self.constraints:
            if not self._is_valid_constraint(c):
                err_msg = _('%(name)s constraint '
                            'invalid for %(utype)s') % dict(
                                name=type(c).__name__, utype=self.type)
                raise exception.InvalidSchemaError(message=err_msg)

        self._validate_default(context)
        # validated nested schema(ta)
        if self.schema:
            if isinstance(self.schema, AnyIndexDict):
                self.schema.value.validate(context)
            else:
                for nested_schema in six.itervalues(self.schema):
                    nested_schema.validate(context)