Skip to content

Commit

Permalink
Merge pull request #2283 from ulyssessouza/3.7.1-release
Browse files Browse the repository at this point in the history
3.7.1 release
  • Loading branch information
rumpl authored Mar 20, 2019
2 parents ac92219 + 963818a commit cb8b462
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 37 deletions.
25 changes: 15 additions & 10 deletions docker/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@
from .. import auth
from ..constants import (
DEFAULT_TIMEOUT_SECONDS, DEFAULT_USER_AGENT, IS_WINDOWS_PLATFORM,
DEFAULT_DOCKER_API_VERSION, STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS,
MINIMUM_DOCKER_API_VERSION
DEFAULT_DOCKER_API_VERSION, MINIMUM_DOCKER_API_VERSION,
STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS_SSH, DEFAULT_NUM_POOLS
)
from ..errors import (
DockerException, InvalidVersion, TLSParameterError,
create_api_error_from_http_exception
)
from ..tls import TLSConfig
from ..transport import SSLAdapter, UnixAdapter
from ..transport import SSLHTTPAdapter, UnixHTTPAdapter
from ..utils import utils, check_resource, update_headers, config
from ..utils.socket import frames_iter, consume_socket_output, demux_adaptor
from ..utils.json_stream import json_stream
from ..utils.proxy import ProxyConfig
try:
from ..transport import NpipeAdapter
from ..transport import NpipeHTTPAdapter
except ImportError:
pass

try:
from ..transport import SSHAdapter
from ..transport import SSHHTTPAdapter
except ImportError:
pass

Expand Down Expand Up @@ -101,7 +101,7 @@ class APIClient(

def __init__(self, base_url=None, version=None,
timeout=DEFAULT_TIMEOUT_SECONDS, tls=False,
user_agent=DEFAULT_USER_AGENT, num_pools=DEFAULT_NUM_POOLS,
user_agent=DEFAULT_USER_AGENT, num_pools=None,
credstore_env=None):
super(APIClient, self).__init__()

Expand Down Expand Up @@ -132,8 +132,12 @@ def __init__(self, base_url=None, version=None,
base_url = utils.parse_host(
base_url, IS_WINDOWS_PLATFORM, tls=bool(tls)
)
# SSH has a different default for num_pools to all other adapters
num_pools = num_pools or DEFAULT_NUM_POOLS_SSH if \
base_url.startswith('ssh://') else DEFAULT_NUM_POOLS

if base_url.startswith('http+unix://'):
self._custom_adapter = UnixAdapter(
self._custom_adapter = UnixHTTPAdapter(
base_url, timeout, pool_connections=num_pools
)
self.mount('http+docker://', self._custom_adapter)
Expand All @@ -147,7 +151,7 @@ def __init__(self, base_url=None, version=None,
'The npipe:// protocol is only supported on Windows'
)
try:
self._custom_adapter = NpipeAdapter(
self._custom_adapter = NpipeHTTPAdapter(
base_url, timeout, pool_connections=num_pools
)
except NameError:
Expand All @@ -158,7 +162,7 @@ def __init__(self, base_url=None, version=None,
self.base_url = 'http+docker://localnpipe'
elif base_url.startswith('ssh://'):
try:
self._custom_adapter = SSHAdapter(
self._custom_adapter = SSHHTTPAdapter(
base_url, timeout, pool_connections=num_pools
)
except NameError:
Expand All @@ -173,7 +177,8 @@ def __init__(self, base_url=None, version=None,
if isinstance(tls, TLSConfig):
tls.configure_client(self)
elif tls:
self._custom_adapter = SSLAdapter(pool_connections=num_pools)
self._custom_adapter = SSLHTTPAdapter(
pool_connections=num_pools)
self.mount('https://', self._custom_adapter)
self.base_url = base_url

Expand Down
6 changes: 6 additions & 0 deletions docker/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@

DEFAULT_USER_AGENT = "docker-sdk-python/{0}".format(version)
DEFAULT_NUM_POOLS = 25

# The OpenSSH server default value for MaxSessions is 10 which means we can
# use up to 9, leaving the final session for the underlying SSH connection.
# For more details see: https://github.com/docker/docker-py/issues/2246
DEFAULT_NUM_POOLS_SSH = 9

DEFAULT_DATA_CHUNK_SIZE = 1024 * 2048
4 changes: 2 additions & 2 deletions docker/tls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import ssl

from . import errors
from .transport import SSLAdapter
from .transport import SSLHTTPAdapter


class TLSConfig(object):
Expand Down Expand Up @@ -105,7 +105,7 @@ def configure_client(self, client):
if self.cert:
client.cert = self.cert

client.mount('https://', SSLAdapter(
client.mount('https://', SSLHTTPAdapter(
ssl_version=self.ssl_version,
assert_hostname=self.assert_hostname,
assert_fingerprint=self.assert_fingerprint,
Expand Down
8 changes: 4 additions & 4 deletions docker/transport/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# flake8: noqa
from .unixconn import UnixAdapter
from .ssladapter import SSLAdapter
from .unixconn import UnixHTTPAdapter
from .ssladapter import SSLHTTPAdapter
try:
from .npipeconn import NpipeAdapter
from .npipeconn import NpipeHTTPAdapter
from .npipesocket import NpipeSocket
except ImportError:
pass

try:
from .sshconn import SSHAdapter
from .sshconn import SSHHTTPAdapter
except ImportError:
pass
8 changes: 8 additions & 0 deletions docker/transport/basehttpadapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import requests.adapters


class BaseHTTPAdapter(requests.adapters.HTTPAdapter):
def close(self):
super(BaseHTTPAdapter, self).close()
if hasattr(self, 'pools'):
self.pools.clear()
8 changes: 3 additions & 5 deletions docker/transport/npipeconn.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import six
import requests.adapters

from docker.transport.basehttpadapter import BaseHTTPAdapter
from .. import constants
from .npipesocket import NpipeSocket

Expand Down Expand Up @@ -68,7 +69,7 @@ def _get_conn(self, timeout):
return conn or self._new_conn()


class NpipeAdapter(requests.adapters.HTTPAdapter):
class NpipeHTTPAdapter(BaseHTTPAdapter):

__attrs__ = requests.adapters.HTTPAdapter.__attrs__ + ['npipe_path',
'pools',
Expand All @@ -81,7 +82,7 @@ def __init__(self, base_url, timeout=60,
self.pools = RecentlyUsedContainer(
pool_connections, dispose_func=lambda p: p.close()
)
super(NpipeAdapter, self).__init__()
super(NpipeHTTPAdapter, self).__init__()

def get_connection(self, url, proxies=None):
with self.pools.lock:
Expand All @@ -103,6 +104,3 @@ def request_url(self, request, proxies):
# anyway, we simply return the path URL directly.
# See also: https://github.com/docker/docker-sdk-python/issues/811
return request.path_url

def close(self):
self.pools.clear()
23 changes: 16 additions & 7 deletions docker/transport/sshconn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import requests.adapters
import six

from docker.transport.basehttpadapter import BaseHTTPAdapter
from .. import constants

if six.PY3:
Expand Down Expand Up @@ -68,7 +69,7 @@ def _get_conn(self, timeout):
return conn or self._new_conn()


class SSHAdapter(requests.adapters.HTTPAdapter):
class SSHHTTPAdapter(BaseHTTPAdapter):

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

parsed = six.moves.urllib_parse.urlparse(base_url)
self.ssh_client.connect(
parsed.hostname, parsed.port, parsed.username,
)
self.base_url = base_url
self._connect()
self.timeout = timeout
self.pools = RecentlyUsedContainer(
pool_connections, dispose_func=lambda p: p.close()
)
super(SSHAdapter, self).__init__()
super(SSHHTTPAdapter, self).__init__()

def _connect(self):
parsed = six.moves.urllib_parse.urlparse(self.base_url)
self.ssh_client.connect(
parsed.hostname, parsed.port, parsed.username,
)

def get_connection(self, url, proxies=None):
with self.pools.lock:
pool = self.pools.get(url)
if pool:
return pool

# Connection is closed try a reconnect
if not self.ssh_client.get_transport():
self._connect()

pool = SSHConnectionPool(
self.ssh_client, self.timeout
)
Expand All @@ -103,5 +112,5 @@ def get_connection(self, url, proxies=None):
return pool

def close(self):
self.pools.clear()
super(SSHHTTPAdapter, self).close()
self.ssh_client.close()
8 changes: 5 additions & 3 deletions docker/transport/ssladapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from distutils.version import StrictVersion
from requests.adapters import HTTPAdapter

from docker.transport.basehttpadapter import BaseHTTPAdapter

try:
import requests.packages.urllib3 as urllib3
except ImportError:
Expand All @@ -22,7 +24,7 @@
urllib3.connection.match_hostname = match_hostname


class SSLAdapter(HTTPAdapter):
class SSLHTTPAdapter(BaseHTTPAdapter):
'''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''

__attrs__ = HTTPAdapter.__attrs__ + ['assert_fingerprint',
Expand All @@ -34,7 +36,7 @@ def __init__(self, ssl_version=None, assert_hostname=None,
self.ssl_version = ssl_version
self.assert_hostname = assert_hostname
self.assert_fingerprint = assert_fingerprint
super(SSLAdapter, self).__init__(**kwargs)
super(SSLHTTPAdapter, self).__init__(**kwargs)

def init_poolmanager(self, connections, maxsize, block=False):
kwargs = {
Expand All @@ -57,7 +59,7 @@ def get_connection(self, *args, **kwargs):
But we still need to take care of when there is a proxy poolmanager
"""
conn = super(SSLAdapter, self).get_connection(*args, **kwargs)
conn = super(SSLHTTPAdapter, self).get_connection(*args, **kwargs)
if conn.assert_hostname != self.assert_hostname:
conn.assert_hostname = self.assert_hostname
return conn
Expand Down
8 changes: 3 additions & 5 deletions docker/transport/unixconn.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import socket
from six.moves import http_client as httplib

from docker.transport.basehttpadapter import BaseHTTPAdapter
from .. import constants

try:
Expand Down Expand Up @@ -69,7 +70,7 @@ def _new_conn(self):
)


class UnixAdapter(requests.adapters.HTTPAdapter):
class UnixHTTPAdapter(BaseHTTPAdapter):

__attrs__ = requests.adapters.HTTPAdapter.__attrs__ + ['pools',
'socket_path',
Expand All @@ -85,7 +86,7 @@ def __init__(self, socket_url, timeout=60,
self.pools = RecentlyUsedContainer(
pool_connections, dispose_func=lambda p: p.close()
)
super(UnixAdapter, self).__init__()
super(UnixHTTPAdapter, self).__init__()

def get_connection(self, url, proxies=None):
with self.pools.lock:
Expand All @@ -107,6 +108,3 @@ def request_url(self, request, proxies):
# anyway, we simply return the path URL directly.
# See also: https://github.com/docker/docker-py/issues/811
return request.path_url

def close(self):
self.pools.clear()
2 changes: 1 addition & 1 deletion docker/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "3.7.0"
version = "3.7.1"
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])
13 changes: 13 additions & 0 deletions docs/change-log.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Change log
==========

3.7.1
-----

[List of PRs / issues for this release](https://github.com/docker/docker-py/milestone/58?closed=1)

### Bugfixes

* Set a different default number (which is now 9) for SSH pools
* 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

3.7.0
-----

Expand Down

0 comments on commit cb8b462

Please sign in to comment.