diff --git a/openstack/config/cloud_region.py b/openstack/config/cloud_region.py index 421e2438c..ddd91bc8e 100644 --- a/openstack/config/cloud_region.py +++ b/openstack/config/cloud_region.py @@ -658,7 +658,11 @@ class CloudRegion: state = self._auth.get_auth_state() try: - keyring.set_password('openstacksdk', cache_id, state) + if state: + # NOTE: under some conditions the method may be invoked when auth + # is empty. This may lead to exception in the keyring lib, thus do + # nothing. + keyring.set_password('openstacksdk', cache_id, state) except RuntimeError: # the fail backend raises this self.log.debug('Failed to set auth into keyring') diff --git a/openstack/connection.py b/openstack/connection.py index 819e16bd3..5722a01e2 100644 --- a/openstack/connection.py +++ b/openstack/connection.py @@ -176,6 +176,7 @@ try to find it and if that fails, you would create it:: Additional information about the services can be found in the :ref:`service-proxies` documentation. """ +import atexit import concurrent.futures import warnings import weakref @@ -472,9 +473,8 @@ class Connection( 'additional_metric_tags' ] = self.config.config['additional_metric_tags'] - def __del__(self): - # try to force release of resources and save authorization - self.close() + # Register cleanup steps + atexit.register(self.close) @property def session(self): @@ -551,9 +551,9 @@ class Connection( def close(self): """Release any resources held open.""" + self.config.set_auth_cache() if self.__pool_executor: self.__pool_executor.shutdown() - self.config.set_auth_cache() def set_global_request_id(self, global_request_id): self._global_request_id = global_request_id diff --git a/openstack/tests/unit/config/test_config.py b/openstack/tests/unit/config/test_config.py index a9a7693b9..da5658940 100644 --- a/openstack/tests/unit/config/test_config.py +++ b/openstack/tests/unit/config/test_config.py @@ -608,6 +608,21 @@ class TestConfig(base.TestCase): ) ks_mock.assert_called_with(fake_auth) + @mock.patch('openstack.config.cloud_region.keyring') + def test_set_auth_cache_empty_auth(self, kr_mock): + c = config.OpenStackConfig( + config_files=[self.cloud_yaml], secure_files=[] + ) + c._cache_auth = True + + kr_mock.get_password = mock.Mock(side_effect=[RuntimeError]) + kr_mock.set_password = mock.Mock() + + region = c.get_one('_test-cloud_') + + region.set_auth_cache() + kr_mock.set_password.assert_not_called() + @mock.patch('openstack.config.cloud_region.keyring') def test_set_auth_cache(self, kr_mock): c = config.OpenStackConfig( @@ -619,6 +634,9 @@ class TestConfig(base.TestCase): kr_mock.set_password = mock.Mock() region = c.get_one('_test-cloud_') + region._auth.set_auth_state( + '{"auth_token":"foo", "body":{"token":"bar"}}' + ) region.set_auth_cache() kr_mock.set_password.assert_called_with(