Skip to content

Commit 313f736

Browse files
author
Ulysses Souza
committed
Homogenize adapters close() behaviour.
- Adds a BaseHTTPAdapter with a close method to ensure that the pools is clean on close() - Makes SSHHTTPAdapter reopen a closed connection when needed like the others Signed-off-by: Ulysses Souza <[email protected]>
1 parent e577f5d commit 313f736

File tree

8 files changed

+47
-33
lines changed

8 files changed

+47
-33
lines changed

docker/api/client.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,18 @@
3030
create_api_error_from_http_exception
3131
)
3232
from ..tls import TLSConfig
33-
from ..transport import SSLAdapter, UnixAdapter
33+
from ..transport import SSLHTTPAdapter, UnixHTTPAdapter
3434
from ..utils import utils, check_resource, update_headers, config
3535
from ..utils.socket import frames_iter, consume_socket_output, demux_adaptor
3636
from ..utils.json_stream import json_stream
3737
from ..utils.proxy import ProxyConfig
3838
try:
39-
from ..transport import NpipeAdapter
39+
from ..transport import NpipeHTTPAdapter
4040
except ImportError:
4141
pass
4242

4343
try:
44-
from ..transport import SSHAdapter
44+
from ..transport import SSHHTTPAdapter
4545
except ImportError:
4646
pass
4747

@@ -137,7 +137,7 @@ def __init__(self, base_url=None, version=None,
137137
base_url.startswith('ssh://') else DEFAULT_NUM_POOLS
138138

139139
if base_url.startswith('http+unix://'):
140-
self._custom_adapter = UnixAdapter(
140+
self._custom_adapter = UnixHTTPAdapter(
141141
base_url, timeout, pool_connections=num_pools
142142
)
143143
self.mount('http+docker://', self._custom_adapter)
@@ -151,7 +151,7 @@ def __init__(self, base_url=None, version=None,
151151
'The npipe:// protocol is only supported on Windows'
152152
)
153153
try:
154-
self._custom_adapter = NpipeAdapter(
154+
self._custom_adapter = NpipeHTTPAdapter(
155155
base_url, timeout, pool_connections=num_pools
156156
)
157157
except NameError:
@@ -162,7 +162,7 @@ def __init__(self, base_url=None, version=None,
162162
self.base_url = 'http+docker://localnpipe'
163163
elif base_url.startswith('ssh://'):
164164
try:
165-
self._custom_adapter = SSHAdapter(
165+
self._custom_adapter = SSHHTTPAdapter(
166166
base_url, timeout, pool_connections=num_pools
167167
)
168168
except NameError:
@@ -177,7 +177,8 @@ def __init__(self, base_url=None, version=None,
177177
if isinstance(tls, TLSConfig):
178178
tls.configure_client(self)
179179
elif tls:
180-
self._custom_adapter = SSLAdapter(pool_connections=num_pools)
180+
self._custom_adapter = SSLHTTPAdapter(
181+
pool_connections=num_pools)
181182
self.mount('https://', self._custom_adapter)
182183
self.base_url = base_url
183184

docker/tls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import ssl
33

44
from . import errors
5-
from .transport import SSLAdapter
5+
from .transport import SSLHTTPAdapter
66

77

88
class TLSConfig(object):
@@ -105,7 +105,7 @@ def configure_client(self, client):
105105
if self.cert:
106106
client.cert = self.cert
107107

108-
client.mount('https://', SSLAdapter(
108+
client.mount('https://', SSLHTTPAdapter(
109109
ssl_version=self.ssl_version,
110110
assert_hostname=self.assert_hostname,
111111
assert_fingerprint=self.assert_fingerprint,

docker/transport/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# flake8: noqa
2-
from .unixconn import UnixAdapter
3-
from .ssladapter import SSLAdapter
2+
from .unixconn import UnixHTTPAdapter
3+
from .ssladapter import SSLHTTPAdapter
44
try:
5-
from .npipeconn import NpipeAdapter
5+
from .npipeconn import NpipeHTTPAdapter
66
from .npipesocket import NpipeSocket
77
except ImportError:
88
pass
99

1010
try:
11-
from .sshconn import SSHAdapter
11+
from .sshconn import SSHHTTPAdapter
1212
except ImportError:
1313
pass
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import requests.adapters
2+
3+
4+
class BaseHTTPAdapter(requests.adapters.HTTPAdapter):
5+
def close(self):
6+
self.pools.clear()

docker/transport/npipeconn.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import six
22
import requests.adapters
33

4+
from docker.transport.basehttpadapter import BaseHTTPAdapter
45
from .. import constants
56
from .npipesocket import NpipeSocket
67

@@ -68,7 +69,7 @@ def _get_conn(self, timeout):
6869
return conn or self._new_conn()
6970

7071

71-
class NpipeAdapter(requests.adapters.HTTPAdapter):
72+
class NpipeHTTPAdapter(BaseHTTPAdapter):
7273

7374
__attrs__ = requests.adapters.HTTPAdapter.__attrs__ + ['npipe_path',
7475
'pools',
@@ -81,7 +82,7 @@ def __init__(self, base_url, timeout=60,
8182
self.pools = RecentlyUsedContainer(
8283
pool_connections, dispose_func=lambda p: p.close()
8384
)
84-
super(NpipeAdapter, self).__init__()
85+
super(NpipeHTTPAdapter, self).__init__()
8586

8687
def get_connection(self, url, proxies=None):
8788
with self.pools.lock:
@@ -103,6 +104,3 @@ def request_url(self, request, proxies):
103104
# anyway, we simply return the path URL directly.
104105
# See also: https://github.com/docker/docker-sdk-python/issues/811
105106
return request.path_url
106-
107-
def close(self):
108-
self.pools.clear()

docker/transport/sshconn.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import requests.adapters
33
import six
44

5+
from docker.transport.basehttpadapter import BaseHTTPAdapter
56
from .. import constants
67

78
if six.PY3:
@@ -68,7 +69,7 @@ def _get_conn(self, timeout):
6869
return conn or self._new_conn()
6970

7071

71-
class SSHAdapter(requests.adapters.HTTPAdapter):
72+
class SSHHTTPAdapter(BaseHTTPAdapter):
7273

7374
__attrs__ = requests.adapters.HTTPAdapter.__attrs__ + [
7475
'pools', 'timeout', 'ssh_client',
@@ -79,22 +80,30 @@ def __init__(self, base_url, timeout=60,
7980
self.ssh_client = paramiko.SSHClient()
8081
self.ssh_client.load_system_host_keys()
8182

82-
parsed = six.moves.urllib_parse.urlparse(base_url)
83-
self.ssh_client.connect(
84-
parsed.hostname, parsed.port, parsed.username,
85-
)
83+
self.base_url = base_url
84+
self._connect()
8685
self.timeout = timeout
8786
self.pools = RecentlyUsedContainer(
8887
pool_connections, dispose_func=lambda p: p.close()
8988
)
90-
super(SSHAdapter, self).__init__()
89+
super(SSHHTTPAdapter, self).__init__()
90+
91+
def _connect(self):
92+
parsed = six.moves.urllib_parse.urlparse(self.base_url)
93+
self.ssh_client.connect(
94+
parsed.hostname, parsed.port, parsed.username,
95+
)
9196

9297
def get_connection(self, url, proxies=None):
9398
with self.pools.lock:
9499
pool = self.pools.get(url)
95100
if pool:
96101
return pool
97102

103+
# Connection is closed try a reconnect
104+
if not self.ssh_client.get_transport():
105+
self._connect()
106+
98107
pool = SSHConnectionPool(
99108
self.ssh_client, self.timeout
100109
)
@@ -103,5 +112,5 @@ def get_connection(self, url, proxies=None):
103112
return pool
104113

105114
def close(self):
106-
self.pools.clear()
115+
super(SSHHTTPAdapter, self).close()
107116
self.ssh_client.close()

docker/transport/ssladapter.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from distutils.version import StrictVersion
88
from requests.adapters import HTTPAdapter
99

10+
from docker.transport.basehttpadapter import BaseHTTPAdapter
11+
1012
try:
1113
import requests.packages.urllib3 as urllib3
1214
except ImportError:
@@ -22,7 +24,7 @@
2224
urllib3.connection.match_hostname = match_hostname
2325

2426

25-
class SSLAdapter(HTTPAdapter):
27+
class SSLHTTPAdapter(BaseHTTPAdapter):
2628
'''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
2729

2830
__attrs__ = HTTPAdapter.__attrs__ + ['assert_fingerprint',
@@ -34,7 +36,7 @@ def __init__(self, ssl_version=None, assert_hostname=None,
3436
self.ssl_version = ssl_version
3537
self.assert_hostname = assert_hostname
3638
self.assert_fingerprint = assert_fingerprint
37-
super(SSLAdapter, self).__init__(**kwargs)
39+
super(SSLHTTPAdapter, self).__init__(**kwargs)
3840

3941
def init_poolmanager(self, connections, maxsize, block=False):
4042
kwargs = {
@@ -57,7 +59,7 @@ def get_connection(self, *args, **kwargs):
5759
5860
But we still need to take care of when there is a proxy poolmanager
5961
"""
60-
conn = super(SSLAdapter, self).get_connection(*args, **kwargs)
62+
conn = super(SSLHTTPAdapter, self).get_connection(*args, **kwargs)
6163
if conn.assert_hostname != self.assert_hostname:
6264
conn.assert_hostname = self.assert_hostname
6365
return conn

docker/transport/unixconn.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import socket
44
from six.moves import http_client as httplib
55

6+
from docker.transport.basehttpadapter import BaseHTTPAdapter
67
from .. import constants
78

89
try:
@@ -69,7 +70,7 @@ def _new_conn(self):
6970
)
7071

7172

72-
class UnixAdapter(requests.adapters.HTTPAdapter):
73+
class UnixHTTPAdapter(BaseHTTPAdapter):
7374

7475
__attrs__ = requests.adapters.HTTPAdapter.__attrs__ + ['pools',
7576
'socket_path',
@@ -85,7 +86,7 @@ def __init__(self, socket_url, timeout=60,
8586
self.pools = RecentlyUsedContainer(
8687
pool_connections, dispose_func=lambda p: p.close()
8788
)
88-
super(UnixAdapter, self).__init__()
89+
super(UnixHTTPAdapter, self).__init__()
8990

9091
def get_connection(self, url, proxies=None):
9192
with self.pools.lock:
@@ -107,6 +108,3 @@ def request_url(self, request, proxies):
107108
# anyway, we simply return the path URL directly.
108109
# See also: https://github.com/docker/docker-py/issues/811
109110
return request.path_url
110-
111-
def close(self):
112-
self.pools.clear()

0 commit comments

Comments
 (0)