From 8fd515773bc98309dc9c9a5b1f1363f2f98a85f8 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Fri, 20 Aug 2021 14:23:54 +0100 Subject: [PATCH] Fix CA file for Swift pollster Most OpenStack API communication uses the cafile option in the service_credentials config. For swift the client is created differently, and does not get this option. When TLS is used, we may get an error like the following: exceptions.SSLError: HTTPSConnectionPool(host='1.2.3.4', port=443): Max retries exceeded with url: /swift/v1/AUTH_XXXX (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),)) This change fixes the issue by creating an HTTP connection for the Swift client that uses the configured CA file. Closes-Bug: #1940660 Change-Id: I38f9ff2bec0a2a3cb9dfc5c362284e33c12f3127 (cherry picked from commit ed404c5f66e874779d58d3ac81f28ae22c55cf09) --- ceilometer/objectstore/swift.py | 8 +++- .../tests/unit/objectstore/test_swift.py | 42 ++++++++++++------- .../notes/fix-1940660-5226988f2e7ae1bd.yaml | 7 ++++ 3 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 releasenotes/notes/fix-1940660-5226988f2e7ae1bd.yaml diff --git a/ceilometer/objectstore/swift.py b/ceilometer/objectstore/swift.py index e4d82a164e..c0a2720193 100644 --- a/ceilometer/objectstore/swift.py +++ b/ceilometer/objectstore/swift.py @@ -86,10 +86,14 @@ class _Base(plugin_base.PollsterBase): swift_api_method = getattr(swift, '%s_account' % self.METHOD) for t in tenants: try: - yield (t.id, swift_api_method( + http_conn = swift.http_connection( self._neaten_url(endpoint, t.id, self.conf.reseller_prefix), - keystone_client.get_auth_token(ksclient))) + cacert=self.conf.service_credentials.cafile) + yield (t.id, swift_api_method( + None, + keystone_client.get_auth_token(ksclient), + http_conn)) except ClientException as e: if e.http_status == 404: LOG.warning("Swift tenant id %s not found.", t.id) diff --git a/ceilometer/tests/unit/objectstore/test_swift.py b/ceilometer/tests/unit/objectstore/test_swift.py index ec69be0631..c2bdd3fc53 100644 --- a/ceilometer/tests/unit/objectstore/test_swift.py +++ b/ceilometer/tests/unit/objectstore/test_swift.py @@ -188,18 +188,27 @@ class TestSwiftPollster(testscenarios.testcase.WithScenarios, mock_method = mock.MagicMock() endpoint = 'end://point/' api_method = '%s_account' % self.pollster.METHOD + mock_connection = mock.MagicMock() with fixtures.MockPatchObject(swift_client, api_method, new=mock_method): - with fixtures.MockPatchObject( - self.manager._service_catalog, 'url_for', - return_value=endpoint): - list(self.pollster.get_samples(self.manager, {}, - ASSIGNED_TENANTS)) + with fixtures.MockPatchObject(swift_client, + 'http_connection', + new=mock_connection): + with fixtures.MockPatchObject( + self.manager._service_catalog, 'url_for', + return_value=endpoint): + list(self.pollster.get_samples(self.manager, {}, + ASSIGNED_TENANTS)) expected = [mock.call(self.pollster._neaten_url( - endpoint, t.id, self.CONF.reseller_prefix), - self.manager._auth_token) - for t in ASSIGNED_TENANTS] + endpoint, t.id, self.CONF.reseller_prefix), + cacert=None) + for t in ASSIGNED_TENANTS] + self.assertEqual(expected, mock_connection.call_args_list) + + expected = [mock.call(None, self.manager._auth_token, + mock_connection.return_value) + for t in ASSIGNED_TENANTS] self.assertEqual(expected, mock_method.call_args_list) def test_get_endpoint_only_once(self): @@ -208,13 +217,16 @@ class TestSwiftPollster(testscenarios.testcase.WithScenarios, api_method = '%s_account' % self.pollster.METHOD with fixtures.MockPatchObject(swift_client, api_method, new=mock.MagicMock()): - with fixtures.MockPatchObject( - self.manager._service_catalog, 'url_for', - new=mock_url_for): - list(self.pollster.get_samples(self.manager, {}, - ASSIGNED_TENANTS)) - list(self.pollster.get_samples(self.manager, {}, - ASSIGNED_TENANTS)) + with fixtures.MockPatchObject(swift_client, + 'http_connection', + new=mock.MagicMock()): + with fixtures.MockPatchObject( + self.manager._service_catalog, 'url_for', + new=mock_url_for): + list(self.pollster.get_samples(self.manager, {}, + ASSIGNED_TENANTS)) + list(self.pollster.get_samples(self.manager, {}, + ASSIGNED_TENANTS)) self.assertEqual(1, mock_url_for.call_count) def test_endpoint_notfound(self): diff --git a/releasenotes/notes/fix-1940660-5226988f2e7ae1bd.yaml b/releasenotes/notes/fix-1940660-5226988f2e7ae1bd.yaml new file mode 100644 index 0000000000..14a515e84e --- /dev/null +++ b/releasenotes/notes/fix-1940660-5226988f2e7ae1bd.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - > + [`bug 1940660 `_] + Fixes an issue with the Swift pollster where the ``[service_credentials] + cafile`` option was not used. This could prevent communication with + TLS-enabled Swift APIs.