Cleanup session on delete

If an external session object was not passed to the Session class, we
create a requests.Session() on our own. Once this is used, it may still
have an open connection when the auth Session is closed. We need to
handle the closing of the requests.Session() ourselves if we created
one. If you do not close it, a ResourceWarning may be reported about the
socket that is left open. If a session object is provided, we do not
attempt to close it as it will be up to the code consuming keystoneauth
to properly handle cleaning up the provided session.

Change-Id: I590755d665b371c76ba8e02836d81d41a95ac601
Closes-Bug: #1838704
This commit is contained in:
Alex Schultz 2019-08-01 16:08:24 -06:00
parent 38cd5fc6c3
commit b2b5ad3cb1
3 changed files with 35 additions and 0 deletions

View File

@ -347,6 +347,13 @@ class Session(object):
self.auth = auth self.auth = auth
self.session = _construct_session(session) self.session = _construct_session(session)
# NOTE(mwhahaha): keep a reference to the session object so we can
# clean it up when this object goes away. We don't want to close the
# session if it was passed into us as it may be reused externally.
# See LP#1838704
self._session = None
if not session:
self._session = self.session
self.original_ip = original_ip self.original_ip = original_ip
self.verify = verify self.verify = verify
self.cert = cert self.cert = cert
@ -375,6 +382,17 @@ class Session(object):
self._json = _JSONEncoder() self._json = _JSONEncoder()
def __del__(self):
"""Clean up resources on delete."""
if self._session:
# If we created a requests.Session, try to close it out correctly
try:
self._session.close()
except Exception:
pass
finally:
self._session = None
@property @property
def adapters(self): def adapters(self):
return self.session.adapters return self.session.adapters

View File

@ -930,6 +930,14 @@ class SessionAuthTests(utils.TestCase):
self.assertRequestHeaderEqual('X-Auth-Token', None) self.assertRequestHeaderEqual('X-Auth-Token', None)
def test_object_delete(self):
auth = AuthPlugin()
sess = client_session.Session(auth=auth)
mock_close = mock.Mock()
sess._session.close = mock_close
del sess
mock_close.assert_called_once()
def test_service_type_urls(self): def test_service_type_urls(self):
service_type = 'compute' service_type = 'compute'
interface = 'public' interface = 'public'

View File

@ -0,0 +1,9 @@
---
fixes:
- >
[`bug 1838704 <https://bugs.launchpad.net/keystone/+bug/1838704>`_]
When consuming keystoneauth1.session.Session, if a requests session is not
provided one is created. The Session used for requests may result in a
ResourceWarning being generated if it is not properly closed. The code
has been updated to close the session correctly when the Session object
is deleted.