Merge "Use exceptions from oslo"
This commit is contained in:
commit
14108c1e78
@ -25,7 +25,7 @@ import os
|
||||
|
||||
import six
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient import utils
|
||||
|
||||
|
||||
|
@ -46,7 +46,7 @@ if not hasattr(urlparse, 'parse_qsl'):
|
||||
|
||||
import requests
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient import service_catalog
|
||||
from cinderclient import utils
|
||||
|
||||
@ -151,7 +151,7 @@ class HTTPClient(object):
|
||||
body = None
|
||||
|
||||
if resp.status_code >= 400:
|
||||
raise exceptions.from_response(resp, body)
|
||||
raise exceptions.from_response(resp, method, url)
|
||||
|
||||
return resp, body
|
||||
|
||||
@ -185,7 +185,7 @@ class HTTPClient(object):
|
||||
except exceptions.ClientException as e:
|
||||
if attempts > self.retries:
|
||||
raise
|
||||
if 500 <= e.code <= 599:
|
||||
if 500 <= e.http_status <= 599:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
@ -211,15 +211,16 @@ class HTTPClient(object):
|
||||
def delete(self, url, **kwargs):
|
||||
return self._cs_request(url, 'DELETE', **kwargs)
|
||||
|
||||
def _extract_service_catalog(self, url, resp, body, extract_token=True):
|
||||
def _extract_service_catalog(self, auth_url, url, method,
|
||||
extract_token=True, **kwargs):
|
||||
"""See what the auth service told us and process the response.
|
||||
We may get redirected to another site, fail or actually get
|
||||
back a service catalog with a token and our endpoints.
|
||||
"""
|
||||
|
||||
resp, body = self.request(url, method, **kwargs)
|
||||
if resp.status_code == 200: # content must always present
|
||||
try:
|
||||
self.auth_url = url
|
||||
self.auth_url = auth_url
|
||||
self.service_catalog = \
|
||||
service_catalog.ServiceCatalog(body)
|
||||
|
||||
@ -248,7 +249,7 @@ class HTTPClient(object):
|
||||
elif resp.status_code == 305:
|
||||
return resp['location']
|
||||
else:
|
||||
raise exceptions.from_response(resp, body)
|
||||
raise exceptions.from_response(resp, method, url)
|
||||
|
||||
def _fetch_endpoints_from_auth(self, url):
|
||||
"""We have a token, but don't know the final endpoint for
|
||||
@ -263,13 +264,14 @@ class HTTPClient(object):
|
||||
"""
|
||||
|
||||
# GET ...:5001/v2.0/tokens/#####/endpoints
|
||||
auth_url = url
|
||||
url = '/'.join([url, 'tokens', '%s?belongsTo=%s'
|
||||
% (self.proxy_token, self.proxy_tenant_id)])
|
||||
self._logger.debug("Using Endpoint URL: %s" % url)
|
||||
resp, body = self.request(url, "GET",
|
||||
headers={'X-Auth-Token': self.auth_token})
|
||||
return self._extract_service_catalog(url, resp, body,
|
||||
extract_token=False)
|
||||
return self._extract_service_catalog(
|
||||
auth_url,
|
||||
url, "GET", headers={'X-Auth-Token': self.auth_token},
|
||||
extract_token=False)
|
||||
|
||||
def authenticate(self):
|
||||
magic_tuple = urlparse.urlsplit(self.auth_url)
|
||||
@ -320,7 +322,9 @@ class HTTPClient(object):
|
||||
|
||||
def _v1_auth(self, url):
|
||||
if self.proxy_token:
|
||||
raise exceptions.NoTokenLookupException()
|
||||
raise exceptions.AuthorizationFailure(
|
||||
"This form of authentication does not support looking up"
|
||||
" endpoints from an existing token.")
|
||||
|
||||
headers = {'X-Auth-User': self.user,
|
||||
'X-Auth-Key': self.password}
|
||||
@ -339,7 +343,7 @@ class HTTPClient(object):
|
||||
elif resp.status_code == 305:
|
||||
return resp.headers['location']
|
||||
else:
|
||||
raise exceptions.from_response(resp, body)
|
||||
raise exceptions.from_response(resp, "GET", url)
|
||||
|
||||
def _v2_auth(self, url):
|
||||
"""Authenticate against a v2.0 auth service."""
|
||||
@ -369,14 +373,13 @@ class HTTPClient(object):
|
||||
token_url = url + "/tokens"
|
||||
|
||||
# Make sure we follow redirects when trying to reach Keystone
|
||||
resp, body = self.request(
|
||||
return self._extract_service_catalog(
|
||||
url,
|
||||
token_url,
|
||||
"POST",
|
||||
body=body,
|
||||
allow_redirects=True)
|
||||
|
||||
return self._extract_service_catalog(url, resp, body)
|
||||
|
||||
def get_volume_api_version_from_endpoint(self):
|
||||
magic_tuple = urlparse.urlsplit(self.management_url)
|
||||
scheme, netloc, path, query, frag = magic_tuple
|
||||
|
@ -1,156 +1,6 @@
|
||||
# Copyright 2010 Jacob Kaplan-Moss
|
||||
"""
|
||||
Exception definitions.
|
||||
Backwards compatible exceptions module.
|
||||
"""
|
||||
|
||||
|
||||
class UnsupportedVersion(Exception):
|
||||
"""Indicates that the user is trying to use an unsupported
|
||||
version of the API.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidAPIVersion(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CommandError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AuthorizationFailure(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NoUniqueMatch(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NoTokenLookupException(Exception):
|
||||
"""This form of authentication does not support looking up
|
||||
endpoints from an existing token.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class EndpointNotFound(Exception):
|
||||
"""Could not find Service or Region in Service Catalog."""
|
||||
pass
|
||||
|
||||
|
||||
class AmbiguousEndpoints(Exception):
|
||||
"""Found more than one matching endpoint in Service Catalog."""
|
||||
def __init__(self, endpoints=None):
|
||||
self.endpoints = endpoints
|
||||
|
||||
def __str__(self):
|
||||
return "AmbiguousEndpoints: %s" % repr(self.endpoints)
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
"""
|
||||
The base exception class for all exceptions this library raises.
|
||||
"""
|
||||
def __init__(self, code, message=None, details=None, request_id=None):
|
||||
self.code = code
|
||||
self.message = message or self.__class__.message
|
||||
self.details = details
|
||||
self.request_id = request_id
|
||||
|
||||
def __str__(self):
|
||||
formatted_string = "%s (HTTP %s)" % (self.message, self.code)
|
||||
if self.request_id:
|
||||
formatted_string += " (Request-ID: %s)" % self.request_id
|
||||
|
||||
return formatted_string
|
||||
|
||||
|
||||
class BadRequest(ClientException):
|
||||
"""
|
||||
HTTP 400 - Bad request: you sent some malformed data.
|
||||
"""
|
||||
http_status = 400
|
||||
message = "Bad request"
|
||||
|
||||
|
||||
class Unauthorized(ClientException):
|
||||
"""
|
||||
HTTP 401 - Unauthorized: bad credentials.
|
||||
"""
|
||||
http_status = 401
|
||||
message = "Unauthorized"
|
||||
|
||||
|
||||
class Forbidden(ClientException):
|
||||
"""
|
||||
HTTP 403 - Forbidden: your credentials don't give you access to this
|
||||
resource.
|
||||
"""
|
||||
http_status = 403
|
||||
message = "Forbidden"
|
||||
|
||||
|
||||
class NotFound(ClientException):
|
||||
"""
|
||||
HTTP 404 - Not found
|
||||
"""
|
||||
http_status = 404
|
||||
message = "Not found"
|
||||
|
||||
|
||||
class OverLimit(ClientException):
|
||||
"""
|
||||
HTTP 413 - Over limit: you're over the API limits for this time period.
|
||||
"""
|
||||
http_status = 413
|
||||
message = "Over limit"
|
||||
|
||||
|
||||
# NotImplemented is a python keyword.
|
||||
class HTTPNotImplemented(ClientException):
|
||||
"""
|
||||
HTTP 501 - Not Implemented: the server does not support this operation.
|
||||
"""
|
||||
http_status = 501
|
||||
message = "Not Implemented"
|
||||
|
||||
|
||||
# In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()
|
||||
# so we can do this:
|
||||
# _code_map = dict((c.http_status, c)
|
||||
# for c in ClientException.__subclasses__())
|
||||
#
|
||||
# Instead, we have to hardcode it:
|
||||
_code_map = dict((c.http_status, c) for c in [BadRequest, Unauthorized,
|
||||
Forbidden, NotFound,
|
||||
OverLimit, HTTPNotImplemented])
|
||||
|
||||
|
||||
def from_response(response, body):
|
||||
"""
|
||||
Return an instance of an ClientException or subclass
|
||||
based on an requests response.
|
||||
|
||||
Usage::
|
||||
|
||||
resp, body = requests.request(...)
|
||||
if resp.status_code != 200:
|
||||
raise exception_from_response(resp, rest.text)
|
||||
"""
|
||||
cls = _code_map.get(response.status_code, ClientException)
|
||||
if response.headers:
|
||||
request_id = response.headers.get('x-compute-request-id')
|
||||
else:
|
||||
request_id = None
|
||||
if body:
|
||||
message = "n/a"
|
||||
details = "n/a"
|
||||
if hasattr(body, 'keys'):
|
||||
error = body[list(body.keys())[0]]
|
||||
message = error.get('message', None)
|
||||
details = error.get('details', None)
|
||||
return cls(code=response.status_code, message=message, details=details,
|
||||
request_id=request_id)
|
||||
else:
|
||||
return cls(code=response.status_code, request_id=request_id)
|
||||
# flake8: noqa
|
||||
from cinderclient.openstack.common.apiclient.exceptions import *
|
||||
|
16
cinderclient/openstack/common/apiclient/__init__.py
Normal file
16
cinderclient/openstack/common/apiclient/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 OpenStack Foundation
|
||||
# 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.
|
446
cinderclient/openstack/common/apiclient/exceptions.py
Normal file
446
cinderclient/openstack/common/apiclient/exceptions.py
Normal file
@ -0,0 +1,446 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 Jacob Kaplan-Moss
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright 2013 Alessio Ababilov
|
||||
# Copyright 2013 OpenStack Foundation
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Exception definitions.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
"""The base exception class for all exceptions this library raises.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MissingArgs(ClientException):
|
||||
"""Supplied arguments are not sufficient for calling a function."""
|
||||
def __init__(self, missing):
|
||||
self.missing = missing
|
||||
msg = "Missing argument(s): %s" % ", ".join(missing)
|
||||
super(MissingArgs, self).__init__(msg)
|
||||
|
||||
|
||||
class ValidationError(ClientException):
|
||||
"""Error in validation on API client side."""
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedVersion(ClientException):
|
||||
"""User is trying to use an unsupported version of the API."""
|
||||
pass
|
||||
|
||||
|
||||
class CommandError(ClientException):
|
||||
"""Error in CLI tool."""
|
||||
pass
|
||||
|
||||
|
||||
class AuthorizationFailure(ClientException):
|
||||
"""Cannot authorize API client."""
|
||||
pass
|
||||
|
||||
|
||||
class AuthPluginOptionsMissing(AuthorizationFailure):
|
||||
"""Auth plugin misses some options."""
|
||||
def __init__(self, opt_names):
|
||||
super(AuthPluginOptionsMissing, self).__init__(
|
||||
"Authentication failed. Missing options: %s" %
|
||||
", ".join(opt_names))
|
||||
self.opt_names = opt_names
|
||||
|
||||
|
||||
class AuthSystemNotFound(AuthorizationFailure):
|
||||
"""User has specified a AuthSystem that is not installed."""
|
||||
def __init__(self, auth_system):
|
||||
super(AuthSystemNotFound, self).__init__(
|
||||
"AuthSystemNotFound: %s" % repr(auth_system))
|
||||
self.auth_system = auth_system
|
||||
|
||||
|
||||
class NoUniqueMatch(ClientException):
|
||||
"""Multiple entities found instead of one."""
|
||||
pass
|
||||
|
||||
|
||||
class EndpointException(ClientException):
|
||||
"""Something is rotten in Service Catalog."""
|
||||
pass
|
||||
|
||||
|
||||
class EndpointNotFound(EndpointException):
|
||||
"""Could not find requested endpoint in Service Catalog."""
|
||||
pass
|
||||
|
||||
|
||||
class AmbiguousEndpoints(EndpointException):
|
||||
"""Found more than one matching endpoint in Service Catalog."""
|
||||
def __init__(self, endpoints=None):
|
||||
super(AmbiguousEndpoints, self).__init__(
|
||||
"AmbiguousEndpoints: %s" % repr(endpoints))
|
||||
self.endpoints = endpoints
|
||||
|
||||
|
||||
class HttpError(ClientException):
|
||||
"""The base exception class for all HTTP exceptions.
|
||||
"""
|
||||
http_status = 0
|
||||
message = "HTTP Error"
|
||||
|
||||
def __init__(self, message=None, details=None,
|
||||
response=None, request_id=None,
|
||||
url=None, method=None, http_status=None):
|
||||
self.http_status = http_status or self.http_status
|
||||
self.message = message or self.message
|
||||
self.details = details
|
||||
self.request_id = request_id
|
||||
self.response = response
|
||||
self.url = url
|
||||
self.method = method
|
||||
formatted_string = "%s (HTTP %s)" % (self.message, self.http_status)
|
||||
if request_id:
|
||||
formatted_string += " (Request-ID: %s)" % request_id
|
||||
super(HttpError, self).__init__(formatted_string)
|
||||
|
||||
|
||||
class HttpClientError(HttpError):
|
||||
"""Client-side HTTP error.
|
||||
|
||||
Exception for cases in which the client seems to have erred.
|
||||
"""
|
||||
message = "HTTP Client Error"
|
||||
|
||||
|
||||
class HttpServerError(HttpError):
|
||||
"""Server-side HTTP error.
|
||||
|
||||
Exception for cases in which the server is aware that it has
|
||||
erred or is incapable of performing the request.
|
||||
"""
|
||||
message = "HTTP Server Error"
|
||||
|
||||
|
||||
class BadRequest(HttpClientError):
|
||||
"""HTTP 400 - Bad Request.
|
||||
|
||||
The request cannot be fulfilled due to bad syntax.
|
||||
"""
|
||||
http_status = 400
|
||||
message = "Bad Request"
|
||||
|
||||
|
||||
class Unauthorized(HttpClientError):
|
||||
"""HTTP 401 - Unauthorized.
|
||||
|
||||
Similar to 403 Forbidden, but specifically for use when authentication
|
||||
is required and has failed or has not yet been provided.
|
||||
"""
|
||||
http_status = 401
|
||||
message = "Unauthorized"
|
||||
|
||||
|
||||
class PaymentRequired(HttpClientError):
|
||||
"""HTTP 402 - Payment Required.
|
||||
|
||||
Reserved for future use.
|
||||
"""
|
||||
http_status = 402
|
||||
message = "Payment Required"
|
||||
|
||||
|
||||
class Forbidden(HttpClientError):
|
||||
"""HTTP 403 - Forbidden.
|
||||
|
||||
The request was a valid request, but the server is refusing to respond
|
||||
to it.
|
||||
"""
|
||||
http_status = 403
|
||||
message = "Forbidden"
|
||||
|
||||
|
||||
class NotFound(HttpClientError):
|
||||
"""HTTP 404 - Not Found.
|
||||
|
||||
The requested resource could not be found but may be available again
|
||||
in the future.
|
||||
"""
|
||||
http_status = 404
|
||||
message = "Not Found"
|
||||
|
||||
|
||||
class MethodNotAllowed(HttpClientError):
|
||||
"""HTTP 405 - Method Not Allowed.
|
||||
|
||||
A request was made of a resource using a request method not supported
|
||||
by that resource.
|
||||
"""
|
||||
http_status = 405
|
||||
message = "Method Not Allowed"
|
||||
|
||||
|
||||
class NotAcceptable(HttpClientError):
|
||||
"""HTTP 406 - Not Acceptable.
|
||||
|
||||
The requested resource is only capable of generating content not
|
||||
acceptable according to the Accept headers sent in the request.
|
||||
"""
|
||||
http_status = 406
|
||||
message = "Not Acceptable"
|
||||
|
||||
|
||||
class ProxyAuthenticationRequired(HttpClientError):
|
||||
"""HTTP 407 - Proxy Authentication Required.
|
||||
|
||||
The client must first authenticate itself with the proxy.
|
||||
"""
|
||||
http_status = 407
|
||||
message = "Proxy Authentication Required"
|
||||
|
||||
|
||||
class RequestTimeout(HttpClientError):
|
||||
"""HTTP 408 - Request Timeout.
|
||||
|
||||
The server timed out waiting for the request.
|
||||
"""
|
||||
http_status = 408
|
||||
message = "Request Timeout"
|
||||
|
||||
|
||||
class Conflict(HttpClientError):
|
||||
"""HTTP 409 - Conflict.
|
||||
|
||||
Indicates that the request could not be processed because of conflict
|
||||
in the request, such as an edit conflict.
|
||||
"""
|
||||
http_status = 409
|
||||
message = "Conflict"
|
||||
|
||||
|
||||
class Gone(HttpClientError):
|
||||
"""HTTP 410 - Gone.
|
||||
|
||||
Indicates that the resource requested is no longer available and will
|
||||
not be available again.
|
||||
"""
|
||||
http_status = 410
|
||||
message = "Gone"
|
||||
|
||||
|
||||
class LengthRequired(HttpClientError):
|
||||
"""HTTP 411 - Length Required.
|
||||
|
||||
The request did not specify the length of its content, which is
|
||||
required by the requested resource.
|
||||
"""
|
||||
http_status = 411
|
||||
message = "Length Required"
|
||||
|
||||
|
||||
class PreconditionFailed(HttpClientError):
|
||||
"""HTTP 412 - Precondition Failed.
|
||||
|
||||
The server does not meet one of the preconditions that the requester
|
||||
put on the request.
|
||||
"""
|
||||
http_status = 412
|
||||
message = "Precondition Failed"
|
||||
|
||||
|
||||
class RequestEntityTooLarge(HttpClientError):
|
||||
"""HTTP 413 - Request Entity Too Large.
|
||||
|
||||
The request is larger than the server is willing or able to process.
|
||||
"""
|
||||
http_status = 413
|
||||
message = "Request Entity Too Large"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
try:
|
||||
self.retry_after = int(kwargs.pop('retry_after'))
|
||||
except (KeyError, ValueError):
|
||||
self.retry_after = 0
|
||||
|
||||
super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class RequestUriTooLong(HttpClientError):
|
||||
"""HTTP 414 - Request-URI Too Long.
|
||||
|
||||
The URI provided was too long for the server to process.
|
||||
"""
|
||||
http_status = 414
|
||||
message = "Request-URI Too Long"
|
||||
|
||||
|
||||
class UnsupportedMediaType(HttpClientError):
|
||||
"""HTTP 415 - Unsupported Media Type.
|
||||
|
||||
The request entity has a media type which the server or resource does
|
||||
not support.
|
||||
"""
|
||||
http_status = 415
|
||||
message = "Unsupported Media Type"
|
||||
|
||||
|
||||
class RequestedRangeNotSatisfiable(HttpClientError):
|
||||
"""HTTP 416 - Requested Range Not Satisfiable.
|
||||
|
||||
The client has asked for a portion of the file, but the server cannot
|
||||
supply that portion.
|
||||
"""
|
||||
http_status = 416
|
||||
message = "Requested Range Not Satisfiable"
|
||||
|
||||
|
||||
class ExpectationFailed(HttpClientError):
|
||||
"""HTTP 417 - Expectation Failed.
|
||||
|
||||
The server cannot meet the requirements of the Expect request-header field.
|
||||
"""
|
||||
http_status = 417
|
||||
message = "Expectation Failed"
|
||||
|
||||
|
||||
class UnprocessableEntity(HttpClientError):
|
||||
"""HTTP 422 - Unprocessable Entity.
|
||||
|
||||
The request was well-formed but was unable to be followed due to semantic
|
||||
errors.
|
||||
"""
|
||||
http_status = 422
|
||||
message = "Unprocessable Entity"
|
||||
|
||||
|
||||
class InternalServerError(HttpServerError):
|
||||
"""HTTP 500 - Internal Server Error.
|
||||
|
||||
A generic error message, given when no more specific message is suitable.
|
||||
"""
|
||||
http_status = 500
|
||||
message = "Internal Server Error"
|
||||
|
||||
|
||||
# NotImplemented is a python keyword.
|
||||
class HttpNotImplemented(HttpServerError):
|
||||
"""HTTP 501 - Not Implemented.
|
||||
|
||||
The server either does not recognize the request method, or it lacks
|
||||
the ability to fulfill the request.
|
||||
"""
|
||||
http_status = 501
|
||||
message = "Not Implemented"
|
||||
|
||||
|
||||
class BadGateway(HttpServerError):
|
||||
"""HTTP 502 - Bad Gateway.
|
||||
|
||||
The server was acting as a gateway or proxy and received an invalid
|
||||
response from the upstream server.
|
||||
"""
|
||||
http_status = 502
|
||||
message = "Bad Gateway"
|
||||
|
||||
|
||||
class ServiceUnavailable(HttpServerError):
|
||||
"""HTTP 503 - Service Unavailable.
|
||||
|
||||
The server is currently unavailable.
|
||||
"""
|
||||
http_status = 503
|
||||
message = "Service Unavailable"
|
||||
|
||||
|
||||
class GatewayTimeout(HttpServerError):
|
||||
"""HTTP 504 - Gateway Timeout.
|
||||
|
||||
The server was acting as a gateway or proxy and did not receive a timely
|
||||
response from the upstream server.
|
||||
"""
|
||||
http_status = 504
|
||||
message = "Gateway Timeout"
|
||||
|
||||
|
||||
class HttpVersionNotSupported(HttpServerError):
|
||||
"""HTTP 505 - HttpVersion Not Supported.
|
||||
|
||||
The server does not support the HTTP protocol version used in the request.
|
||||
"""
|
||||
http_status = 505
|
||||
message = "HTTP Version Not Supported"
|
||||
|
||||
|
||||
# In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()
|
||||
# so we can do this:
|
||||
# _code_map = dict((c.http_status, c)
|
||||
# for c in HttpError.__subclasses__())
|
||||
_code_map = {}
|
||||
for obj in sys.modules[__name__].__dict__.values():
|
||||
if isinstance(obj, type):
|
||||
try:
|
||||
http_status = obj.http_status
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if http_status:
|
||||
_code_map[http_status] = obj
|
||||
|
||||
|
||||
def from_response(response, method, url):
|
||||
"""Returns an instance of :class:`HttpError` or subclass based on response.
|
||||
|
||||
:param response: instance of `requests.Response` class
|
||||
:param method: HTTP method used for request
|
||||
:param url: URL used for request
|
||||
"""
|
||||
kwargs = {
|
||||
"http_status": response.status_code,
|
||||
"response": response,
|
||||
"method": method,
|
||||
"url": url,
|
||||
"request_id": response.headers.get("x-compute-request-id"),
|
||||
}
|
||||
if "retry-after" in response.headers:
|
||||
kwargs["retry_after"] = response.headers["retry-after"]
|
||||
|
||||
content_type = response.headers.get("Content-Type", "")
|
||||
if content_type.startswith("application/json"):
|
||||
try:
|
||||
body = response.json()
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if hasattr(body, "keys"):
|
||||
error = body[body.keys()[0]]
|
||||
kwargs["message"] = error.get("message", None)
|
||||
kwargs["details"] = error.get("details", None)
|
||||
elif content_type.startswith("text/"):
|
||||
kwargs["details"] = response.text
|
||||
|
||||
try:
|
||||
cls = _code_map[response.status_code]
|
||||
except KeyError:
|
||||
if 500 <= response.status_code < 600:
|
||||
cls = HttpServerError
|
||||
elif 400 <= response.status_code < 500:
|
||||
cls = HttpClientError
|
||||
else:
|
||||
cls = HttpError
|
||||
return cls(**kwargs)
|
@ -32,8 +32,8 @@ import logging
|
||||
import six
|
||||
|
||||
from cinderclient import client
|
||||
from cinderclient import exceptions as exc
|
||||
import cinderclient.extension
|
||||
from cinderclient.openstack.common.apiclient import exceptions as exc
|
||||
from cinderclient.openstack.common import strutils
|
||||
from cinderclient import utils
|
||||
from cinderclient.v1 import shell as shell_v1
|
||||
|
@ -1,5 +1,5 @@
|
||||
from cinderclient import base
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient.v1 import volumes
|
||||
from cinderclient.tests import utils
|
||||
from cinderclient.tests.v1 import fakes
|
||||
|
@ -3,7 +3,7 @@ import mock
|
||||
import requests
|
||||
|
||||
from cinderclient import client
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient.tests import utils
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient import service_catalog
|
||||
from cinderclient.tests import utils
|
||||
|
||||
|
@ -5,7 +5,7 @@ import fixtures
|
||||
from six import moves
|
||||
from testtools import matchers
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
import cinderclient.shell
|
||||
from cinderclient.tests import utils
|
||||
|
||||
|
@ -3,7 +3,7 @@ import sys
|
||||
|
||||
from six import moves
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient import utils
|
||||
from cinderclient import base
|
||||
from cinderclient.tests import utils as test_utils
|
||||
|
@ -29,10 +29,11 @@ class TestResponse(requests.Response):
|
||||
|
||||
def __init__(self, data):
|
||||
self._text = None
|
||||
self.headers = {}
|
||||
super(TestResponse, self)
|
||||
if isinstance(data, dict):
|
||||
self.status_code = data.get('status_code', None)
|
||||
self.headers = data.get('headers', None)
|
||||
self.headers = data.get('headers') or {}
|
||||
# Fake the text attribute to streamline Response creation
|
||||
self._text = data.get('text', None)
|
||||
else:
|
||||
|
@ -4,7 +4,7 @@ import mock
|
||||
import requests
|
||||
|
||||
from cinderclient.v1 import client
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient.tests import utils
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ import json
|
||||
import mock
|
||||
import requests
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient.v2 import client
|
||||
from cinderclient.tests import utils
|
||||
|
||||
|
@ -23,7 +23,7 @@ import uuid
|
||||
import six
|
||||
import prettytable
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient.openstack.common import strutils
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient import utils
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ import time
|
||||
|
||||
import six
|
||||
|
||||
from cinderclient import exceptions
|
||||
from cinderclient.openstack.common.apiclient import exceptions
|
||||
from cinderclient import utils
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from openstack-common
|
||||
modules=strutils
|
||||
modules=apiclient,strutils
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=cinderclient
|
||||
|
Loading…
x
Reference in New Issue
Block a user