Beispiel #1
0
    def update(self, req, id, body):
        """Update a snapshot."""
        LOG.info(_LI("Update snapshot with id: %s"), id)
        context = req.environ['sgservice.context']
        if not body:
            msg = _("Missing request body")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        if 'snapshot' not in body:
            msg = (_("Missing required element '%s' in request body"),
                   'snapshot')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        snapshot = body['snapshot']
        update_dict = {}

        valid_update_keys = (
            'name',
            'description',
            'display_name',
            'display_description',
        )
        for key in valid_update_keys:
            if key in snapshot:
                update_dict[key] = snapshot[key]
        self.validate_name_and_description(update_dict)
        if 'name' in update_dict:
            update_dict['display_name'] = update_dict.pop('name')
        if 'description' in update_dict:
            update_dict['display_description'] = update_dict.pop('description')

        snapshot = self.service_api.get_snapshot(context, id)
        snapshot.update(update_dict)
        snapshot.save()
        return self._view_builder.detail(req, snapshot)
    def create(self, req, body):
        """Creates a new replication."""
        if not self.is_valid_body(body, 'replication'):
            raise exc.HTTPUnprocessableEntity()
        LOG.debug('Create replication request body: %s', body)
        context = req.environ['sgservice.context']
        replication = body['replication']

        master_volume_id = replication.get('master_volume', None)
        if master_volume_id is None:
            msg = _('Incorrect request body format')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        slave_volume_id = replication.get('slave_volume', None)
        if slave_volume_id is None:
            msg = _('Incorrect request body format')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        name = replication.get('name', None)
        description = replication.get('description', None)
        if description is None:
            description = 'replication:%s-%s' % (master_volume_id,
                                                 slave_volume_id)

        master_volume = self.service_api.get(context, master_volume_id)
        slave_volume = self.service_api.get(context, slave_volume_id)
        replication = self.service_api.create_replication(
            context, name, description, master_volume, slave_volume)
        return self._view_builder.detail(req, replication)
Beispiel #3
0
    def update(self, req, id, body):
        """Update a backup."""
        LOG.info(_LI("Update backup, backup_id: %s"), id)
        context = req.environ['sgservice.context']
        if not body:
            msg = _("Missing request body")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        if 'backup' not in body:
            msg = (_("Missing required element '%s' in request body"),
                   'backup')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        backup = body['backup']
        update_dict = {}

        valid_update_keys = (
            'name',
            'description',
            'display_name',
            'display_description',
        )
        for key in valid_update_keys:
            if key in backup:
                update_dict[key] = backup[key]
        self.validate_name_and_description(update_dict)
        if 'name' in update_dict:
            update_dict['display_name'] = update_dict.pop('name')
        if 'description' in update_dict:
            update_dict['display_description'] = update_dict.pop('description')

        backup = self.service_api.get_backup(context, id)
        backup.update(update_dict)
        backup.save()
        return self._view_builder.detail(req, backup)
Beispiel #4
0
    def create(self, req, body):
        """Creates a new backup."""
        LOG.debug('Create backup request body: %s', body)
        context = req.environ['sgservice.context']
        backup = body['backup']

        volume_id = backup.get('volume_id', None)
        if volume_id is None:
            msg = _('Incorrect request body format')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        name = backup.get('name', None)
        description = backup.get('description', None)
        if description is None:
            description = 'backup-%s' % volume_id

        backup_type = backup.get('type')
        if backup_type is None:
            backup_type = constants.FULL_BACKUP
        if backup_type not in constants.SUPPORT_BACKUP_TYPES:
            msg = _('backup type should be full or incremental')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        backup_destination = backup.get('destination')
        if backup_destination is None:
            backup_destination = constants.LOCAL_BACKUP
        if backup_destination not in constants.SUPPORT_BACKUP_DESTINATIONS:
            msg = _('backup destination should be local or remote')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        volume = self.service_api.get(context, volume_id)
        backup = self.service_api.create_backup(context, name, description,
                                                volume, backup_type,
                                                backup_destination)
        return self._view_builder.detail(req, backup)
Beispiel #5
0
    def validate_integer(value, name, min_value=None, max_value=None):
        """Make sure that value is a valid integer, potentially within range.

        :param value: the value of the integer
        :param name: the name of the integer
        :param min_length: the min_length of the integer
        :param max_length: the max_length of the integer
        :returns: integer
        """
        try:
            value = int(value)
        except (TypeError, ValueError, UnicodeEncodeError):
            raise webob.exc.HTTPBadRequest(
                explanation=(_('%s must be an integer.') % name))

        if min_value is not None and value < min_value:
            raise webob.exc.HTTPBadRequest(
                explanation=(_('%(value_name)s must be >= %(min_value)d') % {
                    'value_name': name,
                    'min_value': min_value
                }))
        if max_value is not None and value > max_value:
            raise webob.exc.HTTPBadRequest(
                explanation=(_('%(value_name)s must be <= %(max_value)d') % {
                    'value_name': name,
                    'max_value': max_value
                }))

        return value
Beispiel #6
0
def _get_offset_param(params):
    """Extract offset id from request's dictionary (defaults to 0) or fail."""
    try:
        offset = int(params.pop('offset', 0))
    except ValueError:
        msg = _('offset param must be an integer')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    if offset < 0:
        msg = _('offset param must be positive')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    return offset
    def reset_status(self, req, id, body):
        """reset replication status"""
        LOG.info(_LI("Reset replication status, id: %s"), id)
        status = body['reset_status'].get('status',
                                          fields.ReplicationStatus.ENABLED)
        if status not in fields.ReplicationStatus.ALL:
            msg = _("Invalid status provided.")
            LOG.error(msg)
            raise exception.InvalidStatus(status=status)

        context = req.environ['sgservice.context']
        replication = self.service_api.get_replication(context, id)
        replication.status = status
        replication.save()
        # reset master volume replicate status
        master_volume = self.service_api.get(context,
                                             replication.master_volume)
        if master_volume.replicate_status not in [
                None, fields.ReplicateStatus.DELETED
        ]:
            master_volume.replicate_status = status
        master_volume.save()

        # reset slave volume replicate status
        slave_volume = self.service_api.get(context, replication.slave_volume)
        if slave_volume.replicate_status not in [
                None, fields.ReplicateStatus.DELETED
        ]:
            slave_volume.replicate_status = status
        slave_volume.save()
        return webob.Response(status_int=202)
Beispiel #8
0
    def reset_status(self, req, id, body):
        """reset checkpoint status"""
        LOG.info(_LI("Reset checkpoint status, id: %s"), id)
        status = body['reset_status'].get('status',
                                          fields.CheckpointStatus.AVAILABLE)
        if status not in fields.CheckpointStatus.ALL:
            msg = _("Invalid status provided.")
            LOG.error(msg)
            raise exception.InvalidStatus(status=status)

        context = req.environ['sgservice.context']
        checkpoint = self.service_api.get_checkpoint(context, id)
        checkpoint.status = status
        checkpoint.save()
        # reset master snapshot status
        try:
            master_snapshot = self.service_api.get_snapshot(
                context, checkpoint.master_snapshot)
            master_snapshot.status = status
            master_snapshot.save()
        except Exception:
            pass
        # reset slave snapshot status
        try:
            slave_snapshot = self.service_api.get_snapshot(
                context, checkpoint.slave_snapshot)
            slave_snapshot.status = status
            slave_snapshot.save()
        except Exception:
            pass

        return webob.Response(status_int=202)
Beispiel #9
0
    def __init__(self, name, loader=None):
        """Initialize, but do not start the WSGI server.

        :param name: The name of the WSGI server given to the loader.
        :param loader: Loads the WSGI application using the given name.
        :returns: None

        """
        self.name = name
        self.manager = self._get_manager()
        self.loader = loader or wsgi_common.Loader()
        self.app = self.loader.load_app(name)
        self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")
        self.port = getattr(CONF, '%s_listen_port' % name, 0)
        self.workers = (getattr(CONF, '%s_workers' % name, None) or
                        processutils.get_worker_count())
        if self.workers and self.workers < 1:
            worker_name = '%s_workers' % name
            msg = (_("%(worker_name)s value of %(workers)d is invalid, "
                     "must be greater than 0.") %
                   {'worker_name': worker_name,
                    'workers': self.workers})
            raise exception.InvalidInput(msg)

        self.server = wsgi.Server(name,
                                  self.app,
                                  host=self.host,
                                  port=self.port)
Beispiel #10
0
def action_peek_json(body):
    """Determine action to invoke."""

    try:
        decoded = jsonutils.loads(body)
    except ValueError:
        msg = _("cannot understand JSON")
        raise exception.MalformedRequestBody(reason=msg)

    # Make sure there's exactly one key...
    if len(decoded) != 1:
        msg = _("too many body keys")
        raise exception.MalformedRequestBody(reason=msg)

    # Return the action and the decoded body...
    return list(decoded.keys())[0]
Beispiel #11
0
    def _error(self, inner, req):
        LOG.exception(_LE("Caught error: %(type)s %(error)s"), {
            'type': type(inner),
            'error': inner
        })
        safe = getattr(inner, 'safe', False)
        headers = getattr(inner, 'headers', None)
        status = getattr(inner, 'code', 500)
        if status is None:
            status = 500

        msg_dict = dict(url=req.url, status=status)
        LOG.info(_LI("%(url)s returned with HTTP %(status)d"), msg_dict)
        outer = self.status_to_type(status)
        if headers:
            outer.headers = headers
        # NOTE(johannes): We leave the explanation empty here on
        # purpose. It could possibly have sensitive information
        # that should not be returned back to the user. See
        # bugs 868360 and 874472
        # NOTE(eglynn): However, it would be over-conservative and
        # inconsistent with the EC2 API to hide every exception,
        # including those that are safe to expose, see bug 1021373
        if safe:
            msg = (inner.msg if isinstance(inner, exception.SGServiceException)
                   else six.text_type(inner))
            params = {
                'exception': inner.__class__.__name__,
                'explanation': msg
            }
            outer.explanation = _('%(exception)s: %(explanation)s') % params
        return wsgi.Fault(outer)
Beispiel #12
0
 def create(self):
     if self.obj_attr_is_set('id'):
         raise exception.ObjectActionError(action='create',
                                           reason=_('already created'))
     updates = self.sgservice_obj_get_changes()
     db_service = db.service_create(self._context, updates)
     self._from_db_object(self._context, self, db_service)
Beispiel #13
0
 def create(self):
     if self.obj_attr_is_set('id'):
         raise exception.ObjectActionError(action='create',
                                           reason=_('already created'))
     updates = self.sgservice_obj_get_changes()
     with self.obj_as_admin():
         db_attachment = db.volume_attach(self._context, updates)
     self._from_db_object(self._context, self, db_attachment)
Beispiel #14
0
def _get_limit_param(params, max_limit=None):
    """Extract integer limit from request's dictionary or fail.

   Defaults to max_limit if not present and returns max_limit if present
   'limit' is greater than max_limit.
    """
    max_limit = max_limit or CONF.osapi_max_limit
    try:
        limit = int(params.pop('limit', max_limit))
    except ValueError:
        msg = _('limit param must be an integer')
        raise webob.exc.HTTPBadRequest(explanation=msg)
    if limit <= 0:
        msg = _('limit param must be positive')
        raise webob.exc.HTTPBadRequest(explanation=msg)
    limit = min(limit, max_limit)
    return limit
Beispiel #15
0
    def list(self):
        """Show a list of all sgservice services."""

        ctxt = context.get_admin_context()
        services = db.service_get_all(ctxt)
        print_format = "%-16s %-36s %-10s %-5s %-10s"
        print(
            print_format %
            (_('Binary'), _('Host'), _('Status'), _('State'), _('Updated At')))
        for svc in services:
            alive = utils.service_is_up(svc)
            art = ":-)" if alive else "XXX"
            status = 'enabled'
            if svc['disabled']:
                status = 'disabled'
            print(print_format % (svc['binary'], svc['host'].partition('.')[0],
                                  status, art, svc['updated_at']))
Beispiel #16
0
def get_bool_params(param_string, params):
    param = params.get(param_string, False)
    if not is_valid_boolstr(param):
        msg = _('Value %(param)s for %(param_string)s is not a boolean') % {
            'param': param,
            'param_string': param_string
        }
        raise exception.InvalidParameterValue(err=msg)
    return strutils.bool_from_string(param, strict=True)
Beispiel #17
0
 def assert_valid_body(body, entity_name):
     # NOTE: After v1 api is deprecated need to merge 'is_valid_body' and
     #       'assert_valid_body' in to one method. Right now it is not
     #       possible to modify 'is_valid_body' to raise exception because
     #       in case of V1 api when 'is_valid_body' return False,
     #       'HTTPUnprocessableEntity' exception is getting raised and in
     #       V2 api 'HTTPBadRequest' exception is getting raised.
     if not Controller.is_valid_body(body, entity_name):
         raise webob.exc.HTTPBadRequest(
             explanation=_("Missing required element '%s' in "
                           "request body.") % entity_name)
Beispiel #18
0
    def __call__(self, req):
        headers = req.headers
        environ = req.environ

        user_id = headers.get('X_USER_ID') or headers.get('X_USER')
        if user_id is None:
            LOG.debug("Neither X_USER_ID nor X_USER found in request")
            return webob.exc.HTTPUnauthorized()
        # get the roles
        roles = [r.strip() for r in headers.get('X_ROLE', '').split(',')]
        if 'X_TENANT_ID' in headers:
            # This is the new header since Keystone went to ID/Name
            project_id = headers['X_TENANT_ID']
        else:
            # This is for legacy compatibility
            project_id = headers['X_TENANT']

        project_name = headers.get('X_TENANT_NAME')

        req_id = environ.get(request_id.ENV_REQUEST_ID)

        # Get the auth token
        auth_token = headers.get('X_AUTH_TOKEN',
                                 headers.get('X_STORAGE_TOKEN'))

        # Build a context, including the auth_token...
        remote_address = req.remote_addr

        auth_token_info = environ.get('keystone.token_info')

        service_catalog = None
        if headers.get('X_SERVICE_CATALOG') is not None:
            try:
                catalog_header = headers.get('X_SERVICE_CATALOG')
                service_catalog = jsonutils.loads(catalog_header)
            except ValueError:
                raise webob.exc.HTTPInternalServerError(
                    explanation=_('Invalid service catalog json.'))

        if CONF.use_forwarded_for:
            remote_address = headers.get('X-Forwarded-For', remote_address)
        ctx = context.RequestContext(user_id,
                                     project_id,
                                     project_name=project_name,
                                     roles=roles,
                                     auth_token=auth_token,
                                     remote_address=remote_address,
                                     service_catalog=service_catalog,
                                     request_id=req_id,
                                     auth_token_info=auth_token_info)

        environ['sgservice.context'] = ctx
        return self.application
Beispiel #19
0
    def restore(self, req, id, body):
        """Restore backup to an SG-enabled volume"""
        LOG.info(_LI("Restore backup to sg-enabled volume, backup_id: %s"), id)
        context = req.environ['sgservice.context']
        backup = self.service_api.get_backup(context, id)
        restore = body['restore']
        volume_id = restore.get('volume_id', None)
        if volume_id is None:
            msg = _('restored volume should be specified.')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        restore = self.service_api.restore_backup(context, backup, volume_id)
        return self._view_builder.restore_summary(req, restore)
Beispiel #20
0
    def get_by_id(cls, context, id, *args, **kwargs):
        # To get by id we need to have a model and for the model to
        # have an id field
        if 'id' not in cls.fields:
            msg = (_('VersionedObject %s cannot retrieve object by id.') %
                   (cls.obj_name()))
            raise NotImplementedError(msg)

        model = getattr(models, cls.obj_name())
        orm_obj = db.get_by_id(context, model, id, *args, **kwargs)
        kargs = {}
        if hasattr(cls, 'DEFAULT_EXPECTED_ATTR'):
            kargs = {'expected_attrs': getattr(cls, 'DEFAULT_EXPECTED_ATTR')}
        return cls._from_db_object(context, cls(context), orm_obj, **kargs)
Beispiel #21
0
    def obj_load_attr(self, attrname):
        if attrname not in self.OPTIONAL_FIELDS:
            raise exception.ObjectActionError(
                action='obj_load_attr',
                reason=_('attribute %s not lazy-loadable') % attrname)
        if not self._context:
            raise exception.OrphanedObjectError(method='obj_load_attr',
                                                objtype=self.obj_name())

        if attrname == 'volume':
            volume = objects.Volume.get_by_id(self._context, self.volume_id)
            self.volume = volume

        self.obj_reset_changes(fields=[attrname])
Beispiel #22
0
    def reset_status(self, req, id, body):
        """reset volume status"""
        LOG.info(_LI("Reset volume status, id: %s"), id)
        status = body['reset_status'].get('status',
                                          fields.VolumeStatus.ENABLED)
        if status not in fields.VolumeStatus.ALL:
            msg = _("Invalid status provided.")
            LOG.error(msg)
            raise exception.InvalidStatus(status=status)

        context = req.environ['sgservice.context']
        volume = self.service_api.get(context, id)
        volume.status = status
        volume.save()
        return webob.Response(status_int=202)
Beispiel #23
0
    def reset_status(self, req, id, body):
        """reset snapshot status"""
        LOG.info(_LI("Reset snapshot status, id: %s"), id)
        status = body['reset_status'].get('status',
                                          fields.SnapshotStatus.AVAILABLE)
        if status not in fields.SnapshotStatus.ALL:
            msg = _("Invalid status provided.")
            LOG.error(msg)
            raise exception.InvalidStatus(status=status)

        context = req.environ['sgservice.context']
        snapshot = self.service_api.get_snapshot(context, id)
        snapshot.status = status
        snapshot.save()
        return webob.Response(status_int=202)
Beispiel #24
0
    def attach(self, req, id, body):
        """Add sg-volume attachment metadata."""
        LOG.info(_LI("Add SG-volume attachment, volume_id: %s"), id)
        context = req.environ['sgservice.context']
        volume = self.service_api.get(context, id)

        params = body['attach']
        params = {} if params is None else params
        instance_uuid = params.get('instance_uuid', None)

        mode = params.get('mode', None)
        if mode is None:
            mode = 'rw'
        if instance_uuid is None:
            msg = _("Invalid request to attach volume to an invalid target")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        if mode not in ('rw', 'ro'):
            msg = _("Invalid request to attach volume to an invalid mode. "
                    "Attaching mode should be 'rw' or 'ro'.")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        attach_result = self.service_api.attach(context, volume, instance_uuid,
                                                mode)
        return self._view_builder.attach_summary(req, attach_result)
Beispiel #25
0
    def create(self, req, body):
        """Creates a new volume from snapshot or checkpoint."""
        LOG.debug('Create volume from snapshot, request body: %s', body)
        context = req.environ['sgservice.context']
        volume = body['volume']

        volume_type = volume.get('volume_type', None)
        availability_zone = volume.get('availability_zone', None)
        volume_id = volume.get('volume_id', None)
        size = volume.get('size', None)

        # create from snapshot
        snapshot_id = volume.get('snapshot_id')
        if snapshot_id is not None:
            name = volume.get('name', 'volume-%s' % snapshot_id)
            description = volume.get('description', name)
            snapshot = self.service_api.get_snapshot(context, snapshot_id)
            volume = self.service_api.create_volume(
                context,
                snapshot=snapshot,
                volume_type=volume_type,
                availability_zone=availability_zone,
                description=description,
                name=name,
                volume_id=volume_id,
                size=size)
            return self._view_builder.detail(req, volume)

        # create from checkpoint
        checkpoint_id = volume.get('checkpoint_id')
        if checkpoint_id is not None:
            name = volume.get('name', 'volume-%s' % checkpoint_id)
            description = volume.get('description', name)
            checkpoint = self.service_api.get_checkpoint(
                context, checkpoint_id)
            volume = self.service_api.create_volume(
                context,
                checkpoint=checkpoint,
                volume_type=volume_type,
                availability_zone=availability_zone,
                description=description,
                name=name,
                volume_id=volume_id)
            return self._view_builder.detail(req, volume)

        msg = _('Incorrect request body format, create volume must specified '
                'a snapshot or checkpoint')
        raise webob.exc.HTTPBadRequest(explanation=msg)
Beispiel #26
0
    def obj_load_attr(self, attrname):
        if attrname not in self.OPTIONAL_FIELDS:
            raise exception.ObjectActionError(
                action='obj_load_attr',
                reason=_('attribute %s not lazy-loadable') % attrname)
        if not self._context:
            raise exception.OrphanedObjectError(method='obj_load_attr',
                                                objtype=self.obj_name())

        if attrname == 'metadata':
            self.metadata = db.volume_metadata_get(self._context, self.id)
        elif attrname == 'volume_attachment':
            attachments = objects.VolumeAttachmentList.get_all_by_volume_id(
                self._context, self.id)
            self.volume_attachment = attachments
        self.obj_reset_changes(fields=[attrname])
Beispiel #27
0
    def refresh(self):
        # To refresh we need to have a model and for the model to have an id
        # field
        if 'id' not in self.fields:
            msg = (_('VersionedObject %s cannot retrieve object by id.') %
                   (self.obj_name()))
            raise NotImplementedError(msg)

        current = self.get_by_id(self._context, self.id)

        for field in self.fields:
            # Only update attributes that are already set.  We do not want to
            # unexpectedly trigger a lazy-load.
            if self.obj_attr_is_set(field):
                if self[field] != current[field]:
                    self[field] = current[field]
        self.obj_reset_changes()
Beispiel #28
0
def db_sync(version=None, init_version=INIT_VERSION, engine=None):
    """Migrate the database to `version` or the most recent version."""

    if engine is None:
        engine = db_api.get_engine()

    current_db_version = get_backend().db_version(engine, MIGRATE_REPO_PATH,
                                                  init_version)

    # TODO(e0ne): drop version validation when new oslo.db will be released
    if version and int(version) < current_db_version:
        msg = _('Database schema downgrade is not allowed.')
        raise exception.InvalidInput(reason=msg)
    return get_backend().db_sync(engine=engine,
                                 abs_path=MIGRATE_REPO_PATH,
                                 version=version,
                                 init_version=init_version)
Beispiel #29
0
def get_sort_params(params, default_key='created_at', default_dir='desc'):
    """Retrieves sort keys/directions parameters.

    Processes the parameters to create a list of sort keys and sort directions
    that correspond to either the 'sort' parameter or the 'sort_key' and
    'sort_dir' parameter values. The value of the 'sort' parameter is a comma-
    separated list of sort keys, each key is optionally appended with
    ':<sort_direction>'.

    Note that the 'sort_key' and 'sort_dir' parameters are deprecated in kilo
    and an exception is raised if they are supplied with the 'sort' parameter.

    The sort parameters are removed from the request parameters by this
    function.

    :param params: webob.multidict of request parameters (from
                   sgservice.api.openstack.wsgi.Request.params)
    :param default_key: default sort key value, added to the list if no
                        sort keys are supplied
    :param default_dir: default sort dir value, added to the list if the
                        corresponding key does not have a direction
                        specified
    :returns: list of sort keys, list of sort dirs
    :raise webob.exc.HTTPBadRequest: If both 'sort' and either 'sort_key' or
                                     'sort_dir' are supplied parameters
    """
    if 'sort' in params and ('sort_key' in params or 'sort_dir' in params):
        msg = _("The 'sort_key' and 'sort_dir' parameters are deprecated and "
                "cannot be used with the 'sort' parameter.")
        raise webob.exc.HTTPBadRequest(explanation=msg)
    sort_keys = []
    sort_dirs = []
    if 'sort' in params:
        for sort in params.pop('sort').strip().split(','):
            sort_key, _sep, sort_dir = sort.partition(':')
            if not sort_dir:
                sort_dir = default_dir
            sort_keys.append(sort_key.strip())
            sort_dirs.append(sort_dir.strip())
    else:
        sort_key = params.pop('sort_key', default_key)
        sort_dir = params.pop('sort_dir', default_dir)
        sort_keys.append(sort_key.strip())
        sort_dirs.append(sort_dir.strip())
    return sort_keys, sort_dirs
Beispiel #30
0
def limited_by_marker(items, request, max_limit=None):
    """Return a slice of items according to the requested marker and limit."""
    max_limit = max_limit or CONF.osapi_max_limit
    marker, limit, __ = get_pagination_params(request.GET.copy(), max_limit)

    start_index = 0
    if marker:
        start_index = -1
        for i, item in enumerate(items):
            if 'flavorid' in item:
                if item['flavorid'] == marker:
                    start_index = i + 1
                    break
            elif item['id'] == marker or item.get('uuid') == marker:
                start_index = i + 1
                break
        if start_index < 0:
            msg = _('marker [%s] not found') % marker
            raise webob.exc.HTTPBadRequest(explanation=msg)
    range_end = start_index + limit
    return items[start_index:range_end]