diff --git a/neutronclient/client.py b/neutronclient/client.py index 3a153b018..50ef6b413 100644 --- a/neutronclient/client.py +++ b/neutronclient/client.py @@ -161,8 +161,6 @@ class HTTPClient(httplib2.Http): status_code = self.get_status_code(resp) if status_code == 401: raise exceptions.Unauthorized(message=body) - elif status_code == 403: - raise exceptions.Forbidden(message=body) return resp, body def _strip_credentials(self, kwargs): diff --git a/neutronclient/tests/unit/test_cli20.py b/neutronclient/tests/unit/test_cli20.py index ee5d845e5..b804dc868 100644 --- a/neutronclient/tests/unit/test_cli20.py +++ b/neutronclient/tests/unit/test_cli20.py @@ -528,13 +528,84 @@ class ClientV2UnicodeTestXML(ClientV2UnicodeTestJson): class CLITestV20ExceptionHandler(CLITestV20Base): + def _test_exception_handler_v20( + self, expected_exception, status_code, expected_msg, + error_type=None, error_msg=None, error_detail=None, + error_content=None): + if error_content is None: + error_content = {'NeutronError': {'type': error_type, + 'message': error_msg, + 'detail': error_detail}} + + e = self.assertRaises(expected_exception, + client.exception_handler_v20, + status_code, error_content) + self.assertEqual(status_code, e.status_code) + + if expected_msg is None: + if error_detail: + expected_msg = '\n'.join([error_msg, error_detail]) + else: + expected_msg = error_msg + self.assertEqual(expected_msg, e.message) + def test_exception_handler_v20_ip_address_in_use(self): - # Tests that an IpAddressInUse exception from the server is - # translated to an IpAddressInUseClient exception in the client. err_msg = ('Unable to complete operation for network ' 'fake-network-uuid. The IP address fake-ip is in use.') - err_data = {'type': 'IpAddressInUse', 'message': err_msg, 'detail': ''} - error_content = {'NeutronError': err_data} - self.assertRaises(exceptions.IpAddressInUseClient, - client.exception_handler_v20, - 409, error_content) + self._test_exception_handler_v20( + exceptions.IpAddressInUseClient, 409, err_msg, + 'IpAddressInUse', err_msg, '') + + def test_exception_handler_v20_neutron_known_error(self): + error_msg = 'Network not found' + error_detail = 'Network detail' + self._test_exception_handler_v20( + exceptions.NetworkNotFoundClient, 404, + error_msg + '\n' + error_detail, + 'NetworkNotFound', error_msg, error_detail) + + def test_exception_handler_v20_neutron_known_error_without_detail(self): + error_msg = 'Network not found' + error_detail = '' + self._test_exception_handler_v20( + exceptions.NetworkNotFoundClient, 404, + error_msg, + 'NetworkNotFound', error_msg, error_detail) + + def test_exception_handler_v20_neutron_unknown_error(self): + error_msg = 'Unknown error' + error_detail = 'This is detail' + self._test_exception_handler_v20( + exceptions.NeutronClientException, 400, + error_msg + '\n' + error_detail, + 'UnknownError', error_msg, error_detail) + + def test_exception_handler_v20_bad_neutron_error(self): + error_content = {'NeutronError': {'unknown_key': 'UNKNOWN'}} + self._test_exception_handler_v20( + exceptions.NeutronClientException, 500, + expected_msg={'unknown_key': 'UNKNOWN'}, + error_content=error_content) + + def test_exception_handler_v20_error_dict_contains_message(self): + error_content = {'message': 'This is an error message'} + self._test_exception_handler_v20( + exceptions.NeutronClientException, 500, + expected_msg='This is an error message', + error_content=error_content) + + def test_exception_handler_v20_error_dict_not_contain_message(self): + error_content = {'error': 'This is an error message'} + expected_msg = '%s-%s' % (500, error_content) + self._test_exception_handler_v20( + exceptions.NeutronClientException, 500, + expected_msg=expected_msg, + error_content=error_content) + + def test_exception_handler_v20_default_fallback(self): + error_content = 'This is an error message' + expected_msg = '%s-%s' % (500, error_content) + self._test_exception_handler_v20( + exceptions.NeutronClientException, 500, + expected_msg=expected_msg, + error_content=error_content) diff --git a/neutronclient/tests/unit/test_http.py b/neutronclient/tests/unit/test_http.py index 1e66a2b34..1114f33be 100644 --- a/neutronclient/tests/unit/test_http.py +++ b/neutronclient/tests/unit/test_http.py @@ -61,3 +61,25 @@ class TestHTTPClient(testtools.TestCase): self.assertEqual(rv_should_be, self.http._cs_request(URL, METHOD)) self.mox.VerifyAll() + + def test_request_unauthorized(self): + rv_should_be = MyResp(401), 'unauthorized message' + httplib2.Http.request( + URL, METHOD, headers=mox.IgnoreArg() + ).AndReturn(rv_should_be) + self.mox.ReplayAll() + + e = self.assertRaises(exceptions.Unauthorized, + self.http._cs_request, URL, METHOD) + self.assertEqual('unauthorized message', e.message) + self.mox.VerifyAll() + + def test_request_forbidden_is_returned_to_caller(self): + rv_should_be = MyResp(403), 'forbidden message' + httplib2.Http.request( + URL, METHOD, headers=mox.IgnoreArg() + ).AndReturn(rv_should_be) + self.mox.ReplayAll() + + self.assertEqual(rv_should_be, self.http._cs_request(URL, METHOD)) + self.mox.VerifyAll() diff --git a/neutronclient/v2_0/client.py b/neutronclient/v2_0/client.py index 13a22943b..4098c1db8 100644 --- a/neutronclient/v2_0/client.py +++ b/neutronclient/v2_0/client.py @@ -30,6 +30,18 @@ from neutronclient.common import utils _logger = logging.getLogger(__name__) +NEUTRON_ERRORS = { + 'NetworkNotFound': exceptions.NetworkNotFoundClient, + 'NetworkInUse': exceptions.NetworkInUseClient, + 'PortNotFound': exceptions.PortNotFoundClient, + 'RequestedStateInvalid': exceptions.StateInvalidClient, + 'PortInUse': exceptions.PortInUseClient, + 'IpAddressInUse': exceptions.IpAddressInUseClient, + 'AlreadyAttached': exceptions.AlreadyAttachedClient, + 'IpAddressGenerationFailure': exceptions.IpAddressGenerationFailureClient, + 'ExternalIpAddressExhausted': exceptions.ExternalIpAddressExhaustedClient, +} + def exception_handler_v20(status_code, error_content): """Exception handler for API v2.0 client @@ -41,20 +53,6 @@ def exception_handler_v20(status_code, error_content): :param status_code: HTTP error status code :param error_content: deserialized body of error response """ - - neutron_errors = { - 'NetworkNotFound': exceptions.NetworkNotFoundClient, - 'NetworkInUse': exceptions.NetworkInUseClient, - 'PortNotFound': exceptions.PortNotFoundClient, - 'RequestedStateInvalid': exceptions.StateInvalidClient, - 'PortInUse': exceptions.PortInUseClient, - 'IpAddressInUse': exceptions.IpAddressInUseClient, - 'AlreadyAttached': exceptions.AlreadyAttachedClient, - 'IpAddressGenerationFailure': - exceptions.IpAddressGenerationFailureClient, - 'ExternalIpAddressExhausted': - exceptions.ExternalIpAddressExhaustedClient, } - error_dict = None if isinstance(error_content, dict): error_dict = error_content.get('NeutronError') @@ -65,27 +63,26 @@ def exception_handler_v20(status_code, error_content): # a 'message' and 'type' keys? try: error_type = error_dict['type'] - error_message = (error_dict['message'] + "\n" + - error_dict['detail']) + error_message = error_dict['message'] + if error_dict['detail']: + error_message += "\n" + error_dict['detail'] except Exception: bad_neutron_error_flag = True if not bad_neutron_error_flag: - ex = None try: # raise the appropriate error! - ex = neutron_errors[error_type](message=error_message, - status_code=status_code) - except Exception: - pass - if ex: - raise ex + raise NEUTRON_ERRORS[error_type](message=error_message, + status_code=status_code) + except KeyError: + raise exceptions.NeutronClientException( + status_code=status_code, message=error_message) else: raise exceptions.NeutronClientException(status_code=status_code, message=error_dict) else: message = None if isinstance(error_content, dict): - message = error_content.get('message', None) + message = error_content.get('message') if message: raise exceptions.NeutronClientException(status_code=status_code, message=message)