Improve error feedback
When an error occur instead of just return the HTTP response code the client will now try to extract the error message that contains the reason of the problem and show it to the user in a user-friendly way (no codes at all), the intention of this patch is to improve the usability of the ironic client. Things like HTTP response codes can still be viewed when used with the debug mode enabled ( -d ). Change-Id: Ieca021cc0e0eabe91c13335c3062ef9622da3004
This commit is contained in:
parent
6752ae8307
commit
489daf6710
@ -124,6 +124,16 @@ class HTTPClient(object):
|
||||
base_url = _args[2]
|
||||
return '%s/%s' % (base_url.rstrip('/'), url.lstrip('/'))
|
||||
|
||||
def _extract_error_message(self, body):
|
||||
try:
|
||||
body_json = json.loads(body)
|
||||
if 'error_message' in body_json:
|
||||
body_json = json.loads(body_json['error_message'])
|
||||
if 'faultstring' in body_json:
|
||||
return body_json['faultstring']
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def _http_request(self, url, method, **kwargs):
|
||||
"""Send an http request with the specified characteristics.
|
||||
|
||||
@ -156,6 +166,7 @@ class HTTPClient(object):
|
||||
body_iter = ResponseBodyIterator(resp)
|
||||
|
||||
# Read body into string if it isn't obviously image data
|
||||
body_str = None
|
||||
if resp.getheader('content-type', None) != 'application/octet-stream':
|
||||
body_str = ''.join([chunk for chunk in body_iter])
|
||||
self.log_http_response(resp, body_str)
|
||||
@ -165,7 +176,8 @@ class HTTPClient(object):
|
||||
|
||||
if 400 <= resp.status < 600:
|
||||
LOG.warn("Request returned failure status.")
|
||||
raise exc.from_response(resp)
|
||||
err_msg = self._extract_error_message(body_str)
|
||||
raise exc.from_response(resp, err_msg)
|
||||
elif resp.status in (301, 302, 305):
|
||||
# Redirected. Reissue the request to the new location.
|
||||
return self._http_request(resp['location'], method, **kwargs)
|
||||
|
@ -46,7 +46,8 @@ class HTTPException(ClientException):
|
||||
self.details = details
|
||||
|
||||
def __str__(self):
|
||||
return "%s (HTTP %s)" % (self.__class__.__name__, self.code)
|
||||
return self.details or "%s (HTTP %s)" % (self.__class__.__name__,
|
||||
self.code)
|
||||
|
||||
|
||||
class HTTPMultipleChoices(HTTPException):
|
||||
@ -147,10 +148,10 @@ for obj_name in dir(sys.modules[__name__]):
|
||||
_code_map[obj.code] = obj
|
||||
|
||||
|
||||
def from_response(response):
|
||||
def from_response(response, error=None):
|
||||
"""Return an instance of an HTTPException based on httplib response."""
|
||||
cls = _code_map.get(response.status, HTTPException)
|
||||
return cls()
|
||||
return cls(error)
|
||||
|
||||
|
||||
class NoTokenLookupException(Exception):
|
||||
|
@ -184,6 +184,10 @@ class IronicShell(object):
|
||||
level=logging.DEBUG)
|
||||
|
||||
httplib2.debuglevel = 1
|
||||
else:
|
||||
logging.basicConfig(
|
||||
format="%(levelname)s %(message)s",
|
||||
level=logging.CRITICAL)
|
||||
|
||||
def main(self, argv):
|
||||
# Parse args once to find version
|
||||
|
Loading…
x
Reference in New Issue
Block a user