Handle response is not a json format
Change-Id: I62a6c6d248301576176be5631a4ef4900460082d
(cherry picked from commit d915f2fecb
)
This commit is contained in:
parent
d52971a3af
commit
6c112f1dba
|
@ -90,6 +90,16 @@ class MockRequestsResponse(object):
|
||||||
def json(self):
|
def json(self):
|
||||||
return jsonutils.loads(self.content)
|
return jsonutils.loads(self.content)
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
"""Returns True if :attr:`status_code` is less than 400.
|
||||||
|
|
||||||
|
This attribute checks if the status code of the response is between
|
||||||
|
400 and 600 to see if there was a client error or a server error. If
|
||||||
|
the status code, is between 200 and 400, this will return True. This
|
||||||
|
is **not** a check to see if the response code is ``200 OK``.
|
||||||
|
"""
|
||||||
|
return self.status_code < 400
|
||||||
|
|
||||||
|
|
||||||
class MockRequestSessionApi(object):
|
class MockRequestSessionApi(object):
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,7 @@ class NsxClientTestCase(NsxLibTestCase):
|
||||||
super(NsxClientTestCase.MockHTTPProvider, self).__init__()
|
super(NsxClientTestCase.MockHTTPProvider, self).__init__()
|
||||||
if isinstance(session_response, list):
|
if isinstance(session_response, list):
|
||||||
self._session_responses = session_response
|
self._session_responses = session_response
|
||||||
elif session_response:
|
elif session_response is not None:
|
||||||
self._session_responses = [session_response]
|
self._session_responses = [session_response]
|
||||||
else:
|
else:
|
||||||
self._session_responses = None
|
self._session_responses = None
|
||||||
|
|
|
@ -259,7 +259,8 @@ class NsxV3RESTClientTestCase(nsxlib_testcase.NsxClientTestCase):
|
||||||
'error_message': 'bad',
|
'error_message': 'bad',
|
||||||
'related_errors': [{
|
'related_errors': [{
|
||||||
'error_message': 'bla',
|
'error_message': 'bla',
|
||||||
'error_code': 'code'}]})
|
'error_code': 'code',
|
||||||
|
'httpStatus': 'BAD_REQUEST'}]})
|
||||||
response = mocks.MockRequestsResponse(
|
response = mocks.MockRequestsResponse(
|
||||||
status_code, content)
|
status_code, content)
|
||||||
|
|
||||||
|
@ -325,6 +326,10 @@ class NsxV3RESTClientTestCase(nsxlib_testcase.NsxClientTestCase):
|
||||||
500157, [777, 500045])
|
500157, [777, 500045])
|
||||||
self.assertEqual(exc, nsxlib_exc.NsxPendingDelete)
|
self.assertEqual(exc, nsxlib_exc.NsxPendingDelete)
|
||||||
|
|
||||||
|
code = requests.codes.SERVICE_UNAVAILABLE
|
||||||
|
exc = client.http_error_to_exception(code, None)
|
||||||
|
self.assertEqual(exc, nsxlib_exc.ServiceUnavailable)
|
||||||
|
|
||||||
|
|
||||||
class NsxV3JSONClientTestCase(nsxlib_testcase.NsxClientTestCase):
|
class NsxV3JSONClientTestCase(nsxlib_testcase.NsxClientTestCase):
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from requests import codes
|
||||||
from requests import exceptions as requests_exceptions
|
from requests import exceptions as requests_exceptions
|
||||||
from requests import models
|
from requests import models
|
||||||
import six.moves.urllib.parse as urlparse
|
import six.moves.urllib.parse as urlparse
|
||||||
|
@ -288,6 +289,24 @@ class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase):
|
||||||
self.assertRaises(nsxlib_exc.StaleRevision,
|
self.assertRaises(nsxlib_exc.StaleRevision,
|
||||||
api.get, 'api/v1/transport-zones')
|
api.get, 'api/v1/transport-zones')
|
||||||
|
|
||||||
|
def test_max_retry_attempts_on_none_json_error(self):
|
||||||
|
# handle response not json format
|
||||||
|
def server1_error():
|
||||||
|
return mocks.MockRequestsResponse(
|
||||||
|
codes.SERVICE_UNAVAILABLE,
|
||||||
|
"python-requests/2.27.1 d50561a7-7540-4342-88e3-c235e587a19")
|
||||||
|
|
||||||
|
conf_managers = ['8.9.10.11', '9.10.11.12', '10.11.12.13']
|
||||||
|
max_attempts = 2
|
||||||
|
api = self.mock_nsx_clustered_api(
|
||||||
|
nsx_api_managers=conf_managers,
|
||||||
|
max_attempts=max_attempts,
|
||||||
|
session_response=[server1_error for i in range(0, max_attempts)])
|
||||||
|
|
||||||
|
self.assertRaises(nsxlib_exc.ServiceUnavailable,
|
||||||
|
api.get, 'api/v1/transport-zones')
|
||||||
|
self.assertEqual(cluster.ClusterHealth.GREEN, api.health)
|
||||||
|
|
||||||
def test_cluster_proxy_connection_establish_error(self):
|
def test_cluster_proxy_connection_establish_error(self):
|
||||||
|
|
||||||
def connect_timeout():
|
def connect_timeout():
|
||||||
|
|
|
@ -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 json
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -29,6 +30,63 @@ LOG = log.getLogger(__name__)
|
||||||
NULL_CURSOR_PREFIX = '0000'
|
NULL_CURSOR_PREFIX = '0000'
|
||||||
|
|
||||||
|
|
||||||
|
def get_http_error_details(response):
|
||||||
|
try:
|
||||||
|
msg = response.json() if response.content else ''
|
||||||
|
except json.decoder.JSONDecodeError as e:
|
||||||
|
LOG.debug("decode response %s error %s", response.content, e)
|
||||||
|
# error_code can't be None else it can't be casted to an exception
|
||||||
|
return {'status_code': response.status_code,
|
||||||
|
'error_code': response.status_code,
|
||||||
|
'related_error_codes': [],
|
||||||
|
'related_status_codes': [],
|
||||||
|
'details': response.content}
|
||||||
|
|
||||||
|
error_code = None
|
||||||
|
related_error_codes = []
|
||||||
|
related_status_codes = []
|
||||||
|
|
||||||
|
if isinstance(msg, dict) and 'error_message' in msg:
|
||||||
|
error_code = msg.get('error_code')
|
||||||
|
related_errors = [error['error_message'] for error in
|
||||||
|
msg.get('related_errors', [])]
|
||||||
|
related_error_codes = [str(error['error_code']) for error in
|
||||||
|
msg.get('related_errors', []) if
|
||||||
|
error.get('error_code')]
|
||||||
|
related_status_codes = [getattr(requests.codes, error['httpStatus'])
|
||||||
|
for error in msg.get('related_errors', []) if
|
||||||
|
error.get('httpStatus')]
|
||||||
|
|
||||||
|
details = msg.get('details')
|
||||||
|
msg = msg['error_message']
|
||||||
|
if details:
|
||||||
|
msg += " details: %s" % details
|
||||||
|
if related_errors:
|
||||||
|
msg += " relatedErrors: %s" % ' '.join(related_errors)
|
||||||
|
|
||||||
|
return {'status_code': response.status_code,
|
||||||
|
'error_code': error_code,
|
||||||
|
'related_error_codes': related_error_codes,
|
||||||
|
'related_status_codes': related_status_codes,
|
||||||
|
'details': msg}
|
||||||
|
|
||||||
|
|
||||||
|
def init_http_exception_from_response(response):
|
||||||
|
if response is None or response:
|
||||||
|
# The response object has a __bool__ method that return True for
|
||||||
|
# status code under 400. In that case there is no need for exception
|
||||||
|
return None
|
||||||
|
error_details = get_http_error_details(response)
|
||||||
|
if not error_details['error_code']:
|
||||||
|
return None
|
||||||
|
|
||||||
|
error = http_error_to_exception(error_details['status_code'],
|
||||||
|
error_details['error_code'],
|
||||||
|
error_details['related_error_codes'])
|
||||||
|
|
||||||
|
return error(manager='', **error_details)
|
||||||
|
|
||||||
|
|
||||||
def http_error_to_exception(status_code, error_code, related_error_codes=None):
|
def http_error_to_exception(status_code, error_code, related_error_codes=None):
|
||||||
errors = {
|
errors = {
|
||||||
requests.codes.NOT_FOUND:
|
requests.codes.NOT_FOUND:
|
||||||
|
|
|
@ -656,7 +656,10 @@ class ClusteredAPI(object):
|
||||||
# http request/response over the wire
|
# http request/response over the wire
|
||||||
response = do_request(url, *args, **kwargs)
|
response = do_request(url, *args, **kwargs)
|
||||||
endpoint.set_state(EndpointState.UP)
|
endpoint.set_state(EndpointState.UP)
|
||||||
|
exc = nsx_client.init_http_exception_from_response(
|
||||||
|
response)
|
||||||
|
if exc:
|
||||||
|
raise exc
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.warning("Request failed due to: %s", e)
|
LOG.warning("Request failed due to: %s", e)
|
||||||
|
|
Loading…
Reference in New Issue