Skip to content

Commit cb8b462

Browse files
authored
Merge pull request #2283 from ulyssessouza/3.7.1-release
3.7.1 release
2 parents ac92219 + 963818a commit cb8b462

File tree

11 files changed

+76
-37
lines changed

11 files changed

+76
-37
lines changed

docker/api/client.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,26 @@
2222
from .. import auth
2323
from ..constants import (
2424
DEFAULT_TIMEOUT_SECONDS, DEFAULT_USER_AGENT, IS_WINDOWS_PLATFORM,
25-
DEFAULT_DOCKER_API_VERSION, STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS,
26-
MINIMUM_DOCKER_API_VERSION
25+
DEFAULT_DOCKER_API_VERSION, MINIMUM_DOCKER_API_VERSION,
26+
STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS_SSH, DEFAULT_NUM_POOLS
2727
)
2828
from ..errors import (
2929
DockerException, InvalidVersion, TLSParameterError,
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

@@ -101,7 +101,7 @@ class APIClient(
101101

102102
def __init__(self, base_url=None, version=None,
103103
timeout=DEFAULT_TIMEOUT_SECONDS, tls=False,
104-
user_agent=DEFAULT_USER_AGENT, num_pools=DEFAULT_NUM_POOLS,
104+
user_agent=DEFAULT_USER_AGENT, num_pools=None,
105105
credstore_env=None):
106106
super(APIClient, self).__init__()
107107

@@ -132,8 +132,12 @@ def __init__(self, base_url=None, version=None,
132132
base_url = utils.parse_host(
133133
base_url, IS_WINDOWS_PLATFORM, tls=bool(tls)
134134
)
135+
# SSH has a different default for num_pools to all other adapters
136+
num_pools = num_pools or DEFAULT_NUM_POOLS_SSH if \
137+
base_url.startswith('ssh://') else DEFAULT_NUM_POOLS
138+
135139
if base_url.startswith('http+unix://'):
136-
self._custom_adapter = UnixAdapter(
140+
self._custom_adapter = UnixHTTPAdapter(
137141
base_url, timeout, pool_connections=num_pools
138142
)
139143
self.mount('http+docker://', self._custom_adapter)
@@ -147,7 +151,7 @@ def __init__(self, base_url=None, version=None,
147151
'The npipe:// protocol is only supported on Windows'
148152
)
149153
try:
150-
self._custom_adapter = NpipeAdapter(
154+
self._custom_adapter = NpipeHTTPAdapter(
151155
base_url, timeout, pool_connections=num_pools
152156
)
153157
except NameError:
@@ -158,7 +162,7 @@ def __init__(self, base_url=None, version=None,
158162
self.base_url = 'http+docker://localnpipe'
159163
elif base_url.startswith('ssh://'):
160164
try:
161-
self._custom_adapter = SSHAdapter(
165+
self._custom_adapter = SSHHTTPAdapter(
162166
base_url, timeout, pool_connections=num_pools
163167
)
164168
except NameError:
@@ -173,7 +177,8 @@ def __init__(self, base_url=None, version=None,
173177
if isinstance(tls, TLSConfig):
174178
tls.configure_client(self)
175179
elif tls:
176-
self._custom_adapter = SSLAdapter(pool_connections=num_pools)
180+
self._custom_adapter = SSLHTTPAdapter(
181+
pool_connections=num_pools)
177182
self.mount('https://', self._custom_adapter)
178183
self.base_url = base_url
179184

docker/constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,10 @@
1818

1919
DEFAULT_USER_AGENT = "docker-sdk-python/{0}".format(version)
2020
DEFAULT_NUM_POOLS = 25
21+
22+
# The OpenSSH server default value for MaxSessions is 10 which means we can
23+
# use up to 9, leaving the final session for the underlying SSH connection.
24+
# For more details see: https://github.com/docker/docker-py/issues/2246
25+
DEFAULT_NUM_POOLS_SSH = 9
26+
2127
DEFAULT_DATA_CHUNK_SIZE = 1024 * 2048

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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import requests.adapters
2+
3+
4+
class BaseHTTPAdapter(requests.adapters.HTTPAdapter):
5+
def close(self):
6+
super(BaseHTTPAdapter, self).close()
7+
if hasattr(self, 'pools'):
8+
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()

docker/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version = "3.7.0"
1+
version = "3.7.1"
22
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])

0 commit comments

Comments
 (0)