diff options
author | Claudiu Belu <cbelu@cloudbasesolutions.com> | 2015-08-11 10:34:40 -0700 |
---|---|---|
committer | Claudiu Belu <cbelu@cloudbasesolutions.com> | 2015-08-26 09:15:20 +0300 |
commit | 33b24a6984c8de2f26af7900202bb85b6b5db125 (patch) | |
tree | 307dc03ad9b7813404c14829a56951f0bbb4c3aa | |
parent | ce7aea4dd074e32d1dde164a40c64b0bd8e1dbc6 (diff) | |
download | python-keystoneclient-33b24a6984c8de2f26af7900202bb85b6b5db125.tar.gz |
Fixes missing socket attribute error during init_poolmanager
On Windows, the 'socket' python module does not contain the
attributes TCP_KEEPCNT or TCP_KEEPINTVL, causing services
consuming the library to malfunction.
Adds conditionals for adding the mentioned socket attributes
to the socket options.
socket.SIO_KEEPALIVE_VALS cannot be added as a socket option
for Windows, as there is another way entirely to enable that
option.
Change-Id: I2e9746ae65400bbd23c3b48dfc3167de9eb66494
Partial-Bug: #1483696
-rw-r--r-- | keystoneclient/session.py | 21 | ||||
-rw-r--r-- | keystoneclient/tests/unit/test_session.py | 37 |
2 files changed, 54 insertions, 4 deletions
diff --git a/keystoneclient/session.py b/keystoneclient/session.py index 8ac5de6..b24bd90 100644 --- a/keystoneclient/session.py +++ b/keystoneclient/session.py @@ -934,10 +934,6 @@ class TCPKeepAliveAdapter(requests.adapters.HTTPAdapter): (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1), # Turn on TCP Keep-Alive (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), - # Set the maximum number of keep-alive probes - (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4), - # Send keep-alive probes every 15 seconds - (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15), ] # Some operating systems (e.g., OSX) do not support setting @@ -948,6 +944,23 @@ class TCPKeepAliveAdapter(requests.adapters.HTTPAdapter): (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60) ] + # TODO(claudiub): Windows does not contain the TCP_KEEPCNT and + # TCP_KEEPINTVL socket attributes. Instead, it contains + # SIO_KEEPALIVE_VALS, which can be set via ioctl, which should be + # set once it is available in requests. + # https://msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx + if hasattr(socket, 'TCP_KEEPCNT'): + socket_options += [ + # Set the maximum number of keep-alive probes + (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4) + ] + + if hasattr(socket, 'TCP_KEEPINTVL'): + socket_options += [ + # Send keep-alive probes every 15 seconds + (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 15) + ] + # After waiting 60 seconds, and then sending a probe once every 15 # seconds 4 times, these options should ensure that a connection # hands for no longer than 2 minutes before a ConnectionError is diff --git a/keystoneclient/tests/unit/test_session.py b/keystoneclient/tests/unit/test_session.py index ee76337..29bf1e1 100644 --- a/keystoneclient/tests/unit/test_session.py +++ b/keystoneclient/tests/unit/test_session.py @@ -251,6 +251,43 @@ class SessionTests(utils.TestCase): self.TEST_URL) +class TCPKeepAliveAdapter(utils.TestCase): + + @mock.patch.object(client_session, 'socket') + @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') + def test_init_poolmanager_all_options(self, mock_parent_init_poolmanager, + mock_socket): + # properties expected to be in socket. + mock_socket.TCP_KEEPIDLE = mock.sentinel.TCP_KEEPIDLE + mock_socket.TCP_KEEPCNT = mock.sentinel.TCP_KEEPCNT + mock_socket.TCP_KEEPINTVL = mock.sentinel.TCP_KEEPINTVL + desired_opts = [mock_socket.TCP_KEEPIDLE, mock_socket.TCP_KEEPCNT, + mock_socket.TCP_KEEPINTVL] + + adapter = client_session.TCPKeepAliveAdapter() + adapter.init_poolmanager() + + call_args, call_kwargs = mock_parent_init_poolmanager.call_args + called_socket_opts = call_kwargs['socket_options'] + call_options = [opt for (protocol, opt, value) in called_socket_opts] + for opt in desired_opts: + self.assertIn(opt, call_options) + + @mock.patch.object(client_session, 'socket') + @mock.patch('requests.adapters.HTTPAdapter.init_poolmanager') + def test_init_poolmanager(self, mock_parent_init_poolmanager, mock_socket): + spec = ['IPPROTO_TCP', 'TCP_NODELAY', 'SOL_SOCKET', 'SO_KEEPALIVE'] + mock_socket.mock_add_spec(spec) + adapter = client_session.TCPKeepAliveAdapter() + adapter.init_poolmanager() + + call_args, call_kwargs = mock_parent_init_poolmanager.call_args + called_socket_opts = call_kwargs['socket_options'] + call_options = [opt for (protocol, opt, value) in called_socket_opts] + self.assertEqual([mock_socket.TCP_NODELAY, mock_socket.SO_KEEPALIVE], + call_options) + + class RedirectTests(utils.TestCase): REDIRECT_CHAIN = ['http://myhost:3445/', |