Merge "Sync Oslo's apiclient"

This commit is contained in:
Jenkins 2014-06-28 18:24:25 +00:00 committed by Gerrit Code Review
commit 5a3ca61cfd
4 changed files with 71 additions and 49 deletions

View File

@ -213,8 +213,8 @@ class BaseAuthPlugin(object):
:type service_type: string :type service_type: string
:param endpoint_type: Type of endpoint. :param endpoint_type: Type of endpoint.
Possible values: public or publicURL, Possible values: public or publicURL,
internal or internalURL, internal or internalURL,
admin or adminURL admin or adminURL
:type endpoint_type: string :type endpoint_type: string
:returns: tuple of token and endpoint strings :returns: tuple of token and endpoint strings
:raises: EndpointException :raises: EndpointException

View File

@ -30,6 +30,7 @@ import six
from six.moves.urllib import parse from six.moves.urllib import parse
from novaclient.openstack.common.apiclient import exceptions from novaclient.openstack.common.apiclient import exceptions
from novaclient.openstack.common.gettextutils import _
from novaclient.openstack.common import strutils from novaclient.openstack.common import strutils
@ -74,8 +75,8 @@ class HookableMixin(object):
:param cls: class that registers hooks :param cls: class that registers hooks
:param hook_type: hook type, e.g., '__pre_parse_args__' :param hook_type: hook type, e.g., '__pre_parse_args__'
:param **args: args to be passed to every hook function :param args: args to be passed to every hook function
:param **kwargs: kwargs to be passed to every hook function :param kwargs: kwargs to be passed to every hook function
""" """
hook_funcs = cls._hooks_map.get(hook_type) or [] hook_funcs = cls._hooks_map.get(hook_type) or []
for hook_func in hook_funcs: for hook_func in hook_funcs:
@ -219,7 +220,10 @@ class ManagerWithFind(BaseManager):
matches = self.findall(**kwargs) matches = self.findall(**kwargs)
num_matches = len(matches) num_matches = len(matches)
if num_matches == 0: if num_matches == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) msg = _("No %(name)s matching %(args)s.") % {
'name': self.resource_class.__name__,
'args': kwargs
}
raise exceptions.NotFound(msg) raise exceptions.NotFound(msg)
elif num_matches > 1: elif num_matches > 1:
raise exceptions.NoUniqueMatch() raise exceptions.NoUniqueMatch()
@ -373,7 +377,10 @@ class CrudManager(BaseManager):
num = len(rl) num = len(rl)
if num == 0: if num == 0:
msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) msg = _("No %(name)s matching %(args)s.") % {
'name': self.resource_class.__name__,
'args': kwargs
}
raise exceptions.NotFound(404, msg) raise exceptions.NotFound(404, msg)
elif num > 1: elif num > 1:
raise exceptions.NoUniqueMatch raise exceptions.NoUniqueMatch
@ -441,8 +448,10 @@ class Resource(object):
def human_id(self): def human_id(self):
"""Human-readable ID which can be used for bash completion. """Human-readable ID which can be used for bash completion.
""" """
if self.NAME_ATTR in self.__dict__ and self.HUMAN_ID: if self.HUMAN_ID:
return strutils.to_slug(getattr(self, self.NAME_ATTR)) name = getattr(self, self.NAME_ATTR, None)
if name is not None:
return strutils.to_slug(name)
return None return None
def _add_details(self, info): def _add_details(self, info):

View File

@ -36,6 +36,7 @@ except ImportError:
import requests import requests
from novaclient.openstack.common.apiclient import exceptions from novaclient.openstack.common.apiclient import exceptions
from novaclient.openstack.common.gettextutils import _
from novaclient.openstack.common import importutils from novaclient.openstack.common import importutils
@ -46,6 +47,7 @@ class HTTPClient(object):
"""This client handles sending HTTP requests to OpenStack servers. """This client handles sending HTTP requests to OpenStack servers.
Features: Features:
- share authentication information between several clients to different - share authentication information between several clients to different
services (e.g., for compute and image clients); services (e.g., for compute and image clients);
- reissue authentication request for expired tokens; - reissue authentication request for expired tokens;
@ -151,7 +153,7 @@ class HTTPClient(object):
:param method: method of HTTP request :param method: method of HTTP request
:param url: URL of HTTP request :param url: URL of HTTP request
:param kwargs: any other parameter that can be passed to :param kwargs: any other parameter that can be passed to
' requests.Session.request (such as `headers`) or `json` requests.Session.request (such as `headers`) or `json`
that will be encoded as JSON and used as `data` argument that will be encoded as JSON and used as `data` argument
""" """
kwargs.setdefault("headers", kwargs.get("headers", {})) kwargs.setdefault("headers", kwargs.get("headers", {}))
@ -206,7 +208,7 @@ class HTTPClient(object):
:param method: method of HTTP request :param method: method of HTTP request
:param url: URL of HTTP request :param url: URL of HTTP request
:param kwargs: any other parameter that can be passed to :param kwargs: any other parameter that can be passed to
' `HTTPClient.request` `HTTPClient.request`
""" """
filter_args = { filter_args = {
@ -228,7 +230,7 @@ class HTTPClient(object):
**filter_args) **filter_args)
if not (token and endpoint): if not (token and endpoint):
raise exceptions.AuthorizationFailure( raise exceptions.AuthorizationFailure(
"Cannot find endpoint or token for request") _("Cannot find endpoint or token for request"))
old_token_endpoint = (token, endpoint) old_token_endpoint = (token, endpoint)
kwargs.setdefault("headers", {})["X-Auth-Token"] = token kwargs.setdefault("headers", {})["X-Auth-Token"] = token
@ -351,8 +353,12 @@ class BaseClient(object):
try: try:
client_path = version_map[str(version)] client_path = version_map[str(version)]
except (KeyError, ValueError): except (KeyError, ValueError):
msg = "Invalid %s client version '%s'. must be one of: %s" % ( msg = _("Invalid %(api_name)s client version '%(version)s'. "
(api_name, version, ', '.join(version_map.keys()))) "Must be one of: %(version_map)s") % {
'api_name': api_name,
'version': version,
'version_map': ', '.join(version_map.keys())
}
raise exceptions.UnsupportedVersion(msg) raise exceptions.UnsupportedVersion(msg)
return importutils.import_class(client_path) return importutils.import_class(client_path)

View File

@ -25,6 +25,8 @@ import sys
import six import six
from novaclient.openstack.common.gettextutils import _
class ClientException(Exception): class ClientException(Exception):
"""The base exception class for all exceptions this library raises. """The base exception class for all exceptions this library raises.
@ -36,7 +38,7 @@ class MissingArgs(ClientException):
"""Supplied arguments are not sufficient for calling a function.""" """Supplied arguments are not sufficient for calling a function."""
def __init__(self, missing): def __init__(self, missing):
self.missing = missing self.missing = missing
msg = "Missing argument(s): %s" % ", ".join(missing) msg = _("Missing arguments: %s") % ", ".join(missing)
super(MissingArgs, self).__init__(msg) super(MissingArgs, self).__init__(msg)
@ -74,16 +76,16 @@ class AuthPluginOptionsMissing(AuthorizationFailure):
"""Auth plugin misses some options.""" """Auth plugin misses some options."""
def __init__(self, opt_names): def __init__(self, opt_names):
super(AuthPluginOptionsMissing, self).__init__( super(AuthPluginOptionsMissing, self).__init__(
"Authentication failed. Missing options: %s" % _("Authentication failed. Missing options: %s") %
", ".join(opt_names)) ", ".join(opt_names))
self.opt_names = opt_names self.opt_names = opt_names
class AuthSystemNotFound(AuthorizationFailure): class AuthSystemNotFound(AuthorizationFailure):
"""User has specified a AuthSystem that is not installed.""" """User has specified an AuthSystem that is not installed."""
def __init__(self, auth_system): def __init__(self, auth_system):
super(AuthSystemNotFound, self).__init__( super(AuthSystemNotFound, self).__init__(
"AuthSystemNotFound: %s" % repr(auth_system)) _("AuthSystemNotFound: %s") % repr(auth_system))
self.auth_system = auth_system self.auth_system = auth_system
@ -106,7 +108,7 @@ class AmbiguousEndpoints(EndpointException):
"""Found more than one matching endpoint in Service Catalog.""" """Found more than one matching endpoint in Service Catalog."""
def __init__(self, endpoints=None): def __init__(self, endpoints=None):
super(AmbiguousEndpoints, self).__init__( super(AmbiguousEndpoints, self).__init__(
"AmbiguousEndpoints: %s" % repr(endpoints)) _("AmbiguousEndpoints: %s") % repr(endpoints))
self.endpoints = endpoints self.endpoints = endpoints
@ -114,7 +116,7 @@ class HttpError(ClientException):
"""The base exception class for all HTTP exceptions. """The base exception class for all HTTP exceptions.
""" """
http_status = 0 http_status = 0
message = "HTTP Error" message = _("HTTP Error")
def __init__(self, message=None, details=None, def __init__(self, message=None, details=None,
response=None, request_id=None, response=None, request_id=None,
@ -134,7 +136,7 @@ class HttpError(ClientException):
class HTTPRedirection(HttpError): class HTTPRedirection(HttpError):
"""HTTP Redirection.""" """HTTP Redirection."""
message = "HTTP Redirection" message = _("HTTP Redirection")
class HTTPClientError(HttpError): class HTTPClientError(HttpError):
@ -142,7 +144,7 @@ class HTTPClientError(HttpError):
Exception for cases in which the client seems to have erred. Exception for cases in which the client seems to have erred.
""" """
message = "HTTP Client Error" message = _("HTTP Client Error")
class HttpServerError(HttpError): class HttpServerError(HttpError):
@ -151,7 +153,7 @@ class HttpServerError(HttpError):
Exception for cases in which the server is aware that it has Exception for cases in which the server is aware that it has
erred or is incapable of performing the request. erred or is incapable of performing the request.
""" """
message = "HTTP Server Error" message = _("HTTP Server Error")
class MultipleChoices(HTTPRedirection): class MultipleChoices(HTTPRedirection):
@ -161,7 +163,7 @@ class MultipleChoices(HTTPRedirection):
""" """
http_status = 300 http_status = 300
message = "Multiple Choices" message = _("Multiple Choices")
class BadRequest(HTTPClientError): class BadRequest(HTTPClientError):
@ -170,7 +172,7 @@ class BadRequest(HTTPClientError):
The request cannot be fulfilled due to bad syntax. The request cannot be fulfilled due to bad syntax.
""" """
http_status = 400 http_status = 400
message = "Bad Request" message = _("Bad Request")
class Unauthorized(HTTPClientError): class Unauthorized(HTTPClientError):
@ -180,7 +182,7 @@ class Unauthorized(HTTPClientError):
is required and has failed or has not yet been provided. is required and has failed or has not yet been provided.
""" """
http_status = 401 http_status = 401
message = "Unauthorized" message = _("Unauthorized")
class PaymentRequired(HTTPClientError): class PaymentRequired(HTTPClientError):
@ -189,7 +191,7 @@ class PaymentRequired(HTTPClientError):
Reserved for future use. Reserved for future use.
""" """
http_status = 402 http_status = 402
message = "Payment Required" message = _("Payment Required")
class Forbidden(HTTPClientError): class Forbidden(HTTPClientError):
@ -199,7 +201,7 @@ class Forbidden(HTTPClientError):
to it. to it.
""" """
http_status = 403 http_status = 403
message = "Forbidden" message = _("Forbidden")
class NotFound(HTTPClientError): class NotFound(HTTPClientError):
@ -209,7 +211,7 @@ class NotFound(HTTPClientError):
in the future. in the future.
""" """
http_status = 404 http_status = 404
message = "Not Found" message = _("Not Found")
class MethodNotAllowed(HTTPClientError): class MethodNotAllowed(HTTPClientError):
@ -219,7 +221,7 @@ class MethodNotAllowed(HTTPClientError):
by that resource. by that resource.
""" """
http_status = 405 http_status = 405
message = "Method Not Allowed" message = _("Method Not Allowed")
class NotAcceptable(HTTPClientError): class NotAcceptable(HTTPClientError):
@ -229,7 +231,7 @@ class NotAcceptable(HTTPClientError):
acceptable according to the Accept headers sent in the request. acceptable according to the Accept headers sent in the request.
""" """
http_status = 406 http_status = 406
message = "Not Acceptable" message = _("Not Acceptable")
class ProxyAuthenticationRequired(HTTPClientError): class ProxyAuthenticationRequired(HTTPClientError):
@ -238,7 +240,7 @@ class ProxyAuthenticationRequired(HTTPClientError):
The client must first authenticate itself with the proxy. The client must first authenticate itself with the proxy.
""" """
http_status = 407 http_status = 407
message = "Proxy Authentication Required" message = _("Proxy Authentication Required")
class RequestTimeout(HTTPClientError): class RequestTimeout(HTTPClientError):
@ -247,7 +249,7 @@ class RequestTimeout(HTTPClientError):
The server timed out waiting for the request. The server timed out waiting for the request.
""" """
http_status = 408 http_status = 408
message = "Request Timeout" message = _("Request Timeout")
class Conflict(HTTPClientError): class Conflict(HTTPClientError):
@ -257,7 +259,7 @@ class Conflict(HTTPClientError):
in the request, such as an edit conflict. in the request, such as an edit conflict.
""" """
http_status = 409 http_status = 409
message = "Conflict" message = _("Conflict")
class Gone(HTTPClientError): class Gone(HTTPClientError):
@ -267,7 +269,7 @@ class Gone(HTTPClientError):
not be available again. not be available again.
""" """
http_status = 410 http_status = 410
message = "Gone" message = _("Gone")
class LengthRequired(HTTPClientError): class LengthRequired(HTTPClientError):
@ -277,7 +279,7 @@ class LengthRequired(HTTPClientError):
required by the requested resource. required by the requested resource.
""" """
http_status = 411 http_status = 411
message = "Length Required" message = _("Length Required")
class PreconditionFailed(HTTPClientError): class PreconditionFailed(HTTPClientError):
@ -287,7 +289,7 @@ class PreconditionFailed(HTTPClientError):
put on the request. put on the request.
""" """
http_status = 412 http_status = 412
message = "Precondition Failed" message = _("Precondition Failed")
class RequestEntityTooLarge(HTTPClientError): class RequestEntityTooLarge(HTTPClientError):
@ -296,7 +298,7 @@ class RequestEntityTooLarge(HTTPClientError):
The request is larger than the server is willing or able to process. The request is larger than the server is willing or able to process.
""" """
http_status = 413 http_status = 413
message = "Request Entity Too Large" message = _("Request Entity Too Large")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
try: try:
@ -313,7 +315,7 @@ class RequestUriTooLong(HTTPClientError):
The URI provided was too long for the server to process. The URI provided was too long for the server to process.
""" """
http_status = 414 http_status = 414
message = "Request-URI Too Long" message = _("Request-URI Too Long")
class UnsupportedMediaType(HTTPClientError): class UnsupportedMediaType(HTTPClientError):
@ -323,7 +325,7 @@ class UnsupportedMediaType(HTTPClientError):
not support. not support.
""" """
http_status = 415 http_status = 415
message = "Unsupported Media Type" message = _("Unsupported Media Type")
class RequestedRangeNotSatisfiable(HTTPClientError): class RequestedRangeNotSatisfiable(HTTPClientError):
@ -333,7 +335,7 @@ class RequestedRangeNotSatisfiable(HTTPClientError):
supply that portion. supply that portion.
""" """
http_status = 416 http_status = 416
message = "Requested Range Not Satisfiable" message = _("Requested Range Not Satisfiable")
class ExpectationFailed(HTTPClientError): class ExpectationFailed(HTTPClientError):
@ -342,7 +344,7 @@ class ExpectationFailed(HTTPClientError):
The server cannot meet the requirements of the Expect request-header field. The server cannot meet the requirements of the Expect request-header field.
""" """
http_status = 417 http_status = 417
message = "Expectation Failed" message = _("Expectation Failed")
class UnprocessableEntity(HTTPClientError): class UnprocessableEntity(HTTPClientError):
@ -352,7 +354,7 @@ class UnprocessableEntity(HTTPClientError):
errors. errors.
""" """
http_status = 422 http_status = 422
message = "Unprocessable Entity" message = _("Unprocessable Entity")
class InternalServerError(HttpServerError): class InternalServerError(HttpServerError):
@ -361,7 +363,7 @@ class InternalServerError(HttpServerError):
A generic error message, given when no more specific message is suitable. A generic error message, given when no more specific message is suitable.
""" """
http_status = 500 http_status = 500
message = "Internal Server Error" message = _("Internal Server Error")
# NotImplemented is a python keyword. # NotImplemented is a python keyword.
@ -372,7 +374,7 @@ class HttpNotImplemented(HttpServerError):
the ability to fulfill the request. the ability to fulfill the request.
""" """
http_status = 501 http_status = 501
message = "Not Implemented" message = _("Not Implemented")
class BadGateway(HttpServerError): class BadGateway(HttpServerError):
@ -382,7 +384,7 @@ class BadGateway(HttpServerError):
response from the upstream server. response from the upstream server.
""" """
http_status = 502 http_status = 502
message = "Bad Gateway" message = _("Bad Gateway")
class ServiceUnavailable(HttpServerError): class ServiceUnavailable(HttpServerError):
@ -391,7 +393,7 @@ class ServiceUnavailable(HttpServerError):
The server is currently unavailable. The server is currently unavailable.
""" """
http_status = 503 http_status = 503
message = "Service Unavailable" message = _("Service Unavailable")
class GatewayTimeout(HttpServerError): class GatewayTimeout(HttpServerError):
@ -401,7 +403,7 @@ class GatewayTimeout(HttpServerError):
response from the upstream server. response from the upstream server.
""" """
http_status = 504 http_status = 504
message = "Gateway Timeout" message = _("Gateway Timeout")
class HttpVersionNotSupported(HttpServerError): class HttpVersionNotSupported(HttpServerError):
@ -410,7 +412,7 @@ class HttpVersionNotSupported(HttpServerError):
The server does not support the HTTP protocol version used in the request. The server does not support the HTTP protocol version used in the request.
""" """
http_status = 505 http_status = 505
message = "HTTP Version Not Supported" message = _("HTTP Version Not Supported")
# _code_map contains all the classes that have http_status attribute. # _code_map contains all the classes that have http_status attribute.
@ -428,12 +430,17 @@ def from_response(response, method, url):
:param method: HTTP method used for request :param method: HTTP method used for request
:param url: URL used for request :param url: URL used for request
""" """
req_id = response.headers.get("x-openstack-request-id")
#NOTE(hdd) true for older versions of nova and cinder
if not req_id:
req_id = response.headers.get("x-compute-request-id")
kwargs = { kwargs = {
"http_status": response.status_code, "http_status": response.status_code,
"response": response, "response": response,
"method": method, "method": method,
"url": url, "url": url,
"request_id": response.headers.get("x-compute-request-id"), "request_id": req_id,
} }
if "retry-after" in response.headers: if "retry-after" in response.headers:
kwargs["retry_after"] = response.headers["retry-after"] kwargs["retry_after"] = response.headers["retry-after"]