From 87f0fb56b3977cc08693902a660420bdafcb5114 Mon Sep 17 00:00:00 2001 From: Eva Balycheva Date: Tue, 16 Feb 2016 23:51:10 +0300 Subject: [PATCH] Make TransportErrors more descriptive Problems: 1. In some cases no information is provided for the CLI user when these exceptions are raised: https://github.com/openstack/python-zaqarclient/blob/master/zaqarclient/ transport/http.py#L30. For example, try "openstack pool show unexisting_pool". You will see just blank line. It is because the server returns no message in the 404 response body. And the user sees the blank line. 2. Most of the error responses from Zaqar have bodies in title-description format. TransportErrors can only show descriptions from these responses. It's better to include also titles in the client's exception messages. 3. Some of the error responses from Zaqar are not in title-description format, but still have some info in their bodies. It's better to include this info to the client's exception message. Solution: This patch makes all exceptions in zaqarclient/transport/errors.py show at least error response code. The patch TransportErrors properly gather the info from Zaqar's error response bodies and show it. Partial-Bug: 1542804 Change-Id: Ie2cc3081a5dd7c4f21c29bdf78a9bad76b515121 --- zaqarclient/transport/errors.py | 28 +++++++++++++++++++++++++++- zaqarclient/transport/http.py | 12 +++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/zaqarclient/transport/errors.py b/zaqarclient/transport/errors.py index ed8bcd40..163ca165 100644 --- a/zaqarclient/transport/errors.py +++ b/zaqarclient/transport/errors.py @@ -24,12 +24,24 @@ from zaqarclient import errors __all__ = ['TransportError', 'ResourceNotFound', 'MalformedRequest', 'UnauthorizedError', 'ForbiddenError', 'ServiceUnavailableError', - 'InternalServerError'] + 'InternalServerError', 'ConflictError'] class TransportError(errors.ZaqarError): """Base class for all transport errors.""" + code = None + + def __init__(self, title=None, description=None, text=None): + msg = 'Error response from Zaqar. Code: {0}.'.format(self.code) + if title: + msg += ' Title: {0}.'.format(title) + if description: + msg += ' Description: {0}.'.format(description) + if text: + msg += ' Text: {0}.'.format(text) + super(TransportError, self).__init__(msg) + class ResourceNotFound(TransportError): """Indicates that a resource is missing @@ -37,6 +49,8 @@ class ResourceNotFound(TransportError): This error maps to HTTP's 404 """ + code = 404 + class MalformedRequest(TransportError): """Indicates that a request is malformed @@ -44,6 +58,8 @@ class MalformedRequest(TransportError): This error maps to HTTP's 400 """ + code = 400 + class UnauthorizedError(TransportError): """Indicates that a request was not authenticated @@ -51,6 +67,8 @@ class UnauthorizedError(TransportError): This error maps to HTTP's 401 """ + code = 401 + class ForbiddenError(TransportError): """Indicates that a request is forbidden to access the particular resource @@ -58,6 +76,8 @@ class ForbiddenError(TransportError): This error maps to HTTP's 403 """ + code = 403 + class InternalServerError(TransportError): """Indicates that the server encountered an unexpected situation @@ -65,6 +85,8 @@ class InternalServerError(TransportError): This error maps to HTTP's 500 """ + code = 500 + class ServiceUnavailableError(TransportError): """Indicates that the server was unable to service the request @@ -72,9 +94,13 @@ class ServiceUnavailableError(TransportError): This error maps to HTTP's 503 """ + code = 503 + class ConflictError(TransportError): """Indicates that the server was unable to service the request This error maps to HTTP's 409 """ + + code = 409 diff --git a/zaqarclient/transport/http.py b/zaqarclient/transport/http.py index f09f7cba..07a49b70 100644 --- a/zaqarclient/transport/http.py +++ b/zaqarclient/transport/http.py @@ -96,14 +96,20 @@ class HttpTransport(base.Transport): data=request.content) if resp.status_code in self.http_to_zaqar: + kwargs = {} try: - msg = json.loads(resp.text)['description'] + error_body = json.loads(resp.text) + kwargs['title'] = error_body['title'] + kwargs['description'] = error_body['description'] except Exception: # TODO(flaper87): Log this exception # but don't stop raising the corresponding # exception - msg = '' - raise self.http_to_zaqar[resp.status_code](msg) + # Note(Eva-i): most of the error responses from Zaqar have + # dict with title and description in their bodies. If it's not + # the case, let's just show body text. + kwargs['text'] = resp.text + raise self.http_to_zaqar[resp.status_code](**kwargs) # NOTE(flaper87): This reads the whole content # and will consume any attempt of streaming.