summaryrefslogtreecommitdiff
path: root/docker
diff options
context:
space:
mode:
authorJason Pleau <jason@jpleau.ca>2016-12-25 20:07:49 -0500
committerJason Pleau <jason@jpleau.ca>2016-12-25 20:07:49 -0500
commit7c25f0634f5ff158a492426fa6238e4e6351008b (patch)
treea04d43d9d45261489645477bb25b1bbe0ccdcfbe /docker
parent5d8d4569fb7b4e869d9c88fa0f7f703c38f8131e (diff)
New upstream version 1.10.6
Diffstat (limited to 'docker')
-rw-r--r--docker/client.py6
-rw-r--r--docker/transport/__init__.py1
-rw-r--r--docker/transport/npipeconn.py23
-rw-r--r--docker/transport/npipesocket.py55
-rw-r--r--docker/types/services.py2
-rw-r--r--docker/utils/socket.py9
-rw-r--r--docker/utils/utils.py11
-rw-r--r--docker/version.py2
8 files changed, 85 insertions, 24 deletions
diff --git a/docker/client.py b/docker/client.py
index 47ad09e..3fa19e0 100644
--- a/docker/client.py
+++ b/docker/client.py
@@ -86,7 +86,7 @@ class Client(
tls.configure_client(self)
elif tls:
self._custom_adapter = ssladapter.SSLAdapter(
- num_pools=num_pools
+ pool_connections=num_pools
)
self.mount('https://', self._custom_adapter)
self.base_url = base_url
@@ -218,7 +218,9 @@ class Client(
def _get_raw_response_socket(self, response):
self._raise_for_status(response)
- if six.PY3:
+ if self.base_url == "http+docker://localnpipe":
+ sock = response.raw._fp.fp.raw.sock
+ elif six.PY3:
sock = response.raw._fp.fp.raw
if self.base_url.startswith("https://"):
sock = sock._sock
diff --git a/docker/transport/__init__.py b/docker/transport/__init__.py
index d647483..46dfdf8 100644
--- a/docker/transport/__init__.py
+++ b/docker/transport/__init__.py
@@ -2,5 +2,6 @@
from .unixconn import UnixAdapter
try:
from .npipeconn import NpipeAdapter
+ from .npipesocket import NpipeSocket
except ImportError:
pass \ No newline at end of file
diff --git a/docker/transport/npipeconn.py b/docker/transport/npipeconn.py
index 917fa8b..017738e 100644
--- a/docker/transport/npipeconn.py
+++ b/docker/transport/npipeconn.py
@@ -14,7 +14,6 @@ try:
except ImportError:
import urllib3
-
RecentlyUsedContainer = urllib3._collections.RecentlyUsedContainer
@@ -46,6 +45,28 @@ class NpipeHTTPConnectionPool(urllib3.connectionpool.HTTPConnectionPool):
self.npipe_path, self.timeout
)
+ # When re-using connections, urllib3 tries to call select() on our
+ # NpipeSocket instance, causing a crash. To circumvent this, we override
+ # _get_conn, where that check happens.
+ def _get_conn(self, timeout):
+ conn = None
+ try:
+ conn = self.pool.get(block=self.block, timeout=timeout)
+
+ except AttributeError: # self.pool is None
+ raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.")
+
+ except six.moves.queue.Empty:
+ if self.block:
+ raise urllib3.exceptions.EmptyPoolError(
+ self,
+ "Pool reached maximum size and no more "
+ "connections are allowed."
+ )
+ pass # Oh well, we'll create a new connection then
+
+ return conn or self._new_conn()
+
class NpipeAdapter(requests.adapters.HTTPAdapter):
def __init__(self, base_url, timeout=60,
diff --git a/docker/transport/npipesocket.py b/docker/transport/npipesocket.py
index 9010ceb..3b1b644 100644
--- a/docker/transport/npipesocket.py
+++ b/docker/transport/npipesocket.py
@@ -1,12 +1,15 @@
import functools
import io
+import six
import win32file
import win32pipe
+cERROR_PIPE_BUSY = 0xe7
cSECURITY_SQOS_PRESENT = 0x100000
cSECURITY_ANONYMOUS = 0
-cPIPE_READMODE_MESSAGE = 2
+
+RETRY_WAIT_TIMEOUT = 10000
def check_closed(f):
@@ -44,15 +47,27 @@ class NpipeSocket(object):
@check_closed
def connect(self, address):
win32pipe.WaitNamedPipe(address, self._timeout)
- handle = win32file.CreateFile(
- address,
- win32file.GENERIC_READ | win32file.GENERIC_WRITE,
- 0,
- None,
- win32file.OPEN_EXISTING,
- cSECURITY_ANONYMOUS | cSECURITY_SQOS_PRESENT,
- 0
- )
+ try:
+ handle = win32file.CreateFile(
+ address,
+ win32file.GENERIC_READ | win32file.GENERIC_WRITE,
+ 0,
+ None,
+ win32file.OPEN_EXISTING,
+ cSECURITY_ANONYMOUS | cSECURITY_SQOS_PRESENT,
+ 0
+ )
+ except win32pipe.error as e:
+ # See Remarks:
+ # https://msdn.microsoft.com/en-us/library/aa365800.aspx
+ if e.winerror == cERROR_PIPE_BUSY:
+ # Another program or thread has grabbed our pipe instance
+ # before we got to it. Wait for availability and attempt to
+ # connect again.
+ win32pipe.WaitNamedPipe(address, RETRY_WAIT_TIMEOUT)
+ return self.connect(address)
+ raise e
+
self.flags = win32pipe.GetNamedPipeInfo(handle)[0]
self._handle = handle
@@ -94,7 +109,7 @@ class NpipeSocket(object):
if mode.strip('b') != 'r':
raise NotImplementedError()
rawio = NpipeFileIOBase(self)
- if bufsize is None or bufsize < 0:
+ if bufsize is None or bufsize <= 0:
bufsize = io.DEFAULT_BUFFER_SIZE
return io.BufferedReader(rawio, buffer_size=bufsize)
@@ -114,6 +129,9 @@ class NpipeSocket(object):
@check_closed
def recv_into(self, buf, nbytes=0):
+ if six.PY2:
+ return self._recv_into_py2(buf, nbytes)
+
readbuf = buf
if not isinstance(buf, memoryview):
readbuf = memoryview(buf)
@@ -124,6 +142,12 @@ class NpipeSocket(object):
)
return len(data)
+ def _recv_into_py2(self, buf, nbytes):
+ err, data = win32file.ReadFile(self._handle, nbytes or len(buf))
+ n = len(data)
+ buf[:n] = data
+ return n
+
@check_closed
def send(self, string, flags=0):
err, nbytes = win32file.WriteFile(self._handle, string)
@@ -145,13 +169,16 @@ class NpipeSocket(object):
def settimeout(self, value):
if value is None:
- self._timeout = win32pipe.NMPWAIT_NOWAIT
+ # Blocking mode
+ self._timeout = win32pipe.NMPWAIT_WAIT_FOREVER
elif not isinstance(value, (float, int)) or value < 0:
raise ValueError('Timeout value out of range')
elif value == 0:
- self._timeout = win32pipe.NMPWAIT_USE_DEFAULT_WAIT
+ # Non-blocking mode
+ self._timeout = win32pipe.NMPWAIT_NO_WAIT
else:
- self._timeout = value
+ # Timeout mode - Value converted to milliseconds
+ self._timeout = value * 1000
def gettimeout(self):
return self._timeout
diff --git a/docker/types/services.py b/docker/types/services.py
index 8488d6e..063779c 100644
--- a/docker/types/services.py
+++ b/docker/types/services.py
@@ -152,7 +152,7 @@ class UpdateConfig(dict):
class RestartConditionTypesEnum(object):
_values = (
'none',
- 'on_failure',
+ 'on-failure',
'any',
)
NONE, ON_FAILURE, ANY = _values
diff --git a/docker/utils/socket.py b/docker/utils/socket.py
index ed34350..164b845 100644
--- a/docker/utils/socket.py
+++ b/docker/utils/socket.py
@@ -5,6 +5,11 @@ import struct
import six
+try:
+ from ..transport import NpipeSocket
+except ImportError:
+ NpipeSocket = type(None)
+
class SocketError(Exception):
pass
@@ -14,10 +19,12 @@ def read(socket, n=4096):
"""
Reads at most n bytes from socket
"""
+
recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)
# wait for data to become available
- select.select([socket], [], [])
+ if not isinstance(socket, NpipeSocket):
+ select.select([socket], [], [])
try:
if hasattr(socket, 'recv'):
diff --git a/docker/utils/utils.py b/docker/utils/utils.py
index d46f8fc..8d55b57 100644
--- a/docker/utils/utils.py
+++ b/docker/utils/utils.py
@@ -194,8 +194,8 @@ def match_path(path, pattern):
if pattern:
pattern = os.path.relpath(pattern)
- pattern_components = pattern.split('/')
- path_components = path.split('/')[:len(pattern_components)]
+ pattern_components = pattern.split(os.path.sep)
+ path_components = path.split(os.path.sep)[:len(pattern_components)]
return fnmatch('/'.join(path_components), pattern)
@@ -438,8 +438,8 @@ def parse_host(addr, is_win32=False, tls=False):
"Bind address needs a port: {0}".format(addr))
if proto == "http+unix" or proto == 'npipe':
- return "{0}://{1}".format(proto, host)
- return "{0}://{1}:{2}{3}".format(proto, host, port, path)
+ return "{0}://{1}".format(proto, host).rstrip('/')
+ return "{0}://{1}:{2}{3}".format(proto, host, port, path).rstrip('/')
def parse_devices(devices):
@@ -986,6 +986,9 @@ def format_environment(environment):
def format_env(key, value):
if value is None:
return key
+ if isinstance(value, six.binary_type):
+ value = value.decode('utf-8')
+
return u'{key}={value}'.format(key=key, value=value)
return [format_env(*var) for var in six.iteritems(environment)]
diff --git a/docker/version.py b/docker/version.py
index 2bf8436..27d014c 100644
--- a/docker/version.py
+++ b/docker/version.py
@@ -1,2 +1,2 @@
-version = "1.10.3"
+version = "1.10.6"
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])