¡@

Home 

OpenStack Study: api_common.py

OpenStack Index

**** CubicPower OpenStack Study ****

# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2011 Citrix System.

# All Rights Reserved.

#

# Licensed under the Apache License, Version 2.0 (the "License"); you may

# not use this file except in compliance with the License. You may obtain

# a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

# License for the specific language governing permissions and limitations

# under the License.

import urllib

from oslo.config import cfg

from webob import exc

from neutron.common import constants

from neutron.common import exceptions

from neutron.openstack.common import log as logging

LOG = logging.getLogger(__name__)

**** CubicPower OpenStack Study ****

def get_filters(request, attr_info, skips=[]):

    """Extracts the filters from the request string.

    Returns a dict of lists for the filters:

    check=a&check=b&name=Bob&

    becomes:

    {'check': [u'a', u'b'], 'name': [u'Bob']}

    """

    res = {}

    for key, values in request.GET.dict_of_lists().iteritems():

        if key in skips:

            continue

        values = [v for v in values if v]

        key_attr_info = attr_info.get(key, {})

        if 'convert_list_to' in key_attr_info:

            values = key_attr_info['convert_list_to'](values)

        elif 'convert_to' in key_attr_info:

            convert_to = key_attr_info['convert_to']

            values = [convert_to(v) for v in values]

        if values:

            res[key] = values

    return res

**** CubicPower OpenStack Study ****

def get_previous_link(request, items, id_key):

    params = request.GET.copy()

    params.pop('marker', None)

    if items:

        marker = items[0][id_key]

        params['marker'] = marker

    params['page_reverse'] = True

    return "%s?%s" % (request.path_url, urllib.urlencode(params))

**** CubicPower OpenStack Study ****

def get_next_link(request, items, id_key):

    params = request.GET.copy()

    params.pop('marker', None)

    if items:

        marker = items[-1][id_key]

        params['marker'] = marker

    params.pop('page_reverse', None)

    return "%s?%s" % (request.path_url, urllib.urlencode(params))

**** CubicPower OpenStack Study ****

def get_limit_and_marker(request):

    """Return marker, limit tuple from request.

    :param request: `wsgi.Request` possibly containing 'marker' and 'limit'

                    GET variables. 'marker' is the id of the last element

                    the client has seen, and 'limit' is the maximum number

                    of items to return. If limit == 0, it means we needn't

                    pagination, then return None.

    """

    max_limit = _get_pagination_max_limit()

    limit = _get_limit_param(request, max_limit)

    if max_limit > 0:

        limit = min(max_limit, limit) or max_limit

    if not limit:

        return None, None

    marker = request.GET.get('marker', None)

    return limit, marker

**** CubicPower OpenStack Study ****

def _get_pagination_max_limit():

    max_limit = -1

    if (cfg.CONF.pagination_max_limit.lower() !=

        constants.PAGINATION_INFINITE):

        try:

            max_limit = int(cfg.CONF.pagination_max_limit)

            if max_limit == 0:

                raise ValueError()

        except ValueError:

            LOG.warn(_("Invalid value for pagination_max_limit: %s. It "

                       "should be an integer greater to 0"),

                     cfg.CONF.pagination_max_limit)

    return max_limit

**** CubicPower OpenStack Study ****

def _get_limit_param(request, max_limit):

    """Extract integer limit from request or fail."""

    try:

        limit = int(request.GET.get('limit', 0))

        if limit >= 0:

            return limit

    except ValueError:

        pass

    msg = _("Limit must be an integer 0 or greater and not '%d'")

    raise exceptions.BadRequest(resource='limit', msg=msg)

**** CubicPower OpenStack Study ****

def list_args(request, arg):

    """Extracts the list of arg from request."""

    return [v for v in request.GET.getall(arg) if v]

**** CubicPower OpenStack Study ****

def get_sorts(request, attr_info):

    """Extract sort_key and sort_dir from request.

    Return as: [(key1, value1), (key2, value2)]

    """

    sort_keys = list_args(request, "sort_key")

    sort_dirs = list_args(request, "sort_dir")

    if len(sort_keys) != len(sort_dirs):

        msg = _("The number of sort_keys and sort_dirs must be same")

        raise exc.HTTPBadRequest(explanation=msg)

    valid_dirs = [constants.SORT_DIRECTION_ASC, constants.SORT_DIRECTION_DESC]

    absent_keys = [x for x in sort_keys if x not in attr_info]

    if absent_keys:

        msg = _("%s is invalid attribute for sort_keys") % absent_keys

        raise exc.HTTPBadRequest(explanation=msg)

    invalid_dirs = [x for x in sort_dirs if x not in valid_dirs]

    if invalid_dirs:

        msg = (_("%(invalid_dirs)s is invalid value for sort_dirs, "

                 "valid value is '%(asc)s' and '%(desc)s'") %

               {'invalid_dirs': invalid_dirs,

                'asc': constants.SORT_DIRECTION_ASC,

                'desc': constants.SORT_DIRECTION_DESC})

        raise exc.HTTPBadRequest(explanation=msg)

    return zip(sort_keys,

               [x == constants.SORT_DIRECTION_ASC for x in sort_dirs])

**** CubicPower OpenStack Study ****

def get_page_reverse(request):

    data = request.GET.get('page_reverse', 'False')

    return data.lower() == "true"

**** CubicPower OpenStack Study ****

def get_pagination_links(request, items, limit,

                         marker, page_reverse, key="id"):

    key = key if key else 'id'

    links = []

    if not limit:

        return links

    if not (len(items) < limit and not page_reverse):

        links.append({"rel": "next",

                      "href": get_next_link(request, items,

                                            key)})

    if not (len(items) < limit and page_reverse):

        links.append({"rel": "previous",

                      "href": get_previous_link(request, items,

                                                key)})

    return links

**** CubicPower OpenStack Study ****

class PaginationHelper(object):

**** CubicPower OpenStack Study ****

    def __init__(self, request, primary_key='id'):

        self.request = request

        self.primary_key = primary_key

**** CubicPower OpenStack Study ****

    def update_fields(self, original_fields, fields_to_add):

        pass

**** CubicPower OpenStack Study ****

    def update_args(self, args):

        pass

**** CubicPower OpenStack Study ****

    def paginate(self, items):

        return items

**** CubicPower OpenStack Study ****

    def get_links(self, items):

        return {}

**** CubicPower OpenStack Study ****

class PaginationEmulatedHelper(PaginationHelper):

**** CubicPower OpenStack Study ****

    def __init__(self, request, primary_key='id'):

        super(PaginationEmulatedHelper, self).__init__(request, primary_key)

        self.limit, self.marker = get_limit_and_marker(request)

        self.page_reverse = get_page_reverse(request)

**** CubicPower OpenStack Study ****

    def update_fields(self, original_fields, fields_to_add):

        if not original_fields:

            return

        if self.primary_key not in original_fields:

            original_fields.append(self.primary_key)

            fields_to_add.append(self.primary_key)

**** CubicPower OpenStack Study ****

    def paginate(self, items):

        if not self.limit:

            return items

        i = -1

        if self.marker:

            for item in items:

                i = i + 1

                if item[self.primary_key] == self.marker:

                    break

        if self.page_reverse:

            return items[i - self.limit:i]

        return items[i + 1:i + self.limit + 1]

**** CubicPower OpenStack Study ****

    def get_links(self, items):

        return get_pagination_links(

            self.request, items, self.limit, self.marker,

            self.page_reverse, self.primary_key)

**** CubicPower OpenStack Study ****

class PaginationNativeHelper(PaginationEmulatedHelper):

**** CubicPower OpenStack Study ****

    def update_args(self, args):

        if self.primary_key not in dict(args.get('sorts', [])).keys():

            args.setdefault('sorts', []).append((self.primary_key, True))

        args.update({'limit': self.limit, 'marker': self.marker,

                     'page_reverse': self.page_reverse})

**** CubicPower OpenStack Study ****

    def paginate(self, items):

        return items

**** CubicPower OpenStack Study ****

class NoPaginationHelper(PaginationHelper):

pass

**** CubicPower OpenStack Study ****

class SortingHelper(object):

**** CubicPower OpenStack Study ****

    def __init__(self, request, attr_info):

        pass

**** CubicPower OpenStack Study ****

    def update_args(self, args):

        pass

**** CubicPower OpenStack Study ****

    def update_fields(self, original_fields, fields_to_add):

        pass

**** CubicPower OpenStack Study ****

    def sort(self, items):

        return items

**** CubicPower OpenStack Study ****

class SortingEmulatedHelper(SortingHelper):

**** CubicPower OpenStack Study ****

    def __init__(self, request, attr_info):

        super(SortingEmulatedHelper, self).__init__(request, attr_info)

        self.sort_dict = get_sorts(request, attr_info)

**** CubicPower OpenStack Study ****

    def update_fields(self, original_fields, fields_to_add):

        if not original_fields:

            return

        for key in dict(self.sort_dict).keys():

            if key not in original_fields:

                original_fields.append(key)

                fields_to_add.append(key)

**** CubicPower OpenStack Study ****

    def sort(self, items):

        def cmp_func(obj1, obj2):

            for key, direction in self.sort_dict:

                ret = cmp(obj1[key], obj2[key])

                if ret:

                    return ret * (1 if direction else -1)

            return 0

        return sorted(items, cmp=cmp_func)

**** CubicPower OpenStack Study ****

        def cmp_func(obj1, obj2):

            for key, direction in self.sort_dict:

                ret = cmp(obj1[key], obj2[key])

                if ret:

                    return ret * (1 if direction else -1)

            return 0

        return sorted(items, cmp=cmp_func)

**** CubicPower OpenStack Study ****

class SortingNativeHelper(SortingHelper):

**** CubicPower OpenStack Study ****

    def __init__(self, request, attr_info):

        self.sort_dict = get_sorts(request, attr_info)

**** CubicPower OpenStack Study ****

    def update_args(self, args):

        args['sorts'] = self.sort_dict

**** CubicPower OpenStack Study ****

class NoSortingHelper(SortingHelper):

pass

**** CubicPower OpenStack Study ****

class NeutronController(object):

"""Base controller class for Neutron API."""

# _resource_name will be re

**** CubicPower OpenStack Study ****

    def __init__(self, plugin):

        self._plugin = plugin

        super(NeutronController, self).__init__()

**** CubicPower OpenStack Study ****

    def _prepare_request_body(self, body, params):

        """Verifies required parameters are in request body.

        Sets default value for missing optional parameters.

        Body argument must be the deserialized body.

        """

        try:

            if body is None:

                # Initialize empty resource for setting default value

                body = {self._resource_name: {}}

            data = body[self._resource_name]

        except KeyError:

            # raise if _resource_name is not in req body.

            raise exc.HTTPBadRequest(_("Unable to find '%s' in request body") %

                                     self._resource_name)

        for param in params:

            param_name = param['param-name']

            param_value = data.get(param_name)

            # If the parameter wasn't found and it was required, return 400

            if param_value is None and param['required']:

                msg = (_("Failed to parse request. "

                         "Parameter '%s' not specified") % param_name)

                LOG.error(msg)

                raise exc.HTTPBadRequest(msg)

            data[param_name] = param_value or param.get('default-value')

        return body