diff --git a/glanceclient/exc.py b/glanceclient/exc.py index 3eeaffa1..95eb575f 100644 --- a/glanceclient/exc.py +++ b/glanceclient/exc.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import re import sys @@ -141,7 +142,7 @@ class HTTPServiceUnavailable(ServiceUnavailable): pass -#NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception +# NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception # classes _code_map = {} for obj_name in dir(sys.modules[__name__]): @@ -153,7 +154,29 @@ for obj_name in dir(sys.modules[__name__]): def from_response(response, body=None): """Return an instance of an HTTPException based on httplib response.""" cls = _code_map.get(response.status_code, HTTPException) - if body: + if body and 'json' in response.headers['content-type']: + # Iterate over the nested objects and retreive the "message" attribute. + messages = [obj.get('message') for obj in response.json().values()] + # Join all of the messages together nicely and filter out any objects + # that don't have a "message" attr. + details = '\n'.join(i for i in messages if i is not None) + return cls(details=details) + elif body and 'html' in response.headers['content-type']: + # Split the lines, strip whitespace and inline HTML from the response. + details = [re.sub(r'<.+?>', '', i.strip()) + for i in response.text.splitlines()] + details = [i for i in details if i] + # Remove duplicates from the list. + details_seen = set() + details_temp = [] + for i in details: + if i not in details_seen: + details_temp.append(i) + details_seen.add(i) + # Return joined string separated by colons. + details = ': '.join(details_temp) + return cls(details=details) + elif body: details = body.replace('\n\n', '\n') return cls(details=details) diff --git a/glanceclient/shell.py b/glanceclient/shell.py index 4eb174eb..4b5b73d2 100644 --- a/glanceclient/shell.py +++ b/glanceclient/shell.py @@ -477,14 +477,16 @@ class OpenStackImagesShell(object): "or prompted response")) # Validate password flow auth - project_info = (args.os_tenant_name or - args.os_tenant_id or - (args.os_project_name and - (args.os_project_domain_name or - args.os_project_domain_id)) or - args.os_project_id) + project_info = ( + args.os_tenant_name or args.os_tenant_id or ( + args.os_project_name and ( + args.os_project_domain_name or + args.os_project_domain_id + ) + ) or args.os_project_id + ) - if (not project_info): + if not project_info: # tenant is deprecated in Keystone v3. Use the latest # terminology instead. raise exc.CommandError( @@ -571,14 +573,14 @@ class OpenStackImagesShell(object): with open(schema_file_path, 'w') as f: f.write(json.dumps(schema.raw())) except Exception: - #NOTE(esheffield) do nothing here, we'll get a message - #later if the schema is missing + # NOTE(esheffield) do nothing here, we'll get a message + # later if the schema is missing pass def main(self, argv): # Parse args once to find version - #NOTE(flepied) Under Python3, parsed arguments are removed + # NOTE(flepied) Under Python3, parsed arguments are removed # from the list so make a copy for the first parsing base_argv = copy.deepcopy(argv) parser = self.get_base_parser() @@ -642,8 +644,8 @@ class OpenStackImagesShell(object): except exc.Unauthorized: raise exc.CommandError("Invalid OpenStack Identity credentials.") except Exception: - #NOTE(kragniz) Print any exceptions raised to stderr if the --debug - # flag is set + # NOTE(kragniz) Print any exceptions raised to stderr if the + # --debug flag is set if args.debug: traceback.print_exc() raise diff --git a/tests/test_exc.py b/tests/test_exc.py index c8ad2dfc..575c62b5 100644 --- a/tests/test_exc.py +++ b/tests/test_exc.py @@ -17,6 +17,17 @@ import testtools from glanceclient import exc +HTML_MSG = """ +
+