summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kurilin <akurilin@mirantis.com>2014-04-16 14:09:00 +0300
committerAndrey Kurilin <akurilin@mirantis.com>2014-04-24 12:01:31 +0300
commit0f6419015c5f03448689ffe7c75ff3bdb5f19c08 (patch)
tree038263a6a097ed273f35f5afd98ac0d069c7aa1a
parent587c4705b88339e3dd2acd7a30a9fdeae737740f (diff)
downloadpython-ironicclient-0f6419015c5f03448689ffe7c75ff3bdb5f19c08.tar.gz
Sync latest code and reuse exceptions from oslo
Module `ironicclient.exc` contains exceptions which equal to exceptions from oslo common code. This patch: - sync latest code of `apiclient.exceptions`(hash of last commit in oslo related to apiclient.exceptions: 3570f44d5ccf52c59cc586bed1446b874fc3c07c) - reuses exceptions from common code - removes needless exceptions from `ironicclient.exc` Related to bp common-client-library-2 Change-Id: I784007f36dd6a63fc4c77e0d0f0f000e05eb792f
-rw-r--r--ironicclient/common/http.py16
-rw-r--r--ironicclient/common/utils.py2
-rw-r--r--ironicclient/exc.py184
-rw-r--r--ironicclient/openstack/common/apiclient/exceptions.py23
-rw-r--r--ironicclient/tests/test_http.py17
-rw-r--r--ironicclient/v1/node.py2
6 files changed, 72 insertions, 172 deletions
diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py
index ecfac51..2ac0ea5 100644
--- a/ironicclient/common/http.py
+++ b/ironicclient/common/http.py
@@ -56,7 +56,7 @@ class HTTPClient(object):
_class = six.moves.http_client.HTTPConnection
else:
msg = 'Unsupported scheme: %s' % parts.scheme
- raise exc.InvalidEndpoint(msg)
+ raise exc.EndpointException(msg)
return (_class, _args, _kwargs)
@@ -66,7 +66,7 @@ class HTTPClient(object):
return _class(*self.connection_params[1][0:2],
**self.connection_params[2])
except six.moves.http_client.InvalidURL:
- raise exc.InvalidEndpoint()
+ raise exc.EndpointException()
def log_curl_request(self, method, url, kwargs):
curl = ['curl -i -X %s' % method]
@@ -143,12 +143,12 @@ class HTTPClient(object):
except socket.gaierror as e:
message = ("Error finding address for %(url)s: %(e)s"
% dict(url=url, e=e))
- raise exc.InvalidEndpoint(message=message)
+ raise exc.EndpointNotFound(message)
except (socket.error, socket.timeout) as e:
endpoint = self.endpoint
message = ("Error communicating with %(endpoint)s %(e)s"
% dict(endpoint=endpoint, e=e))
- raise exc.CommunicationError(message=message)
+ raise exc.ConnectionRefused(message)
body_iter = ResponseBodyIterator(resp)
@@ -164,14 +164,14 @@ class HTTPClient(object):
if 400 <= resp.status < 600:
LOG.warn("Request returned failure status.")
error_json = self._extract_error_json(body_str)
- raise exc.from_response(resp,
- error_json.get('faultstring'),
- error_json.get('debuginfo'))
+ raise exc.from_response(
+ resp, error_json.get('faultstring'),
+ error_json.get('debuginfo'), method, url)
elif resp.status in (301, 302, 305):
# Redirected. Reissue the request to the new location.
return self._http_request(resp['location'], method, **kwargs)
elif resp.status == 300:
- raise exc.from_response(resp)
+ raise exc.from_response(resp, method=method, url=url)
return resp, body_iter
diff --git a/ironicclient/common/utils.py b/ironicclient/common/utils.py
index 1bca1de..fc2daff 100644
--- a/ironicclient/common/utils.py
+++ b/ironicclient/common/utils.py
@@ -179,7 +179,7 @@ def args_array_to_dict(kwargs, key_to_convert):
except ValueError:
raise exc.CommandError(
_('%(key)s must be a list of KEY=VALUE not "%(values)s"') %
- {'key': key_to_convert, 'values': values_to_convert})
+ {'key': key_to_convert, 'values': values_to_convert})
return kwargs
diff --git a/ironicclient/exc.py b/ironicclient/exc.py
index aa2d840..4c5cfd1 100644
--- a/ironicclient/exc.py
+++ b/ironicclient/exc.py
@@ -10,169 +10,49 @@
# License for the specific language governing permissions and limitations
# under the License.
-import sys
+from ironicclient.openstack.common.apiclient import exceptions
+from ironicclient.openstack.common.apiclient.exceptions import * # noqa
-class BaseException(Exception):
- """An error occurred."""
- def __init__(self, message=None):
- self.message = message
+# NOTE(akurilin): This alias is left here since v.0.1.3 to support backwards
+# compatibility.
+InvalidEndpoint = EndpointException
+CommunicationError = ConnectionRefused
+HTTPBadRequest = BadRequest
+HTTPInternalServerError = InternalServerError
+HTTPNotFound = NotFound
+HTTPServiceUnavailable = ServiceUnavailable
- def __str__(self):
- return self.message or self.__class__.__doc__
-
-class AmbigiousAuthSystem(BaseException):
+class AmbigiousAuthSystem(ClientException):
"""Could not obtain token and endpoint using provided credentials."""
-
-
-class CommandError(BaseException):
- """Invalid usage of CLI."""
-
-
-class InvalidEndpoint(BaseException):
- """The provided endpoint is invalid."""
-
-
-class CommunicationError(BaseException):
- """Unable to communicate with server."""
-
-
-class ClientException(Exception):
- """DEPRECATED."""
-
-
-class HTTPException(ClientException):
- """Base exception for all HTTP-derived exceptions."""
- code = 'N/A'
-
- def __init__(self, details=None, server_traceback=None):
- self.details = details
- self.server_traceback = server_traceback
-
- def __str__(self):
- msg = "%s (HTTP %s)" % (self.__class__.__name__,
- self.code)
- if self.details:
- msg = self.details
- if self.server_traceback:
- msg += "\n%s" % self.server_traceback
- return msg
-
-
-class HTTPMultipleChoices(HTTPException):
- code = 300
-
- def __str__(self):
- self.details = ("Requested version of OpenStack Images API is not"
- "available.")
- return "%s (HTTP %s) %s" % (self.__class__.__name__, self.code,
- self.details)
-
-
-class BadRequest(HTTPException):
- """DEPRECATED."""
- code = 400
-
-
-class HTTPBadRequest(BadRequest):
- pass
-
-
-class Unauthorized(HTTPException):
- """DEPRECATED."""
- code = 401
-
-
-class HTTPUnauthorized(Unauthorized):
pass
-class Forbidden(HTTPException):
- """DEPRECATED."""
- code = 403
-
-
-class HTTPForbidden(Forbidden):
- pass
-
-
-class NotFound(HTTPException):
- """DEPRECATED."""
- code = 404
-
-
-class HTTPNotFound(NotFound):
- pass
-
-
-class HTTPMethodNotAllowed(HTTPException):
- code = 405
-
-
-class Conflict(HTTPException):
- """DEPRECATED."""
- code = 409
-
-
-class HTTPConflict(Conflict):
- pass
-
-
-class OverLimit(HTTPException):
- """DEPRECATED."""
- code = 413
-
-
-class HTTPOverLimit(OverLimit):
- pass
-
-
-class HTTPInternalServerError(HTTPException):
- code = 500
-
-
-class HTTPNotImplemented(HTTPException):
- code = 501
-
-
-class HTTPBadGateway(HTTPException):
- code = 502
-
-
-class ServiceUnavailable(HTTPException):
- """DEPRECATED."""
- code = 503
-
-
-class HTTPServiceUnavailable(ServiceUnavailable):
+class InvalidAttribute(ClientException):
pass
-#NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception
-# classes
-_code_map = {}
-for obj_name in dir(sys.modules[__name__]):
- if obj_name.startswith('HTTP'):
- obj = getattr(sys.modules[__name__], obj_name)
- _code_map[obj.code] = obj
-
+def from_response(response, message=None, traceback=None, method=None,
+ url=None):
+ """Return an instance of an HttpError based on response from
+ httplib/requests.
+ """
-def from_response(response, message=None, traceback=None):
- """Return an instance of an HTTPException based on httplib response."""
- cls = _code_map.get(response.status, HTTPException)
- return cls(message, traceback)
+ error_body = {}
+ if message:
+ error_body['message'] = message
+ if traceback:
+ error_body['details'] = traceback
+ if hasattr(response, 'status') and not hasattr(response, 'status_code'):
+ # NOTE(akurilin): These modifications around response object give
+ # ability to get all necessary information in method `from_response`
+ # from common code, which expecting response object from `requests`
+ # library instead of object from `httplib/httplib2` library.
+ response.status_code = response.status
+ response.headers = {
+ 'Content-Type': response.getheader('content-type', "")}
+ response.json = lambda: {'error': error_body}
-class NoTokenLookupException(Exception):
- """DEPRECATED."""
- pass
-
-
-class EndpointNotFound(Exception):
- """DEPRECATED."""
- pass
-
-
-class InvalidAttribute(ClientException):
- pass
+ return exceptions.from_response(response, message, url)
diff --git a/ironicclient/openstack/common/apiclient/exceptions.py b/ironicclient/openstack/common/apiclient/exceptions.py
index 4776d58..ada1344 100644
--- a/ironicclient/openstack/common/apiclient/exceptions.py
+++ b/ironicclient/openstack/common/apiclient/exceptions.py
@@ -127,6 +127,11 @@ class HttpError(ClientException):
super(HttpError, self).__init__(formatted_string)
+class HTTPRedirection(HttpError):
+ """HTTP Redirection."""
+ message = "HTTP Redirection"
+
+
class HTTPClientError(HttpError):
"""Client-side HTTP error.
@@ -144,6 +149,16 @@ class HttpServerError(HttpError):
message = "HTTP Server Error"
+class MultipleChoices(HTTPRedirection):
+ """HTTP 300 - Multiple Choices.
+
+ Indicates multiple options for the resource that the client may follow.
+ """
+
+ http_status = 300
+ message = "Multiple Choices"
+
+
class BadRequest(HTTPClientError):
"""HTTP 400 - Bad Request.
@@ -425,10 +440,10 @@ def from_response(response, method, url):
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)
+ if isinstance(body, dict):
+ error = list(body.values())[0]
+ kwargs["message"] = error.get("message")
+ kwargs["details"] = error.get("details")
elif content_type.startswith("text/"):
kwargs["details"] = response.text
diff --git a/ironicclient/tests/test_http.py b/ironicclient/tests/test_http.py
index 94847a6..d7e82d5 100644
--- a/ironicclient/tests/test_http.py
+++ b/ironicclient/tests/test_http.py
@@ -64,10 +64,10 @@ class HttpClientTest(utils.BaseTestCase):
client.get_connection = \
lambda *a, **kw: utils.FakeConnection(fake_resp)
- error = self.assertRaises(exc.HTTPInternalServerError,
+ error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
- self.assertEqual('HTTPInternalServerError (HTTP 500)', str(error))
+ self.assertEqual('Internal Server Error (HTTP 500)', str(error))
def test_server_exception_msg_only(self):
error_msg = 'test error msg'
@@ -80,10 +80,10 @@ class HttpClientTest(utils.BaseTestCase):
client.get_connection = \
lambda *a, **kw: utils.FakeConnection(fake_resp)
- error = self.assertRaises(exc.HTTPInternalServerError,
+ error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
- self.assertEqual(error_msg, str(error))
+ self.assertEqual(error_msg + ' (HTTP 500)', str(error))
def test_server_exception_msg_and_traceback(self):
error_msg = 'another test error'
@@ -98,7 +98,12 @@ class HttpClientTest(utils.BaseTestCase):
client.get_connection = \
lambda *a, **kw: utils.FakeConnection(fake_resp)
- error = self.assertRaises(exc.HTTPInternalServerError,
+ error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
- self.assertEqual(error_msg + "\n" + error_trace, str(error))
+
+ self.assertEqual(
+ '%(error)s (HTTP 500)\n%(trace)s' % {'error': error_msg,
+ 'trace': error_trace},
+ "%(error)s\n%(details)s" % {'error': str(error),
+ 'details': str(error.details)})
diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py
index 2570aa6..ede506f 100644
--- a/ironicclient/v1/node.py
+++ b/ironicclient/v1/node.py
@@ -66,7 +66,7 @@ class NodeManager(base.Manager):
uuid = getattr(nodes[0], 'uuid')
return self.get(uuid)
else:
- raise exc.HTTPNotFound()
+ raise exc.NotFound()
def create(self, **kwargs):
new = {}