Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
dmapi / usr / lib / python2.7 / dist-packages / dmapi / api / openstack / common.py
Size: Mime:
# Copyright 2018 TrilioData Inc.
# All Rights Reserved.

import collections
import functools
import itertools
import re

from oslo_log import log as logging
from oslo_utils import strutils
import six
import six.moves.urllib.parse as urlparse
import webob
from webob import exc

from dmapi.api.openstack import api_version_request
import dmapi.conf
from dmapi import exception
from dmapi.i18n import _
from dmapi import utils

CONF = dmapi.conf.CONF

LOG = logging.getLogger(__name__)


def get_id_from_href(href):
    """Return the id or uuid portion of a url.

    Given: 'http://www.foo.com/bar/123?q=4'
    Returns: '123'

    Given: 'http://www.foo.com/bar/abc123?q=4'
    Returns: 'abc123'

    """
    return urlparse.urlsplit("%s" % href).path.split('/')[-1]


def remove_trailing_version_from_href(href):
    """Removes the api version from the href.

    Given: 'http://www.dmapi.com/compute/v1.1'
    Returns: 'http://www.dmapi.com/compute'

    Given: 'http://www.dmapi.com/v1.1'
    Returns: 'http://www.dmapi.com'

    """
    parsed_url = urlparse.urlsplit(href)
    url_parts = parsed_url.path.rsplit('/', 1)

    # NOTE: this should match vX.X or vX
    expression = re.compile(r'^v([0-9]+|[0-9]+\.[0-9]+)(/.*|$)')
    if not expression.match(url_parts.pop()):
        LOG.debug('href %s does not contain version', href)
        raise ValueError(_('href %s does not contain version') % href)

    new_path = url_join(*url_parts)
    parsed_url = list(parsed_url)
    parsed_url[2] = new_path
    return urlparse.urlunsplit(parsed_url)


def url_join(*parts):
    """Convenience method for joining parts of a URL

    Any leading and trailing '/' characters are removed, and the parts joined
    together with '/' as a separator. If last element of 'parts' is an empty
    string, the returned URL will have a trailing slash.
    """
    parts = parts or [""]
    clean_parts = [part.strip("/") for part in parts if part]
    if not parts[-1]:
        # Empty last element should add a trailing slash
        clean_parts.append("")
    return "/".join(clean_parts)


class ViewBuilder(object):
    """Model API responses as dictionaries."""

    def _get_project_id(self, request):
        """Get project id from request url if present or empty string
        otherwise
        """
        project_id = request.environ["dmapi.context"].project_id
        if project_id and project_id in request.url:
            return project_id
        return ''

    def _get_links(self, request, identifier, collection_name):
        return [{
            "rel": "self",
            "href": self._get_href_link(request, identifier, collection_name),
        },
        {
            "rel": "bookmark",
            "href": self._get_bookmark_link(request,
                                            identifier,
                                            collection_name),
        }]

    def _get_next_link(self, request, identifier, collection_name):
        """Return href string with proper limit and marker params."""
        params = collections.OrderedDict(sorted(request.params.items()))
        params["marker"] = identifier
        prefix = self._update_dmapi_link_prefix(request.application_url)
        url = url_join(prefix,
                       self._get_project_id(request),
                       collection_name)
        return "%s?%s" % (url, urlparse.urlencode(params))

    def _get_href_link(self, request, identifier, collection_name):
        """Return an href string pointing to this object."""
        prefix = self._update_dmapi_link_prefix(request.application_url)
        return url_join(prefix,
                        self._get_project_id(request),
                        collection_name,
                        str(identifier))

    def _get_bookmark_link(self, request, identifier, collection_name):
        """Create a URL that refers to a specific resource."""
        base_url = remove_trailing_version_from_href(request.application_url)
        base_url = self._update_dmapi_link_prefix(base_url)
        return url_join(base_url,
                        self._get_project_id(request),
                        collection_name,
                        str(identifier))

    def _get_collection_links(self,
                              request,
                              items,
                              collection_name,
                              id_key="uuid"):
        """Retrieve 'next' link, if applicable. This is included if:
        1) 'limit' param is specified and equals the number of items.
        2) 'limit' param is specified but it exceeds CONF.api.max_limit,
        in this case the number of items is CONF.api.max_limit.
        3) 'limit' param is NOT specified but the number of items is
        CONF.api.max_limit.
        """
        links = []
        max_items = min(
            int(request.params.get("limit", CONF.api.max_limit)),
            CONF.api.max_limit)
        if max_items and max_items == len(items):
            last_item = items[-1]
            if id_key in last_item:
                last_item_id = last_item[id_key]
            elif 'id' in last_item:
                last_item_id = last_item["id"]
            else:
                last_item_id = last_item["flavorid"]
            links.append({
                "rel": "next",
                "href": self._get_next_link(request,
                                            last_item_id,
                                            collection_name),
            })
        return links

    def _update_link_prefix(self, orig_url, prefix):
        if not prefix:
            return orig_url
        url_parts = list(urlparse.urlsplit(orig_url))
        prefix_parts = list(urlparse.urlsplit(prefix))
        url_parts[0:2] = prefix_parts[0:2]
        url_parts[2] = prefix_parts[2] + url_parts[2]
        return urlparse.urlunsplit(url_parts).rstrip('/')

    def _update_dmapi_link_prefix(self, orig_url):
        return self._update_link_prefix(orig_url, CONF.api.dmapi_link_prefix)


def get_instance(compute_api, context, instance_id, expected_attrs=None):
    """Fetch an instance from the compute API, handling error checking."""
    try:
        return compute_api.get(context, instance_id,
                               expected_attrs=expected_attrs)
    except exception.InstanceNotFound as e:
        raise exc.HTTPNotFound(explanation=e.format_message())


def normalize_name(name):
    # NOTE(alex_xu): This method is used by v2.1 legacy v2 compat mode.
    # In the legacy v2 API, some of APIs strip the spaces and some of APIs not.
    # The v2.1 disallow leading/trailing, for compatible v2 API and consistent,
    # we enable leading/trailing spaces and strip spaces in legacy v2 compat
    # mode. Althrough in legacy v2 API there are some APIs didn't strip spaces,
    # but actually leading/trailing spaces(that means user depend on leading/
    # trailing spaces distinguish different instance) is pointless usecase.
    return name.strip()


def raise_feature_not_supported(msg=None):
    if msg is None:
        msg = _("The requested functionality is not supported.")
    raise webob.exc.HTTPNotImplemented(explanation=msg)