summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Lennox <jamielennox@gmail.com>2015-11-11 10:51:42 +1100
committerJamie Lennox <jamielennox@gmail.com>2015-11-19 13:35:18 +1100
commitbdd44d314217cfc834505404b8583289c22e9e9d (patch)
tree0ee01579ab26bd6b82a245ccfd12462897920203
parent4a070903d29aca07a8d19b59bb20818d1c759c44 (diff)
downloadpython-keystoneclient-bdd44d314217cfc834505404b8583289c22e9e9d.tar.gz
Map keystoneclient exceptions to keystoneauth
To allow people to use a keystoneauth session with keystoneclient we need to make it so that any exceptions that keystoneclient catch are the same as what keystoneauth might throw. The only practical way to do this is to map the keystoneclient exceptions onto the keystoneauth equivalents. This is fairly easy as all these exceptions were extracted from keystoneclient initially. Closes-Bug: #1515048 Change-Id: I3b74b0ba1e1f9dda937a2d90e2d75ff0b7597a9b
-rw-r--r--doc/source/conf.py2
-rw-r--r--keystoneclient/exceptions.py571
2 files changed, 225 insertions, 348 deletions
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 593d7e2..9f05b9d 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -224,7 +224,9 @@ latex_documents = [
# If false, no module index is generated.
#latex_use_modindex = True
+keystoneauth_url = 'http://docs.openstack.org/developer/keystoneauth/'
intersphinx_mapping = {
'python': ('http://docs.python.org/', None),
'osloconfig': ('http://docs.openstack.org/developer/oslo.config/', None),
+ 'keystoneauth1': (keystoneauth_url, None),
}
diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py
index 8756929..0bbd35a 100644
--- a/keystoneclient/exceptions.py
+++ b/keystoneclient/exceptions.py
@@ -14,47 +14,54 @@
# under the License.
"""Exception definitions."""
-import inspect
-import sys
-
-import six
+from keystoneauth1 import exceptions as _exc
from keystoneclient.i18n import _
-class ClientException(Exception):
- """The base exception class for all exceptions this library raises.
- """
- pass
+ClientException = _exc.ClientException
+"""The base exception class for all exceptions this library raises.
+An alias of :py:exc:`keystoneauth1.exceptions.base.ClientException`
+"""
-class ValidationError(ClientException):
- """Error in validation on API client side."""
- pass
+ConnectionError = _exc.ConnectionError
+"""Cannot connect to API service.
+An alias of :py:exc:`keystoneauth1.exceptions.connection.ConnectionError`
+"""
-class UnsupportedVersion(ClientException):
- """User is trying to use an unsupported version of the API."""
- pass
+ConnectionRefused = _exc.ConnectFailure
+"""Connection refused while trying to connect to API service.
+An alias of :py:exc:`keystoneauth1.exceptions.connection.ConnectFailure`
+"""
-class CommandError(ClientException):
- """Error in CLI tool."""
- pass
+SSLError = _exc.SSLError
+"""An SSL error occurred.
+
+An alias of :py:exc:`keystoneauth1.exceptions.connection.SSLError`
+"""
+AuthorizationFailure = _exc.AuthorizationFailure
+"""Cannot authorize API client.
-class AuthorizationFailure(ClientException):
- """Cannot authorize API client."""
+An alias of :py:exc:`keystoneauth1.exceptions.auth.AuthorizationFailure`
+"""
+
+
+class ValidationError(ClientException):
+ """Error in validation on API client side."""
pass
-class ConnectionError(ClientException):
- """Cannot connect to API service."""
+class UnsupportedVersion(ClientException):
+ """User is trying to use an unsupported version of the API."""
pass
-class ConnectionRefused(ConnectionError):
- """Connection refused while trying to connect to API service."""
+class CommandError(ClientException):
+ """Error in CLI tool."""
pass
@@ -80,14 +87,17 @@ class NoUniqueMatch(ClientException):
pass
-class EndpointException(ClientException):
- """Something is rotten in Service Catalog."""
- pass
+EndpointException = _exc.CatalogException
+"""Something is rotten in Service Catalog.
+An alias of :py:exc:`keystoneauth1.exceptions.catalog.CatalogException`
+"""
-class EndpointNotFound(EndpointException):
- """Could not find requested endpoint in Service Catalog."""
- pass
+EndpointNotFound = _exc.EndpointNotFound
+"""Could not find requested endpoint in Service Catalog.
+
+An alias of :py:exc:`keystoneauth1.exceptions.catalog.EndpointNotFound`
+"""
class AmbiguousEndpoints(EndpointException):
@@ -98,48 +108,31 @@ class AmbiguousEndpoints(EndpointException):
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)
-
+HttpError = _exc.HttpError
+"""The base exception class for all HTTP exceptions.
-class HTTPRedirection(HttpError):
- """HTTP Redirection."""
- message = _("HTTP Redirection")
+An alias of :py:exc:`keystoneauth1.exceptions.http.HttpError`
+"""
+HTTPClientError = _exc.HTTPClientError
+"""Client-side HTTP error.
-class HTTPClientError(HttpError):
- """Client-side HTTP error.
+Exception for cases in which the client seems to have erred.
+An alias of :py:exc:`keystoneauth1.exceptions.http.HTTPClientError`
+"""
- Exception for cases in which the client seems to have erred.
- """
- message = _("HTTP Client Error")
+HttpServerError = _exc.HttpServerError
+"""Server-side HTTP error.
+Exception for cases in which the server is aware that it has
+erred or is incapable of performing the request.
+An alias of :py:exc:`keystoneauth1.exceptions.http.HttpServerError`
+"""
-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 HTTPRedirection(HttpError):
+ """HTTP Redirection."""
+ message = _("HTTP Redirection")
class MultipleChoices(HTTPRedirection):
@@ -152,318 +145,207 @@ class MultipleChoices(HTTPRedirection):
message = _("Multiple Choices")
-class BadRequest(HTTPClientError):
- """HTTP 400 - Bad Request.
+BadRequest = _exc.BadRequest
+"""HTTP 400 - Bad Request.
- The request cannot be fulfilled due to bad syntax.
- """
- http_status = 400
- message = _("Bad Request")
+The request cannot be fulfilled due to bad syntax.
+An alias of :py:exc:`keystoneauth1.exceptions.http.BadRequest`
+"""
+Unauthorized = _exc.Unauthorized
+"""HTTP 401 - Unauthorized.
-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.
+An alias of :py:exc:`keystoneauth1.exceptions.http.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")
+PaymentRequired = _exc.PaymentRequired
+"""HTTP 402 - Payment Required.
+Reserved for future use.
+An alias of :py:exc:`keystoneauth1.exceptions.http.PaymentRequired`
+"""
-class PaymentRequired(HTTPClientError):
- """HTTP 402 - Payment Required.
+Forbidden = _exc.Forbidden
+"""HTTP 403 - Forbidden.
- Reserved for future use.
- """
- http_status = 402
- message = _("Payment Required")
+The request was a valid request, but the server is refusing to respond
+to it.
+An alias of :py:exc:`keystoneauth1.exceptions.http.Forbidden`
+"""
+NotFound = _exc.NotFound
+"""HTTP 404 - Not Found.
-class Forbidden(HTTPClientError):
- """HTTP 403 - Forbidden.
+The requested resource could not be found but may be available again
+in the future.
+An alias of :py:exc:`keystoneauth1.exceptions.http.NotFound`
+"""
- The request was a valid request, but the server is refusing to respond
- to it.
- """
- http_status = 403
- message = _("Forbidden")
+MethodNotAllowed = _exc.MethodNotAllowed
+"""HTTP 405 - Method Not Allowed.
+A request was made of a resource using a request method not supported
+by that resource.
+An alias of :py:exc:`keystoneauth1.exceptions.http.MethodNotAllowed`
+"""
-class NotFound(HTTPClientError):
- """HTTP 404 - Not Found.
+NotAcceptable = _exc.NotAcceptable
+"""HTTP 406 - Not Acceptable.
- The requested resource could not be found but may be available again
- in the future.
- """
- http_status = 404
- message = _("Not Found")
+The requested resource is only capable of generating content not
+acceptable according to the Accept headers sent in the request.
+An alias of :py:exc:`keystoneauth1.exceptions.http.NotAcceptable`
+"""
+ProxyAuthenticationRequired = _exc.ProxyAuthenticationRequired
+"""HTTP 407 - Proxy Authentication Required.
-class MethodNotAllowed(HTTPClientError):
- """HTTP 405 - Method Not Allowed.
+The client must first authenticate itself with the proxy.
+An alias of :py:exc:`keystoneauth1.exceptions.http.ProxyAuthenticationRequired`
+"""
- A request was made of a resource using a request method not supported
- by that resource.
- """
- http_status = 405
- message = _("Method Not Allowed")
+RequestTimeout = _exc.RequestTimeout
+"""HTTP 408 - Request Timeout.
+The server timed out waiting for the request.
+An alias of :py:exc:`keystoneauth1.exceptions.http.RequestTimeout`
+"""
-class NotAcceptable(HTTPClientError):
- """HTTP 406 - Not Acceptable.
+Conflict = _exc.Conflict
+"""HTTP 409 - Conflict.
- 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")
+Indicates that the request could not be processed because of conflict
+in the request, such as an edit conflict.
+An alias of :py:exc:`keystoneauth1.exceptions.http.Conflict`
+"""
+Gone = _exc.Gone
+"""HTTP 410 - Gone.
-class ProxyAuthenticationRequired(HTTPClientError):
- """HTTP 407 - Proxy Authentication Required.
+Indicates that the resource requested is no longer available and will
+not be available again.
+An alias of :py:exc:`keystoneauth1.exceptions.http.Gone`
+"""
- The client must first authenticate itself with the proxy.
- """
- http_status = 407
- message = _("Proxy Authentication Required")
+LengthRequired = _exc.LengthRequired
+"""HTTP 411 - Length Required.
+The request did not specify the length of its content, which is
+required by the requested resource.
+An alias of :py:exc:`keystoneauth1.exceptions.http.LengthRequired`
+"""
-class RequestTimeout(HTTPClientError):
- """HTTP 408 - Request Timeout.
+PreconditionFailed = _exc.PreconditionFailed
+"""HTTP 412 - Precondition Failed.
- The server timed out waiting for the request.
- """
- http_status = 408
- message = _("Request Timeout")
+The server does not meet one of the preconditions that the requester
+put on the request.
+An alias of :py:exc:`keystoneauth1.exceptions.http.PreconditionFailed`
+"""
+RequestEntityTooLarge = _exc.RequestEntityTooLarge
+"""HTTP 413 - Request Entity Too Large.
-class Conflict(HTTPClientError):
- """HTTP 409 - Conflict.
+The request is larger than the server is willing or able to process.
+An alias of :py:exc:`keystoneauth1.exceptions.http.RequestEntityTooLarge`
+"""
- Indicates that the request could not be processed because of conflict
- in the request, such as an edit conflict.
- """
- http_status = 409
- message = _("Conflict")
+RequestUriTooLong = _exc.RequestUriTooLong
+"""HTTP 414 - Request-URI Too Long.
+The URI provided was too long for the server to process.
+An alias of :py:exc:`keystoneauth1.exceptions.http.RequestUriTooLong`
+"""
-class Gone(HTTPClientError):
- """HTTP 410 - Gone.
+UnsupportedMediaType = _exc.UnsupportedMediaType
+"""HTTP 415 - Unsupported Media Type.
- Indicates that the resource requested is no longer available and will
- not be available again.
- """
- http_status = 410
- message = _("Gone")
+The request entity has a media type which the server or resource does
+not support.
+An alias of :py:exc:`keystoneauth1.exceptions.http.UnsupportedMediaType`
+"""
+RequestedRangeNotSatisfiable = _exc.RequestedRangeNotSatisfiable
+"""HTTP 416 - Requested Range Not Satisfiable.
-class LengthRequired(HTTPClientError):
- """HTTP 411 - Length Required.
+The client has asked for a portion of the file, but the server cannot
+supply that portion.
+An alias of
+:py:exc:`keystoneauth1.exceptions.http.RequestedRangeNotSatisfiable`
+"""
- The request did not specify the length of its content, which is
- required by the requested resource.
- """
- http_status = 411
- message = _("Length Required")
+ExpectationFailed = _exc.ExpectationFailed
+"""HTTP 417 - Expectation Failed.
+The server cannot meet the requirements of the Expect request-header field.
+An alias of :py:exc:`keystoneauth1.exceptions.http.ExpectationFailed`
+"""
-class PreconditionFailed(HTTPClientError):
- """HTTP 412 - Precondition Failed.
+UnprocessableEntity = _exc.UnprocessableEntity
+"""HTTP 422 - Unprocessable Entity.
- The server does not meet one of the preconditions that the requester
- put on the request.
- """
- http_status = 412
- message = _("Precondition Failed")
+The request was well-formed but was unable to be followed due to semantic
+errors.
+An alias of :py:exc:`keystoneauth1.exceptions.http.UnprocessableEntity`
+"""
+InternalServerError = _exc.InternalServerError
+"""HTTP 500 - Internal Server Error.
-class RequestEntityTooLarge(HTTPClientError):
- """HTTP 413 - Request Entity Too Large.
+A generic error message, given when no more specific message is suitable.
+An alias of :py:exc:`keystoneauth1.exceptions.http.InternalServerError`
+"""
- The request is larger than the server is willing or able to process.
- """
- http_status = 413
- message = _("Request Entity Too Large")
+HttpNotImplemented = _exc.HttpNotImplemented
+"""HTTP 501 - Not Implemented.
- def __init__(self, *args, **kwargs):
- try:
- self.retry_after = int(kwargs.pop('retry_after'))
- except (KeyError, ValueError):
- self.retry_after = 0
+The server either does not recognize the request method, or it lacks
+the ability to fulfill the request.
+An alias of :py:exc:`keystoneauth1.exceptions.http.HttpNotImplemented`
+"""
- super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
+BadGateway = _exc.BadGateway
+"""HTTP 502 - Bad Gateway.
+The server was acting as a gateway or proxy and received an invalid
+response from the upstream server.
+An alias of :py:exc:`keystoneauth1.exceptions.http.BadGateway`
+"""
-class RequestUriTooLong(HTTPClientError):
- """HTTP 414 - Request-URI Too Long.
+ServiceUnavailable = _exc.ServiceUnavailable
+"""HTTP 503 - Service Unavailable.
- The URI provided was too long for the server to process.
- """
- http_status = 414
- message = _("Request-URI Too Long")
+The server is currently unavailable.
+An alias of :py:exc:`keystoneauth1.exceptions.http.ServiceUnavailable`
+"""
+GatewayTimeout = _exc.GatewayTimeout
+"""HTTP 504 - Gateway Timeout.
-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")
+The server was acting as a gateway or proxy and did not receive a timely
+response from the upstream server.
+An alias of :py:exc:`keystoneauth1.exceptions.http.GatewayTimeout`
+"""
+HttpVersionNotSupported = _exc.HttpVersionNotSupported
+"""HTTP 505 - HttpVersion Not Supported.
-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")
+The server does not support the HTTP protocol version used in the request.
+An alias of :py:exc:`keystoneauth1.exceptions.http.HttpVersionNotSupported`
+"""
+from_response = _exc.from_response
+"""Returns an instance of :class:`HttpError` or subclass based on response.
-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")
-
-
-# _code_map contains all the classes that have http_status attribute.
-_code_map = dict(
- (getattr(obj, 'http_status', None), obj)
- for name, obj in six.iteritems(vars(sys.modules[__name__]))
- if inspect.isclass(obj) and getattr(obj, 'http_status', False)
-)
-
-
-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
- """
-
- 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 = {
- "http_status": response.status_code,
- "response": response,
- "method": method,
- "url": url,
- "request_id": req_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 isinstance(body, dict):
- error = body.get(list(body)[0])
- if isinstance(error, dict):
- kwargs["message"] = (error.get("message") or
- error.get("faultstring"))
- kwargs["details"] = (error.get("details") or
- six.text_type(body))
- elif content_type.startswith("text/"):
- kwargs["details"] = getattr(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)
+An alias of :py:func:`keystoneauth1.exceptions.http.from_response`
+"""
# NOTE(akurilin): This alias should be left here to support backwards
# compatibility until we are sure that usage of these exceptions in
# projects is correct.
-ConnectionError = ConnectionRefused
HTTPNotImplemented = HttpNotImplemented
Timeout = RequestTimeout
HTTPError = HttpError
@@ -484,47 +366,40 @@ class CMSError(Exception):
msg = _('Unable to sign or verify data.')
super(CMSError, self).__init__(msg)
+EmptyCatalog = _exc.EmptyCatalog
+"""The service catalog is empty.
-class EmptyCatalog(EndpointNotFound):
- """The service catalog is empty."""
- pass
-
-
-class SSLError(ConnectionRefused):
- """An SSL error occurred."""
+An alias of :py:exc:`keystoneauth1.exceptions.catalog.EmptyCatalog`
+"""
+DiscoveryFailure = _exc.DiscoveryFailure
+"""Discovery of client versions failed.
-class DiscoveryFailure(ClientException):
- """Discovery of client versions failed."""
+An alias of :py:exc:`keystoneauth1.exceptions.discovery.DiscoveryFailure`
+"""
+VersionNotAvailable = _exc.VersionNotAvailable
+"""Discovery failed as the version you requested is not available.
-class VersionNotAvailable(DiscoveryFailure):
- """Discovery failed as the version you requested is not available."""
+An alias of :py:exc:`keystoneauth1.exceptions.discovery.VersionNotAvailable`
+"""
class MethodNotImplemented(ClientException):
"""Method not implemented by the keystoneclient API."""
+MissingAuthPlugin = _exc.MissingAuthPlugin
+"""An authenticated request is required but no plugin available.
-class MissingAuthPlugin(ClientException):
- """An authenticated request is required but no plugin available."""
-
-
-class NoMatchingPlugin(ClientException):
- """There were no auth plugins that could be created from the parameters
- provided.
+An alias of :py:exc:`keystoneauth1.exceptions.auth_plugins.MissingAuthPlugin`
+"""
- :param str name: The name of the plugin that was attempted to load.
-
- .. py:attribute:: name
-
- The name of the plugin that was attempted to load.
- """
+NoMatchingPlugin = _exc.NoMatchingPlugin
+"""There were no auth plugins that could be created from the parameters
+provided.
- def __init__(self, name):
- self.name = name
- msg = _('The plugin %s could not be found') % name
- super(NoMatchingPlugin, self).__init__(msg)
+An alias of :py:exc:`keystoneauth1.exceptions.auth_plugins.NoMatchingPlugin`
+"""
class UnsupportedParameters(ClientException):