diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py index c9ecaa766..d03faf26b 100644 --- a/ironicclient/common/http.py +++ b/ironicclient/common/http.py @@ -13,9 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -import copy from distutils.version import StrictVersion -import hashlib import logging import os import re @@ -27,8 +25,6 @@ import time from keystoneauth1 import adapter from keystoneauth1 import exceptions as kexc from oslo_serialization import jsonutils -from oslo_utils import strutils -import requests import six from six.moves import http_client import six.moves.urllib.parse as urlparse @@ -305,224 +301,6 @@ def with_retries(func): return wrapper -class HTTPClient(VersionNegotiationMixin): - - def __init__(self, endpoint, **kwargs): - LOG.warning('HTTPClient class is deprecated and will be removed ' - 'in Stein release, please use SessionClient instead.') - self.endpoint = endpoint - self.endpoint_trimmed = _trim_endpoint_api_version(endpoint) - self.auth_token = kwargs.get('token') - self.auth_ref = kwargs.get('auth_ref') - self.os_ironic_api_version = kwargs.get('os_ironic_api_version', - DEFAULT_VER) - self.api_version_select_state = kwargs.get( - 'api_version_select_state', 'default') - self.conflict_max_retries = kwargs.pop('max_retries', - DEFAULT_MAX_RETRIES) - self.conflict_retry_interval = kwargs.pop('retry_interval', - DEFAULT_RETRY_INTERVAL) - self.session = requests.Session() - - parts = urlparse.urlparse(endpoint) - if parts.scheme not in SUPPORTED_ENDPOINT_SCHEME: - msg = _('Unsupported scheme: %s') % parts.scheme - raise exc.EndpointException(msg) - - if parts.scheme == 'https': - if kwargs.get('insecure') is True: - self.session.verify = False - elif kwargs.get('ca_file'): - self.session.verify = kwargs['ca_file'] - self.session.cert = (kwargs.get('cert_file'), - kwargs.get('key_file')) - - def _process_header(self, name, value): - """Redacts any sensitive header - - Redact a header that contains sensitive information, by returning an - updated header with the sha1 hash of that value. The redacted value is - prefixed by '{SHA1}' because that's the convention used within - OpenStack. - - :returns: A tuple of (name, value) - name: the safe encoding format of name - value: the redacted value if name is x-auth-token, - or the safe encoding format of name - - """ - if name in SENSITIVE_HEADERS: - v = value.encode('utf-8') - h = hashlib.sha1(v) - d = h.hexdigest() - return (name, "{SHA1}%s" % d) - else: - return (name, value) - - def log_curl_request(self, method, url, kwargs): - curl = ['curl -i -X %s' % method] - - for (key, value) in kwargs['headers'].items(): - header = '-H \'%s: %s\'' % self._process_header(key, value) - curl.append(header) - - if not self.session.verify: - curl.append('-k') - elif isinstance(self.session.verify, six.string_types): - curl.append('--cacert %s' % self.session.verify) - - if self.session.cert: - curl.append('--cert %s' % self.session.cert[0]) - curl.append('--key %s' % self.session.cert[1]) - - if 'body' in kwargs: - body = strutils.mask_password(kwargs['body']) - curl.append('-d \'%s\'' % body) - - curl.append(self._make_connection_url(url)) - LOG.debug(' '.join(curl)) - - @staticmethod - def log_http_response(resp, body=None): - # NOTE(aarefiev): resp.raw is urllib3 response object, it's used - # only to get 'version', response from request with 'stream = True' - # should be used for raw reading. - status = (resp.raw.version / 10.0, resp.status_code, resp.reason) - dump = ['\nHTTP/%.1f %s %s' % status] - dump.extend(['%s: %s' % (k, v) for k, v in resp.headers.items()]) - dump.append('') - if body: - body = strutils.mask_password(body) - dump.extend([body, '']) - LOG.debug('\n'.join(dump)) - - def _make_connection_url(self, url): - # NOTE(pas-ha) we already stripped trailing / from endpoint_trimmed - if not url.startswith('/'): - url = '/' + url - return self.endpoint_trimmed + url - - def _parse_version_headers(self, resp): - return self._generic_parse_version_headers(resp.headers.get) - - def _make_simple_request(self, conn, method, url): - return conn.request(method, self._make_connection_url(url)) - - @with_retries - def _http_request(self, url, method, **kwargs): - """Send an http request with the specified characteristics. - - Wrapper around request.Session.request to handle tasks such - as setting headers and error handling. - """ - # NOTE(TheJulia): self.os_ironic_api_version is reset in - # the self.negotiate_version() call if negotiation occurs. - if self.os_ironic_api_version and self._must_negotiate_version(): - self.negotiate_version(self.session, None) - # Copy the kwargs so we can reuse the original in case of redirects - kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) - kwargs['headers'].setdefault('User-Agent', USER_AGENT) - if self.os_ironic_api_version: - kwargs['headers'].setdefault('X-OpenStack-Ironic-API-Version', - self.os_ironic_api_version) - if self.auth_token: - kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) - - self.log_curl_request(method, url, kwargs) - - # NOTE(aarefiev): This is for backwards compatibility, request - # expected body in 'data' field, previously we used httplib, - # which expected 'body' field. - body = kwargs.pop('body', None) - if body: - kwargs['data'] = body - - conn_url = self._make_connection_url(url) - try: - resp = self.session.request(method, - conn_url, - **kwargs) - - # TODO(deva): implement graceful client downgrade when connecting - # to servers that did not support microversions. Details here: - # https://specs.openstack.org/openstack/ironic-specs/specs/kilo-implemented/api-microversions.html#use-case-3b-new-client-communicating-with-a-old-ironic-user-specified # noqa - - if resp.status_code == http_client.NOT_ACCEPTABLE: - negotiated_ver = self.negotiate_version(self.session, resp) - kwargs['headers']['X-OpenStack-Ironic-API-Version'] = ( - negotiated_ver) - return self._http_request(url, method, **kwargs) - - except requests.exceptions.RequestException as e: - message = (_("Error has occurred while handling " - "request for %(url)s: %(e)s") % - dict(url=conn_url, e=e)) - # NOTE(aarefiev): not valid request(invalid url, missing schema, - # and so on), retrying is not needed. - if isinstance(e, ValueError): - raise exc.ValidationError(message) - - raise exc.ConnectionRefused(message) - - body_str = None - if resp.headers.get('Content-Type') == 'application/octet-stream': - body_iter = resp.iter_content(chunk_size=CHUNKSIZE) - self.log_http_response(resp) - else: - # Read body into string if it isn't obviously image data - body_str = resp.text - self.log_http_response(resp, body_str) - body_iter = six.StringIO(body_str) - - if resp.status_code >= http_client.BAD_REQUEST: - error_json = _extract_error_json(body_str) - raise exc.from_response( - resp, error_json.get('error_message'), - error_json.get('debuginfo'), method, url) - elif resp.status_code in (http_client.MOVED_PERMANENTLY, - http_client.FOUND, - http_client.USE_PROXY): - # Redirected. Reissue the request to the new location. - return self._http_request(resp['location'], method, **kwargs) - elif resp.status_code == http_client.MULTIPLE_CHOICES: - raise exc.from_response(resp, method=method, url=url) - - return resp, body_iter - - def json_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', 'application/json') - kwargs['headers'].setdefault('Accept', 'application/json') - - if 'body' in kwargs: - kwargs['body'] = jsonutils.dump_as_bytes(kwargs['body']) - - resp, body_iter = self._http_request(url, method, **kwargs) - content_type = resp.headers.get('Content-Type') - - if (resp.status_code in (http_client.NO_CONTENT, - http_client.RESET_CONTENT) - or content_type is None): - return resp, list() - - if 'application/json' in content_type: - body = ''.join([chunk for chunk in body_iter]) - try: - body = jsonutils.loads(body) - except ValueError: - LOG.error('Could not decode response body as JSON') - else: - body = None - - return resp, body - - def raw_request(self, method, url, **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', - 'application/octet-stream') - return self._http_request(url, method, **kwargs) - - class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection): """httplib-compatible connection using client-side SSL authentication @@ -722,49 +500,30 @@ def _construct_http_client(session=None, key_file=None, insecure=None, **kwargs): - if session: - kwargs.setdefault('service_type', 'baremetal') - kwargs.setdefault('user_agent', 'python-ironicclient') - kwargs.setdefault('interface', kwargs.pop('endpoint_type', - 'publicURL')) - ignored = {'token': token, - 'auth_ref': auth_ref, - 'timeout': timeout != 600, - 'ca_file': ca_file, - 'cert_file': cert_file, - 'key_file': key_file, - 'insecure': insecure} + kwargs.setdefault('service_type', 'baremetal') + kwargs.setdefault('user_agent', 'python-ironicclient') + kwargs.setdefault('interface', kwargs.pop('endpoint_type', + 'publicURL')) - dvars = [k for k, v in ignored.items() if v] + ignored = {'token': token, + 'auth_ref': auth_ref, + 'timeout': timeout != 600, + 'ca_file': ca_file, + 'cert_file': cert_file, + 'key_file': key_file, + 'insecure': insecure} - if dvars: - LOG.warning('The following arguments are ignored when using ' - 'the session to construct a client: %s', - ', '.join(dvars)) + dvars = [k for k, v in ignored.items() if v] - return SessionClient(session=session, - os_ironic_api_version=os_ironic_api_version, - api_version_select_state=api_version_select_state, - max_retries=max_retries, - retry_interval=retry_interval, - **kwargs) - else: - endpoint = None - if kwargs: - endpoint = kwargs.pop('endpoint_override', None) - LOG.warning('The following arguments are being ignored when ' - 'constructing the client: %s', ', '.join(kwargs)) + if dvars: + LOG.warning('The following arguments are ignored when using ' + 'the session to construct a client: %s', + ', '.join(dvars)) - return HTTPClient(endpoint=endpoint, - token=token, - auth_ref=auth_ref, - os_ironic_api_version=os_ironic_api_version, - api_version_select_state=api_version_select_state, - max_retries=max_retries, - retry_interval=retry_interval, - timeout=timeout, - ca_file=ca_file, - cert_file=cert_file, - key_file=key_file, - insecure=insecure) + return SessionClient(session=session, + os_ironic_api_version=os_ironic_api_version, + api_version_select_state=api_version_select_state, + max_retries=max_retries, + retry_interval=retry_interval, + **kwargs) diff --git a/ironicclient/tests/unit/common/test_http.py b/ironicclient/tests/unit/common/test_http.py index 7828bfc08..f77563294 100644 --- a/ironicclient/tests/unit/common/test_http.py +++ b/ironicclient/tests/unit/common/test_http.py @@ -17,7 +17,6 @@ import time import mock from oslo_serialization import jsonutils -import requests import six from six.moves import http_client @@ -348,296 +347,6 @@ class VersionNegotiationMixinTest(utils.BaseTestCase): self.assertEqual((host, port), http.get_server(endpoint)) -class HttpClientTest(utils.BaseTestCase): - - @mock.patch.object(http.LOG, 'warning', autospec=True) - def test_http_client_deprecation(self, log_mock): - http.HTTPClient('http://localhost') - self.assertIn('deprecated', log_mock.call_args[0][0]) - - def test_url_generation_trailing_slash_in_base(self): - client = http.HTTPClient('http://localhost/') - url = client._make_connection_url('/v1/resources') - self.assertEqual('http://localhost/v1/resources', url) - - def test_url_generation_without_trailing_slash_in_base(self): - client = http.HTTPClient('http://localhost') - url = client._make_connection_url('/v1/resources') - self.assertEqual('http://localhost/v1/resources', url) - - def test_url_generation_without_prefix_slash_in_path(self): - client = http.HTTPClient('http://localhost') - url = client._make_connection_url('v1/resources') - self.assertEqual('http://localhost/v1/resources', url) - - def test_server_https_request_with_application_octet_stream(self): - client = http.HTTPClient('https://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/octet-stream'}, - "Body", - version=1, - status_code=http_client.OK) - - response, body = client.json_request('GET', '/v1/resources') - self.assertEqual(client.session.request.return_value, response) - self.assertIsNone(body) - - def test_server_exception_empty_body(self): - error_body = _get_error_body() - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.INTERNAL_SERVER_ERROR) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_server_exception_msg_only(self): - error_msg = 'test error msg' - error_body = _get_error_body(error_msg) - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.INTERNAL_SERVER_ERROR) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_server_exception_description_only(self): - error_msg = 'test error msg' - error_body = _get_error_body(description=error_msg) - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.BAD_REQUEST) - - self.assertRaisesRegex(exc.BadRequest, 'test error msg', - client.json_request, - 'GET', '/v1/resources') - - def test_server_https_request_ok(self): - client = http.HTTPClient('https://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - "Body", - version=1, - status_code=http_client.OK) - - client.json_request('GET', '/v1/resources') - - def test_server_https_empty_body(self): - error_body = _get_error_body() - - client = http.HTTPClient('https://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'application/json'}, - error_body, - version=1, - status_code=http_client.INTERNAL_SERVER_ERROR) - - self.assertRaises(exc.InternalServerError, - client.json_request, - 'GET', '/v1/resources') - - def test_401_unauthorized_exception(self): - error_body = _get_error_body() - client = http.HTTPClient('http://localhost/') - client.session = utils.mockSession( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.UNAUTHORIZED) - - self.assertRaises(exc.Unauthorized, client.json_request, - 'GET', '/v1/resources') - - def test_http_request_not_valid_request(self): - client = http.HTTPClient('http://localhost/') - client.session.request = mock.Mock( - side_effect=http.requests.exceptions.InvalidSchema) - - self.assertRaises(exc.ValidationError, client._http_request, - 'http://localhost/', 'GET') - - def test__parse_version_headers(self): - # Test parsing of version headers from HTTPClient - error_body = _get_error_body() - expected_result = ('1.1', '1.6') - - client = http.HTTPClient('http://localhost/') - fake_resp = utils.mockSessionResponse( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'Content-Type': 'text/plain', - }, - error_body, - version=1, - status_code=http_client.NOT_ACCEPTABLE) - result = client._parse_version_headers(fake_resp) - self.assertEqual(expected_result, result) - - @mock.patch.object(filecache, 'save_data', autospec=True) - def test__http_request_client_fallback_fail(self, mock_save_data): - # Test when fallback to a supported version fails - host, port, latest_ver = 'localhost', '1234', '1.6' - error_body = _get_error_body() - - client = http.HTTPClient('http://%s:%s/' % (host, port)) - client.session = utils.mockSession( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': latest_ver, - 'content-type': 'text/plain', - }, - error_body, - version=1, - status_code=http_client.NOT_ACCEPTABLE) - self.assertRaises( - exc.UnsupportedVersion, - client._http_request, - '/v1/resources', - 'GET') - mock_save_data.assert_called_once_with(host=host, data=latest_ver, - port=port) - - @mock.patch.object(http.VersionNegotiationMixin, 'negotiate_version', - autospec=False) - def test__http_request_client_fallback_success(self, mock_negotiate): - # Test when fallback to a supported version succeeds - mock_negotiate.return_value = '1.6' - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'content-type': 'text/plain', - }, - error_body, - version=1, - status_code=http_client.NOT_ACCEPTABLE) - good_resp = utils.mockSessionResponse( - {'X-OpenStack-Ironic-API-Minimum-Version': '1.1', - 'X-OpenStack-Ironic-API-Maximum-Version': '1.6', - 'content-type': 'text/plain', - }, - "We got some text", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - - mock_session.request.side_effect = iter([bad_resp, good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(1, mock_negotiate.call_count) - - @mock.patch.object(requests.Session, 'request', autospec=True) - @mock.patch.object(http.VersionNegotiationMixin, 'negotiate_version', - autospec=False) - def test__http_request_explicit_version(self, mock_negotiate, - mock_session): - headers = {'User-Agent': 'python-ironicclient', - 'X-OpenStack-Ironic-API-Version': '1.28'} - kwargs = {'os_ironic_api_version': '1.30', - 'api_version_select_state': 'negotiated'} - mock_session.return_value = utils.mockSessionResponse( - {}, status_code=http_client.NO_CONTENT, version=1) - client = http.HTTPClient('http://localhost/', **kwargs) - response, body_iter = client._http_request('/v1/resources', 'GET', - headers=headers) - mock_session.assert_called_once_with(mock.ANY, 'GET', - 'http://localhost/v1/resources', - headers=headers) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_mask_password(self, mock_log): - client = http.HTTPClient('http://localhost/') - kwargs = {'headers': {'foo-header': 'bar-header'}, - 'body': '{"password": "foo"}'} - client.log_curl_request('foo', '/v1/nodes', kwargs) - expected_log = ("curl -i -X foo -H 'foo-header: bar-header' " - "-d '{\"password\": \"***\"}' " - "http://localhost/v1/nodes") - mock_log.assert_called_once_with(expected_log) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_http_response_mask_password(self, mock_log): - client = http.HTTPClient('http://localhost/') - fake_response = utils.FakeResponse({}, version=1, reason='foo', - status=200) - body = '{"password": "foo"}' - client.log_http_response(fake_response, body=body) - expected_log = ("\nHTTP/0.1 200 foo\n\n{\"password\": \"***\"}\n") - mock_log.assert_called_once_with(expected_log) - - def test__https_init_ssl_args_insecure(self): - client = http.HTTPClient('https://localhost/', insecure=True) - - self.assertEqual(False, client.session.verify) - - def test__https_init_ssl_args_secure(self): - client = http.HTTPClient('https://localhost/', ca_file='test_ca', - key_file='test_key', cert_file='test_cert') - - self.assertEqual('test_ca', client.session.verify) - self.assertEqual(('test_cert', 'test_key'), client.session.cert) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_with_body_and_header(self, mock_log): - client = http.HTTPClient('http://test') - headers = {'header1': 'value1'} - body = 'example body' - - client.log_curl_request('GET', '/v1/nodes', - {'headers': headers, 'body': body}) - - self.assertTrue(mock_log.called) - self.assertTrue(mock_log.call_args[0]) - self.assertEqual("curl -i -X GET -H 'header1: value1'" - " -d 'example body' http://test/v1/nodes", - mock_log.call_args[0][0]) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_with_certs(self, mock_log): - headers = {'header1': 'value1'} - client = http.HTTPClient('https://test', key_file='key', - cert_file='cert', cacert='cacert', - token='fake-token') - - client.log_curl_request('GET', '/v1/test', {'headers': headers}) - - self.assertTrue(mock_log.called) - self.assertTrue(mock_log.call_args[0]) - - self.assertEqual("curl -i -X GET -H 'header1: value1' " - "--cert cert --key key https://test/v1/test", - mock_log.call_args[0][0]) - - @mock.patch.object(http.LOG, 'debug', autospec=True) - def test_log_curl_request_with_insecure_param(self, mock_log): - headers = {'header1': 'value1'} - http_client_object = http.HTTPClient('https://test', insecure=True, - token='fake-token') - - http_client_object.log_curl_request('GET', '/v1/test', - {'headers': headers}) - - self.assertTrue(mock_log.called) - self.assertTrue(mock_log.call_args[0]) - self.assertEqual("curl -i -X GET -H 'header1: value1' -k " - "--cert None --key None https://test/v1/test", - mock_log.call_args[0][0]) - - class SessionClientTest(utils.BaseTestCase): @mock.patch.object(http.LOG, 'warning', autospec=True) @@ -750,136 +459,6 @@ class SessionClientTest(utils.BaseTestCase): @mock.patch.object(time, 'sleep', lambda *_: None) class RetriesTestCase(utils.BaseTestCase): - def test_http_no_retry(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/', max_retries=0) - - with mock.patch.object(client.session, 'request', autospec=True, - return_value=bad_resp) as mock_request: - - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(1, mock_request.call_count) - - def test_http_retry(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - good_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - "meow", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - - mock_session.request.side_effect = iter([bad_resp, good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(2, mock_session.request.call_count) - - def test_http_retry_503(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.SERVICE_UNAVAILABLE) - good_resp = utils.mockSessionResponse( - {'Content-Type': 'text/plain'}, - "meow", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.side_effect = iter([bad_resp, good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(2, mock_session.request.call_count) - - def test_http_retry_connection_refused(self): - good_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - "meow", - version=1, - status_code=http_client.OK) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.side_effect = iter([exc.ConnectionRefused(), - good_resp]) - response, body_iter = client._http_request('/v1/resources', 'GET') - - self.assertEqual(http_client.OK, response.status_code) - self.assertEqual(2, mock_session.request.call_count) - - def test_http_failed_retry(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/') - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.return_value = bad_resp - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 1, - mock_session.request.call_count) - - def test_http_max_retries_none(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/', max_retries=None) - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.return_value = bad_resp - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 1, - mock_session.request.call_count) - - def test_http_change_max_retries(self): - error_body = _get_error_body() - bad_resp = utils.mockSessionResponse( - {'content-type': 'text/plain'}, - error_body, - version=1, - status_code=http_client.CONFLICT) - client = http.HTTPClient('http://localhost/', - max_retries=http.DEFAULT_MAX_RETRIES + 1) - - with mock.patch.object(client, 'session', - autospec=True) as mock_session: - mock_session.request.return_value = bad_resp - self.assertRaises(exc.Conflict, client._http_request, - '/v1/resources', 'GET') - self.assertEqual(http.DEFAULT_MAX_RETRIES + 2, - mock_session.request.call_count) - def test_session_retry(self): error_body = _get_error_body() diff --git a/ironicclient/tests/unit/test_client.py b/ironicclient/tests/unit/test_client.py index ff10f197a..d9c77f965 100644 --- a/ironicclient/tests/unit/test_client.py +++ b/ironicclient/tests/unit/test_client.py @@ -490,18 +490,3 @@ class ClientTest(utils.BaseTestCase): 'interface': None} ) self.assertFalse(mock_ks_session.called) - - def test_safe_header_with_auth_token(self): - (name, value) = ('X-Auth-Token', u'3b640e2e64d946ac8f55615aff221dc1') - expected_header = (u'X-Auth-Token', - '{SHA1}6de9fb3b0b89099030a54abfeb468e7b1b1f0f2b') - client = http.HTTPClient('http://localhost/') - header_redact = client._process_header(name, value) - self.assertEqual(expected_header, header_redact) - - def test_safe_header_with_no_auth_token(self): - name, value = ('Accept', 'application/json') - header = ('Accept', 'application/json') - client = http.HTTPClient('http://localhost/') - header_redact = client._process_header(name, value) - self.assertEqual(header, header_redact) diff --git a/releasenotes/notes/remove-deprecated-http-client-c969f583573251e9.yaml b/releasenotes/notes/remove-deprecated-http-client-c969f583573251e9.yaml new file mode 100644 index 000000000..3b768a7e8 --- /dev/null +++ b/releasenotes/notes/remove-deprecated-http-client-c969f583573251e9.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + Removes deprecated ``common.http.HTTPClient`` class. + The ``common.http.SessionClient`` class should be used instead.