Exemple #1
0
    def update(self, req, id, body):
        context = req.environ['cinder.context']
        authorize_update(context)
        self.validate_string_length(id, 'quota_set_name',
                                    min_length=1, max_length=255)

        project_id = id
        self.assert_valid_body(body, 'quota_set')

        # Get the optional argument 'skip_validation' from body,
        # if skip_validation is False, then validate existing resource.
        skip_flag = body.get('skip_validation', True)
        if not utils.is_valid_boolstr(skip_flag):
            msg = _("Invalid value '%s' for skip_validation.") % skip_flag
            raise exception.InvalidParameterValue(err=msg)
        skip_flag = strutils.bool_from_string(skip_flag)

        bad_keys = []

        # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
        # we figure out if we have any bad keys.
        for key, value in body['quota_set'].items():
            if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
                bad_keys.append(key)
                continue

        if len(bad_keys) > 0:
            msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(),
        # we validate the quota limits to ensure that we can bail out if
        # any of the items in the set is bad. Meanwhile we validate value
        # to ensure that the value can't be lower than number of existing
        # resources.
        quota_values = QUOTAS.get_project_quotas(context, project_id)
        valid_quotas = {}
        for key in body['quota_set'].keys():
            if key in NON_QUOTA_KEYS:
                continue

            valid_quotas[key] = self.validate_integer(
                body['quota_set'][key], key, min_value=-1,
                max_value=db.MAX_INT)

            if not skip_flag:
                self._validate_existing_resource(key, value, quota_values)

        # NOTE(ankit): Pass #3 - At this point we know that all the keys and
        # values are valid and we can iterate and update them all in one shot
        # without having to worry about rolling back etc as we have done
        # the validation up front in the 2 loops above.
        for key, value in valid_quotas.items():
            try:
                db.quota_update(context, project_id, key, value)
            except exception.ProjectQuotaNotFound:
                db.quota_create(context, project_id, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()
        return {'quota_set': self._get_quotas(context, id)}
Exemple #2
0
    def get_all(self,
                context,
                search_opts=None,
                marker=None,
                limit=None,
                offset=None,
                sort_keys=None,
                sort_dirs=None):
        check_policy(context, 'get_all')

        search_opts = search_opts or {}

        all_tenants = search_opts.pop('all_tenants', '0')
        if not utils.is_valid_boolstr(all_tenants):
            msg = _("all_tenants must be a boolean, got '%s'.") % all_tenants
            raise exception.InvalidParameterValue(err=msg)

        if context.is_admin and strutils.bool_from_string(all_tenants):
            backups = objects.BackupList.get_all(context, search_opts, marker,
                                                 limit, offset, sort_keys,
                                                 sort_dirs)
        else:
            backups = objects.BackupList.get_all_by_project(
                context, context.project_id, search_opts, marker, limit,
                offset, sort_keys, sort_dirs)

        return backups
Exemple #3
0
    def _update(self, req, id, body):
        # Update description for a given volume type.
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        description = vol_type.get('description')
        name = vol_type.get('name')
        is_public = vol_type.get('is_public')

        # Name and description can not be both None.
        # If name specified, name can not be empty.
        if name and len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name is None and description is None and is_public is None:
            msg = _("Specify volume type name, description, is_public or "
                    "a combination thereof.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if is_public is not None and not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if name:
            utils.check_string_length(name, 'Type name',
                                      min_length=1, max_length=255)

        if description is not None:
            utils.check_string_length(description, 'Type description',
                                      min_length=0, max_length=255)

        try:
            volume_types.update(context, id, name, description,
                                is_public=is_public)
            # Get the updated
            vol_type = volume_types.get_volume_type(context, id)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.update', vol_type)

        except exception.VolumeTypeNotFound as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, id=id)
            raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeUpdateFailed as err:
            self._notify_volume_type_error(
                context, 'volume_type.update', err, volume_type=vol_type)
            raise webob.exc.HTTPInternalServerError(
                explanation=six.text_type(err))

        return self._view_builder.show(req, vol_type)
Exemple #4
0
    def create(self, req, body):
        """Creates a new snapshot."""
        kwargs = {}
        context = req.environ['cinder.context']

        if not self.is_valid_body(body, 'snapshot'):
            raise exc.HTTPUnprocessableEntity()

        snapshot = body['snapshot']
        kwargs['metadata'] = snapshot.get('metadata', None)

        volume_id = snapshot['volume_id']
        volume = self.volume_api.get(context, volume_id)
        force = snapshot.get('force', False)
        msg = _("Create snapshot from volume %s")
        LOG.audit(msg, volume_id, context=context)

        if not utils.is_valid_boolstr(force):
            msg = _("Invalid value '%s' for force. ") % force
            raise exception.InvalidParameterValue(err=msg)

        if strutils.bool_from_string(force):
            new_snapshot = self.volume_api.create_snapshot_force(
                context, volume, snapshot.get('display_name'),
                snapshot.get('display_description'), **kwargs)
        else:
            new_snapshot = self.volume_api.create_snapshot(
                context, volume, snapshot.get('display_name'),
                snapshot.get('display_description'), **kwargs)

        retval = _translate_snapshot_detail_view(context, new_snapshot)

        return {'snapshot': retval}
Exemple #5
0
    def create(self, req, body):
        """Creates a new snapshot."""
        context = req.environ["cinder.context"]

        if not self.is_valid_body(body, "snapshot"):
            raise exc.HTTPUnprocessableEntity()

        snapshot = body["snapshot"]
        volume_id = snapshot["volume_id"]
        volume = self.volume_api.get(context, volume_id)
        force = snapshot.get("force", False)
        msg = _("Create snapshot from volume %s")
        LOG.audit(msg, volume_id, context=context)

        if not utils.is_valid_boolstr(force):
            msg = _("Invalid value '%s' for force. ") % force
            raise exception.InvalidParameterValue(err=msg)

        if utils.bool_from_str(force):
            new_snapshot = self.volume_api.create_snapshot_force(
                context, volume, snapshot.get("display_name"), snapshot.get("display_description")
            )
        else:
            new_snapshot = self.volume_api.create_snapshot(
                context, volume, snapshot.get("display_name"), snapshot.get("display_description")
            )

        retval = _translate_snapshot_detail_view(context, new_snapshot)

        return {"snapshot": retval}
Exemple #6
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        utils.validate_extra_specs(specs)
        is_public = vol_type.get('os-volume-type-access:is_public', True)

        if name is None or len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        utils.check_string_length(name,
                                  'Type name',
                                  min_length=1,
                                  max_length=255)

        if description is not None:
            utils.check_string_length(description,
                                      'Type description',
                                      min_length=0,
                                      max_length=255)

        if not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            volume_types.create(context,
                                name,
                                specs,
                                is_public,
                                description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(context, 'volume_type.create',
                                          vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(context,
                                           'volume_type.create',
                                           err,
                                           volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeNotFoundByName as err:
            self._notify_volume_type_error(context,
                                           'volume_type.create',
                                           err,
                                           name=name)
            raise webob.exc.HTTPNotFound(explanation=err.msg)

        return self._view_builder.show(req, vol_type)
Exemple #7
0
    def create(self, req, body):
        """Creates a new snapshot."""
        kwargs = {}
        context = req.environ['cinder.context']

        if not self.is_valid_body(body, 'snapshot'):
            msg = (_("Missing required element '%s' in request body") %
                   'snapshot')
            raise exc.HTTPBadRequest(explanation=msg)

        snapshot = body['snapshot']
        kwargs['metadata'] = snapshot.get('metadata', None)

        try:
            volume_id = snapshot['volume_id']
        except KeyError:
            msg = _("'volume_id' must be specified")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            volume = self.volume_api.get(context, volume_id)
        except exception.NotFound:
            msg = _("Volume could not be found")
            raise exc.HTTPNotFound(explanation=msg)
        force = snapshot.get('force', False)
        msg = _("Create snapshot from volume %s")
        LOG.info(msg, volume_id, context=context)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in snapshot:
            snapshot['display_name'] = snapshot.get('name')
            del snapshot['name']

        if not utils.is_valid_boolstr(force):
            msg = _("Invalid value '%s' for force. ") % force
            raise exception.InvalidParameterValue(err=msg)

        if strutils.bool_from_string(force):
            new_snapshot = self.volume_api.create_snapshot_force(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('description'),
                **kwargs)
        else:
            new_snapshot = self.volume_api.create_snapshot(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('description'),
                **kwargs)
        req.cache_db_snapshot(new_snapshot)

        retval = _translate_snapshot_detail_view(context, new_snapshot)

        return {'snapshot': retval}
Exemple #8
0
    def _create(self, req, body):
        """Creates a new volume type."""
        context = req.environ['cinder.context']
        authorize(context)

        self.assert_valid_body(body, 'volume_type')

        vol_type = body['volume_type']
        name = vol_type.get('name', None)
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        utils.validate_dictionary_string_length(specs)
        is_public = vol_type.get('os-volume-type-access:is_public', True)

        if name is None or len(name.strip()) == 0:
            msg = _("Volume type name can not be empty.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        utils.check_string_length(name, 'Type name',
                                  min_length=1, max_length=255)

        if description is not None:
            utils.check_string_length(description, 'Type description',
                                      min_length=0, max_length=255)

        if not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%s' for is_public. Accepted values: "
                    "True or False.") % is_public
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            volume_types.create(context,
                                name,
                                specs,
                                is_public,
                                description=description)
            vol_type = volume_types.get_volume_type_by_name(context, name)
            req.cache_resource(vol_type, name='types')
            self._notify_volume_type_info(
                context, 'volume_type.create', vol_type)

        except exception.VolumeTypeExists as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, volume_type=vol_type)
            raise webob.exc.HTTPConflict(explanation=six.text_type(err))
        except exception.VolumeTypeNotFoundByName as err:
            self._notify_volume_type_error(
                context, 'volume_type.create', err, name=name)
            # Not found exception will be handled at the wsgi level
            raise

        return self._view_builder.show(req, vol_type)
Exemple #9
0
    def create(self, req, body):
        """Creates a new snapshot."""
        kwargs = {}
        context = req.environ['cinder.context']

        if not self.is_valid_body(body, 'snapshot'):
            raise exc.HTTPUnprocessableEntity()

        snapshot = body['snapshot']
        kwargs['metadata'] = snapshot.get('metadata', None)

        try:
            volume_id = snapshot['volume_id']
        except KeyError:
            msg = _("'volume_id' must be specified")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            volume = self.volume_api.get(context, volume_id)
        except exception.NotFound:
            raise exc.HTTPNotFound()

        force = snapshot.get('force', False)
        msg = _LI("Create snapshot from volume %s")
        LOG.info(msg, volume_id, context=context)

        if not utils.is_valid_boolstr(force):
            msg = _("Invalid value '%s' for force. ") % force
            raise exception.InvalidParameterValue(err=msg)

        if strutils.bool_from_string(force):
            new_snapshot = self.volume_api.create_snapshot_force(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('display_description'),
                **kwargs)
        else:
            new_snapshot = self.volume_api.create_snapshot(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('display_description'),
                **kwargs)
        req.cache_db_snapshot(new_snapshot)

        retval = _translate_snapshot_detail_view(new_snapshot)

        return {'snapshot': retval}
Exemple #10
0
    def create(self, req, body):
        """Creates a new snapshot."""
        kwargs = {}
        context = req.environ['cinder.context']

        if not self.is_valid_body(body, 'snapshot'):
            raise exc.HTTPUnprocessableEntity()

        snapshot = body['snapshot']
        kwargs['metadata'] = snapshot.get('metadata', None)

        try:
            volume_id = snapshot['volume_id']
        except KeyError:
            msg = _("'volume_id' must be specified")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            volume = self.volume_api.get(context, volume_id)
        except exception.NotFound:
            raise exc.HTTPNotFound()

        force = snapshot.get('force', False)
        msg = _("Create snapshot from volume %s")
        LOG.info(msg, volume_id, context=context)

        if not utils.is_valid_boolstr(force):
            msg = _("Invalid value '%s' for force. ") % force
            raise exception.InvalidParameterValue(err=msg)

        if strutils.bool_from_string(force):
            new_snapshot = self.volume_api.create_snapshot_force(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('display_description'),
                **kwargs)
        else:
            new_snapshot = self.volume_api.create_snapshot(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('display_description'),
                **kwargs)
        req.cache_db_snapshot(new_snapshot)

        retval = _translate_snapshot_detail_view(context, new_snapshot)

        return {'snapshot': retval}
Exemple #11
0
    def create(self, req, body):
        """Creates a new snapshot."""
        kwargs = {}
        context = req.environ['cinder.context']

        if not self.is_valid_body(body, 'snapshot'):
            raise exc.HTTPBadRequest()

        snapshot = body['snapshot']
        kwargs['metadata'] = snapshot.get('metadata', None)

        volume_id = snapshot['volume_id']
        volume = self.volume_api.get(context, volume_id)
        force = snapshot.get('force', False)
        msg = _("Create snapshot from volume %s")
        LOG.audit(msg, volume_id, context=context)

        # NOTE(thingee): v2 API allows name instead of display_name
        if 'name' in snapshot:
            snapshot['display_name'] = snapshot.get('name')
            del snapshot['name']

        if not utils.is_valid_boolstr(force):
            msg = _("Invalid value '%s' for force. ") % force
            raise exception.InvalidParameterValue(err=msg)

        if strutils.bool_from_string(force):
            new_snapshot = self.volume_api.create_snapshot_force(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('description'),
                **kwargs)
        else:
            new_snapshot = self.volume_api.create_snapshot(
                context,
                volume,
                snapshot.get('display_name'),
                snapshot.get('description'),
                **kwargs)

        retval = _translate_snapshot_detail_view(context, new_snapshot)

        return {'snapshot': retval}
Exemple #12
0
    def get_all(self, context, search_opts=None):
        check_policy(context, 'get_all')

        search_opts = search_opts or {}

        all_tenants = search_opts.pop('all_tenants', '0')
        if not utils.is_valid_boolstr(all_tenants):
            msg = _("all_tenants must be a boolean, got '%s'.") % all_tenants
            raise exception.InvalidParameterValue(err=msg)

        if context.is_admin and strutils.bool_from_string(all_tenants):
            backups = objects.BackupList.get_all(context, filters=search_opts)
        else:
            backups = objects.BackupList.get_all_by_project(
                context,
                context.project_id,
                filters=search_opts
            )

        return backups
Exemple #13
0
    def update(self, req, id, body):
        """Update Quota for a particular tenant

        This works for hierarchical and non-hierarchical projects. For
        hierarchical projects only immediate parent admin or the
        CLOUD admin are able to perform an update.

        :param req: request
        :param id: target project id that needs to be updated
        :param body: key, value pair that that will be
                     applied to the resources if the update
                     succeeds
        """
        context = req.environ['cinder.context']
        authorize_update(context)
        self.validate_string_length(id, 'quota_set_name',
                                    min_length=1, max_length=255)

        self.assert_valid_body(body, 'quota_set')

        # Get the optional argument 'skip_validation' from body,
        # if skip_validation is False, then validate existing resource.
        skip_flag = body.get('skip_validation', True)
        if not utils.is_valid_boolstr(skip_flag):
            msg = _("Invalid value '%s' for skip_validation.") % skip_flag
            raise exception.InvalidParameterValue(err=msg)
        skip_flag = strutils.bool_from_string(skip_flag)

        target_project_id = id
        bad_keys = []

        # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
        # we figure out if we have any bad keys.
        for key, value in body['quota_set'].items():
            if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
                bad_keys.append(key)
                continue

        if len(bad_keys) > 0:
            msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # Saving off this value since we need to use it multiple times
        use_nested_quotas = QUOTAS.using_nested_quotas()
        if use_nested_quotas:
            # Get the parent_id of the target project to verify whether we are
            # dealing with hierarchical namespace or non-hierarchical namespace
            target_project = quota_utils.get_project_hierarchy(
                context, target_project_id, parents_as_ids=True)
            parent_id = target_project.parent_id

            if parent_id:
                # Get the children of the project which the token is scoped to
                # in order to know if the target_project is in its hierarchy.
                context_project = quota_utils.get_project_hierarchy(
                    context, context.project_id, subtree_as_ids=True)
                self._authorize_update_or_delete(context_project,
                                                 target_project.id,
                                                 parent_id)

        # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(),
        # we validate the quota limits to ensure that we can bail out if
        # any of the items in the set is bad. Meanwhile we validate value
        # to ensure that the value can't be lower than number of existing
        # resources.
        quota_values = QUOTAS.get_project_quotas(context, target_project_id,
                                                 defaults=False)
        valid_quotas = {}
        reservations = []
        for key in body['quota_set'].keys():
            if key in NON_QUOTA_KEYS:
                continue

            value = utils.validate_integer(
                body['quota_set'][key], key, min_value=-1,
                max_value=db.MAX_INT)

            # Can't skip the validation of nested quotas since it could mess up
            # hierarchy if parent limit is less than childrens' current usage
            if not skip_flag or use_nested_quotas:
                self._validate_existing_resource(key, value, quota_values)

            if use_nested_quotas:
                try:
                    reservations += self._update_nested_quota_allocated(
                        context, target_project, quota_values, key, value)
                except exception.OverQuota as e:
                    if reservations:
                        db.reservation_rollback(context, reservations)
                    raise webob.exc.HTTPBadRequest(explanation=e.msg)

            valid_quotas[key] = value

        # NOTE(ankit): Pass #3 - At this point we know that all the keys and
        # values are valid and we can iterate and update them all in one shot
        # without having to worry about rolling back etc as we have done
        # the validation up front in the 2 loops above.
        for key, value in valid_quotas.items():
            try:
                db.quota_update(context, target_project_id, key, value)
            except exception.ProjectQuotaNotFound:
                db.quota_create(context, target_project_id, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()

        if reservations:
            db.reservation_commit(context, reservations)
        return {'quota_set': self._get_quotas(context, target_project_id)}
Exemple #14
0
    def update(self, req, id, body):
        """Update Quota for a particular tenant

        This works for hierarchical and non-hierarchical projects. For
        hierarchical projects only immediate parent admin or the
        CLOUD admin are able to perform an update.

        :param req: request
        :param id: target project id that needs to be updated
        :param body: key, value pair that that will be
                     applied to the resources if the update
                     succeeds
        """
        context = req.environ['cinder.context']
        authorize_update(context)
        self.validate_string_length(id, 'quota_set_name',
                                    min_length=1, max_length=255)

        self.assert_valid_body(body, 'quota_set')

        # Get the optional argument 'skip_validation' from body,
        # if skip_validation is False, then validate existing resource.
        skip_flag = body.get('skip_validation', True)
        if not utils.is_valid_boolstr(skip_flag):
            msg = _("Invalid value '%s' for skip_validation.") % skip_flag
            raise exception.InvalidParameterValue(err=msg)
        skip_flag = strutils.bool_from_string(skip_flag)

        target_project_id = id
        bad_keys = []

        # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
        # we figure out if we have any bad keys.
        for key, value in body['quota_set'].items():
            if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
                bad_keys.append(key)
                continue

        if len(bad_keys) > 0:
            msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # Saving off this value since we need to use it multiple times
        use_nested_quotas = QUOTAS.using_nested_quotas()
        if use_nested_quotas:
            # Get the parent_id of the target project to verify whether we are
            # dealing with hierarchical namespace or non-hierarchical namespace
            target_project = quota_utils.get_project_hierarchy(
                context, target_project_id)
            parent_id = target_project.parent_id

            if parent_id:
                # Get the children of the project which the token is scoped to
                # in order to know if the target_project is in its hierarchy.
                context_project = quota_utils.get_project_hierarchy(
                    context, context.project_id, subtree_as_ids=True)
                self._authorize_update_or_delete(context_project,
                                                 target_project.id,
                                                 parent_id)
                parent_project_quotas = QUOTAS.get_project_quotas(
                    context, parent_id)

        # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(),
        # we validate the quota limits to ensure that we can bail out if
        # any of the items in the set is bad. Meanwhile we validate value
        # to ensure that the value can't be lower than number of existing
        # resources.
        quota_values = QUOTAS.get_project_quotas(context, target_project_id,
                                                 defaults=False)
        valid_quotas = {}
        allocated_quotas = {}
        for key in body['quota_set'].keys():
            if key in NON_QUOTA_KEYS:
                continue

            if not skip_flag:
                self._validate_existing_resource(key, value, quota_values)

            if use_nested_quotas and parent_id:
                value = self._validate_quota_limit(body['quota_set'], key,
                                                   quota_values,
                                                   parent_project_quotas)

                if value < 0:
                    # TODO(mc_nair): extend to handle -1 limits and recurse up
                    # the hierarchy
                    msg = _("Quota can't be set to -1 for child projects.")
                    raise webob.exc.HTTPBadRequest(explanation=msg)

                original_quota = 0
                if quota_values.get(key):
                    original_quota = quota_values[key]['limit']

                allocated_quotas[key] = (
                    parent_project_quotas[key].get('allocated', 0) + value -
                    original_quota)
            else:
                value = self._validate_quota_limit(body['quota_set'], key)
            valid_quotas[key] = value

        # NOTE(ankit): Pass #3 - At this point we know that all the keys and
        # values are valid and we can iterate and update them all in one shot
        # without having to worry about rolling back etc as we have done
        # the validation up front in the 2 loops above.
        for key, value in valid_quotas.items():
            try:
                db.quota_update(context, target_project_id, key, value)
            except exception.ProjectQuotaNotFound:
                db.quota_create(context, target_project_id, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()
            # If hierarchical projects, update child's quota first
            # and then parents quota. In future this needs to be an
            # atomic operation.
            if use_nested_quotas and parent_id:
                if key in allocated_quotas.keys():
                    try:
                        db.quota_allocated_update(context, parent_id, key,
                                                  allocated_quotas[key])
                    except exception.ProjectQuotaNotFound:
                        parent_limit = parent_project_quotas[key]['limit']
                        db.quota_create(context, parent_id, key, parent_limit,
                                        allocated=allocated_quotas[key])

        return {'quota_set': self._get_quotas(context, target_project_id)}
Exemple #15
0
    def update(self, req, id, body):
        """Update Quota for a particular tenant

        This works for hierarchical and non-hierarchical projects. For
        hierarchical projects only immediate parent admin or the
        CLOUD admin are able to perform an update.

        :param req: request
        :param id: target project id that needs to be updated
        :param body: key, value pair that that will be
                     applied to the resources if the update
                     succeeds
        """
        context = req.environ['cinder.context']
        authorize_update(context)
        self.validate_string_length(id,
                                    'quota_set_name',
                                    min_length=1,
                                    max_length=255)

        self.assert_valid_body(body, 'quota_set')

        # Get the optional argument 'skip_validation' from body,
        # if skip_validation is False, then validate existing resource.
        skip_flag = body.get('skip_validation', True)
        if not utils.is_valid_boolstr(skip_flag):
            msg = _("Invalid value '%s' for skip_validation.") % skip_flag
            raise exception.InvalidParameterValue(err=msg)
        skip_flag = strutils.bool_from_string(skip_flag)

        target_project_id = id
        bad_keys = []

        # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
        # we figure out if we have any bad keys.
        for key, value in body['quota_set'].items():
            if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
                bad_keys.append(key)
                continue

        if len(bad_keys) > 0:
            msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # Get the parent_id of the target project to verify whether we are
        # dealing with hierarchical namespace or non-hierarchical namespace.
        target_project = self._get_project(context, target_project_id)
        parent_id = target_project.parent_id

        if parent_id:
            # Get the children of the project which the token is scoped to
            # in order to know if the target_project is in its hierarchy.
            context_project = self._get_project(context,
                                                context.project_id,
                                                subtree_as_ids=True)
            self._authorize_update_or_delete(context_project,
                                             target_project.id, parent_id)
            parent_project_quotas = QUOTAS.get_project_quotas(
                context, parent_id)

        # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(),
        # we validate the quota limits to ensure that we can bail out if
        # any of the items in the set is bad. Meanwhile we validate value
        # to ensure that the value can't be lower than number of existing
        # resources.
        quota_values = QUOTAS.get_project_quotas(context,
                                                 target_project_id,
                                                 defaults=False)
        valid_quotas = {}
        allocated_quotas = {}
        for key in body['quota_set'].keys():
            if key in NON_QUOTA_KEYS:
                continue

            if not skip_flag:
                self._validate_existing_resource(key, value, quota_values)

            if parent_id:
                value = self._validate_quota_limit(body['quota_set'], key,
                                                   quota_values,
                                                   parent_project_quotas)
                original_quota = 0
                if quota_values.get(key):
                    original_quota = quota_values[key]['limit']

                allocated_quotas[key] = (
                    parent_project_quotas[key].get('allocated', 0) + value -
                    original_quota)
            else:
                value = self._validate_quota_limit(body['quota_set'], key)
            valid_quotas[key] = value

        # NOTE(ankit): Pass #3 - At this point we know that all the keys and
        # values are valid and we can iterate and update them all in one shot
        # without having to worry about rolling back etc as we have done
        # the validation up front in the 2 loops above.
        for key, value in valid_quotas.items():
            try:
                db.quota_update(context, target_project_id, key, value)
            except exception.ProjectQuotaNotFound:
                db.quota_create(context, target_project_id, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()
            # If hierarchical projects, update child's quota first
            # and then parents quota. In future this needs to be an
            # atomic operation.
            if parent_id:
                if key in allocated_quotas.keys():
                    try:
                        db.quota_allocated_update(context, parent_id, key,
                                                  allocated_quotas[key])
                    except exception.ProjectQuotaNotFound:
                        parent_limit = parent_project_quotas[key]['limit']
                        db.quota_create(context,
                                        parent_id,
                                        key,
                                        parent_limit,
                                        allocated=allocated_quotas[key])

        return {
            'quota_set':
            self._get_quotas(context,
                             target_project_id,
                             parent_project_id=parent_id)
        }
 def test_is_valid_boolstr(self):
     self.assertTrue(utils.is_valid_boolstr(True))
     self.assertTrue(utils.is_valid_boolstr('trUe'))
     self.assertTrue(utils.is_valid_boolstr(False))
     self.assertTrue(utils.is_valid_boolstr('faLse'))
     self.assertTrue(utils.is_valid_boolstr('yeS'))
     self.assertTrue(utils.is_valid_boolstr('nO'))
     self.assertTrue(utils.is_valid_boolstr('y'))
     self.assertTrue(utils.is_valid_boolstr('N'))
     self.assertTrue(utils.is_valid_boolstr(1))
     self.assertTrue(utils.is_valid_boolstr('1'))
     self.assertTrue(utils.is_valid_boolstr(0))
     self.assertTrue(utils.is_valid_boolstr('0'))
Exemple #17
0
    def update(self, req, id, body):
        """Update Quota for a particular tenant

        This works for hierarchical and non-hierarchical projects. For
        hierarchical projects only immediate parent admin or the
        CLOUD admin are able to perform an update.

        :param req: request
        :param id: target project id that needs to be updated
        :param body: key, value pair that that will be
                     applied to the resources if the update
                     succeeds
        """
        context = req.environ['cinder.context']
        authorize_update(context)
        self.validate_string_length(id,
                                    'quota_set_name',
                                    min_length=1,
                                    max_length=255)

        self.assert_valid_body(body, 'quota_set')

        # Get the optional argument 'skip_validation' from body,
        # if skip_validation is False, then validate existing resource.
        skip_flag = body.get('skip_validation', True)
        if not utils.is_valid_boolstr(skip_flag):
            msg = _("Invalid value '%s' for skip_validation.") % skip_flag
            raise exception.InvalidParameterValue(err=msg)
        skip_flag = strutils.bool_from_string(skip_flag)

        target_project_id = id
        bad_keys = []

        # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
        # we figure out if we have any bad keys.
        for key, value in body['quota_set'].items():
            if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
                bad_keys.append(key)
                continue

        if len(bad_keys) > 0:
            msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # Saving off this value since we need to use it multiple times
        use_nested_quotas = QUOTAS.using_nested_quotas()
        if use_nested_quotas:
            # Get the parent_id of the target project to verify whether we are
            # dealing with hierarchical namespace or non-hierarchical namespace
            target_project = quota_utils.get_project_hierarchy(
                context, target_project_id, parents_as_ids=True)
            parent_id = target_project.parent_id

            if parent_id:
                # Get the children of the project which the token is scoped to
                # in order to know if the target_project is in its hierarchy.
                context_project = quota_utils.get_project_hierarchy(
                    context,
                    context.project_id,
                    subtree_as_ids=True,
                    is_admin_project=context.is_admin)
                self._authorize_update_or_delete(context_project,
                                                 target_project.id, parent_id)

        # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(),
        # we validate the quota limits to ensure that we can bail out if
        # any of the items in the set is bad. Meanwhile we validate value
        # to ensure that the value can't be lower than number of existing
        # resources.
        quota_values = QUOTAS.get_project_quotas(context,
                                                 target_project_id,
                                                 defaults=False)
        valid_quotas = {}
        reservations = []
        for key in body['quota_set'].keys():
            if key in NON_QUOTA_KEYS:
                continue

            value = utils.validate_integer(body['quota_set'][key],
                                           key,
                                           min_value=-1,
                                           max_value=db.MAX_INT)

            # Can't skip the validation of nested quotas since it could mess up
            # hierarchy if parent limit is less than childrens' current usage
            if not skip_flag or use_nested_quotas:
                self._validate_existing_resource(key, value, quota_values)

            if use_nested_quotas:
                try:
                    reservations += self._update_nested_quota_allocated(
                        context, target_project, quota_values, key, value)
                except exception.OverQuota as e:
                    if reservations:
                        db.reservation_rollback(context, reservations)
                    raise webob.exc.HTTPBadRequest(explanation=e.message)

            valid_quotas[key] = value

        # NOTE(ankit): Pass #3 - At this point we know that all the keys and
        # values are valid and we can iterate and update them all in one shot
        # without having to worry about rolling back etc as we have done
        # the validation up front in the 2 loops above.
        for key, value in valid_quotas.items():
            try:
                db.quota_update(context, target_project_id, key, value)
            except exception.ProjectQuotaNotFound:
                db.quota_create(context, target_project_id, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()

        if reservations:
            db.reservation_commit(context, reservations)
        return {'quota_set': self._get_quotas(context, target_project_id)}
Exemple #18
0
    def update(self, req, id, body):
        context = req.environ['cinder.context']
        authorize_update(context)
        self.validate_string_length(id,
                                    'quota_set_name',
                                    min_length=1,
                                    max_length=255)

        project_id = id
        self.assert_valid_body(body, 'quota_set')

        # Get the optional argument 'skip_validation' from body,
        # if skip_validation is False, then validate existing resource.
        skip_flag = body.get('skip_validation', True)
        if not utils.is_valid_boolstr(skip_flag):
            msg = _("Invalid value '%s' for skip_validation.") % skip_flag
            raise exception.InvalidParameterValue(err=msg)
        skip_flag = strutils.bool_from_string(skip_flag)

        bad_keys = []

        # NOTE(ankit): Pass #1 - In this loop for body['quota_set'].items(),
        # we figure out if we have any bad keys.
        for key, value in body['quota_set'].items():
            if (key not in QUOTAS and key not in NON_QUOTA_KEYS):
                bad_keys.append(key)
                continue

        if len(bad_keys) > 0:
            msg = _("Bad key(s) in quota set: %s") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # NOTE(ankit): Pass #2 - In this loop for body['quota_set'].keys(),
        # we validate the quota limits to ensure that we can bail out if
        # any of the items in the set is bad. Meanwhile we validate value
        # to ensure that the value can't be lower than number of existing
        # resources.
        quota_values = QUOTAS.get_project_quotas(context, project_id)
        valid_quotas = {}
        for key in body['quota_set'].keys():
            if key in NON_QUOTA_KEYS:
                continue

            valid_quotas[key] = self.validate_integer(body['quota_set'][key],
                                                      key,
                                                      min_value=-1,
                                                      max_value=db.MAX_INT)

            if not skip_flag:
                self._validate_existing_resource(key, value, quota_values)

        # NOTE(ankit): Pass #3 - At this point we know that all the keys and
        # values are valid and we can iterate and update them all in one shot
        # without having to worry about rolling back etc as we have done
        # the validation up front in the 2 loops above.
        for key, value in valid_quotas.items():
            try:
                db.quota_update(context, project_id, key, value)
            except exception.ProjectQuotaNotFound:
                db.quota_create(context, project_id, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()
        return {'quota_set': self._get_quotas(context, id)}
Exemple #19
0
 def test_is_valid_boolstr(self):
     self.assertTrue(utils.is_valid_boolstr(True))
     self.assertTrue(utils.is_valid_boolstr('trUe'))
     self.assertTrue(utils.is_valid_boolstr(False))
     self.assertTrue(utils.is_valid_boolstr('faLse'))
     self.assertTrue(utils.is_valid_boolstr('yeS'))
     self.assertTrue(utils.is_valid_boolstr('nO'))
     self.assertTrue(utils.is_valid_boolstr('y'))
     self.assertTrue(utils.is_valid_boolstr('N'))
     self.assertTrue(utils.is_valid_boolstr(1))
     self.assertTrue(utils.is_valid_boolstr('1'))
     self.assertTrue(utils.is_valid_boolstr(0))
     self.assertTrue(utils.is_valid_boolstr('0'))