Esempio n. 1
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))
Esempio n. 2
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
                 })
Esempio n. 3
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)
Esempio n. 4
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.'))
Esempio n. 5
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)
Esempio n. 6
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
Esempio n. 7
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)
Esempio n. 8
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)
Esempio n. 9
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.'))
Esempio n. 10
0
 def _validate_default(self, context):
     if self.default is not None:
         try:
             self.validate_constraints(self.default, context,
                                       [CustomConstraint])
         except (ValueError, TypeError) as exc:
             raise exception.InvalidSchemaError(
                 message=_('Invalid default %(default)s (%(exc)s)') %
                 dict(default=self.default, exc=exc))
Esempio n. 11
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(
                _LW("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
Esempio n. 12
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)
         elif self.type == self.LIST and isinstance(self.default, list):
             default_value = [(six.text_type(x)) for x in self.default]
         try:
             self.validate_constraints(default_value, context,
                                       [constr.CustomConstraint])
         except (ValueError, TypeError,
                 exception.StackValidationFailed) as exc:
             raise exception.InvalidSchemaError(
                 message=_('Invalid default %(default)s (%(exc)s)') %
                 dict(default=self.default, exc=exc))
Esempio n. 13
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"))
Esempio n. 14
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)
Esempio n. 15
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)