Merge "Strip json and html from error messages"
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +154,29 @@ for obj_name in dir(sys.modules[__name__]):
|
|||||||
def from_response(response, body=None):
|
def from_response(response, body=None):
|
||||||
"""Return an instance of an HTTPException based on httplib response."""
|
"""Return an instance of an HTTPException based on httplib response."""
|
||||||
cls = _code_map.get(response.status_code, HTTPException)
|
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')
|
details = body.replace('\n\n', '\n')
|
||||||
return cls(details=details)
|
return cls(details=details)
|
||||||
|
|
||||||
|
@@ -477,14 +477,16 @@ class OpenStackImagesShell(object):
|
|||||||
"or prompted response"))
|
"or prompted response"))
|
||||||
|
|
||||||
# Validate password flow auth
|
# Validate password flow auth
|
||||||
project_info = (args.os_tenant_name or
|
project_info = (
|
||||||
args.os_tenant_id or
|
args.os_tenant_name or args.os_tenant_id or (
|
||||||
(args.os_project_name and
|
args.os_project_name and (
|
||||||
(args.os_project_domain_name or
|
args.os_project_domain_name or
|
||||||
args.os_project_domain_id)) or
|
args.os_project_domain_id
|
||||||
args.os_project_id)
|
)
|
||||||
|
) or args.os_project_id
|
||||||
|
)
|
||||||
|
|
||||||
if (not project_info):
|
if not project_info:
|
||||||
# tenant is deprecated in Keystone v3. Use the latest
|
# tenant is deprecated in Keystone v3. Use the latest
|
||||||
# terminology instead.
|
# terminology instead.
|
||||||
raise exc.CommandError(
|
raise exc.CommandError(
|
||||||
@@ -642,8 +644,8 @@ class OpenStackImagesShell(object):
|
|||||||
except exc.Unauthorized:
|
except exc.Unauthorized:
|
||||||
raise exc.CommandError("Invalid OpenStack Identity credentials.")
|
raise exc.CommandError("Invalid OpenStack Identity credentials.")
|
||||||
except Exception:
|
except Exception:
|
||||||
#NOTE(kragniz) Print any exceptions raised to stderr if the --debug
|
# NOTE(kragniz) Print any exceptions raised to stderr if the
|
||||||
# flag is set
|
# --debug flag is set
|
||||||
if args.debug:
|
if args.debug:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
raise
|
raise
|
||||||
|
@@ -17,6 +17,17 @@ import testtools
|
|||||||
|
|
||||||
from glanceclient import exc
|
from glanceclient import exc
|
||||||
|
|
||||||
|
HTML_MSG = """<html>
|
||||||
|
<head>
|
||||||
|
<title>404 Entity Not Found</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>404 Entity Not Found</h1>
|
||||||
|
Entity could not be found
|
||||||
|
<br /><br />
|
||||||
|
</body>
|
||||||
|
</html>"""
|
||||||
|
|
||||||
|
|
||||||
class TestHTTPExceptions(testtools.TestCase):
|
class TestHTTPExceptions(testtools.TestCase):
|
||||||
def test_from_response(self):
|
def test_from_response(self):
|
||||||
@@ -25,3 +36,35 @@ class TestHTTPExceptions(testtools.TestCase):
|
|||||||
mock_resp.status_code = 400
|
mock_resp.status_code = 400
|
||||||
out = exc.from_response(mock_resp)
|
out = exc.from_response(mock_resp)
|
||||||
self.assertIsInstance(out, exc.HTTPBadRequest)
|
self.assertIsInstance(out, exc.HTTPBadRequest)
|
||||||
|
|
||||||
|
def test_handles_json(self):
|
||||||
|
"""exc.from_response should not print JSON."""
|
||||||
|
mock_resp = mock.Mock()
|
||||||
|
mock_resp.status_code = 413
|
||||||
|
mock_resp.json.return_value = {
|
||||||
|
"overLimit": {
|
||||||
|
"code": 413,
|
||||||
|
"message": "OverLimit Retry...",
|
||||||
|
"details": "Error Details...",
|
||||||
|
"retryAt": "2014-12-03T13:33:06Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mock_resp.headers = {
|
||||||
|
"content-type": "application/json"
|
||||||
|
}
|
||||||
|
err = exc.from_response(mock_resp, "Non-empty body")
|
||||||
|
self.assertIsInstance(err, exc.HTTPOverLimit)
|
||||||
|
self.assertEqual("OverLimit Retry...", err.details)
|
||||||
|
|
||||||
|
def test_handles_html(self):
|
||||||
|
"""exc.from_response should not print HTML."""
|
||||||
|
mock_resp = mock.Mock()
|
||||||
|
mock_resp.status_code = 404
|
||||||
|
mock_resp.text = HTML_MSG
|
||||||
|
mock_resp.headers = {
|
||||||
|
"content-type": "text/html"
|
||||||
|
}
|
||||||
|
err = exc.from_response(mock_resp, HTML_MSG)
|
||||||
|
self.assertIsInstance(err, exc.HTTPNotFound)
|
||||||
|
self.assertEqual("404 Entity Not Found: Entity could not be found",
|
||||||
|
err.details)
|
||||||
|
Reference in New Issue
Block a user