summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--docker/client.py20
-rw-r--r--pytest.ini2
-rw-r--r--tests/Dockerfile-dind-certs20
-rw-r--r--tests/integration_test.py73
5 files changed, 123 insertions, 12 deletions
diff --git a/Makefile b/Makefile
index 30421e5..c051bac 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,10 @@ build:
build-py3:
docker build -t docker-py3 -f Dockerfile-py3 .
-test: flake8 unit-test unit-test-py3 integration-dind
+build-dind-certs:
+ docker build -t dpy-dind-certs -f tests/Dockerfile-dind-certs .
+
+test: flake8 unit-test unit-test-py3 integration-dind integration-dind-ssl
unit-test: build
docker run docker-py py.test tests/test.py tests/utils_test.py
@@ -26,10 +29,17 @@ integration-test-py3: build-py3
docker run -v /var/run/docker.sock:/var/run/docker.sock docker-py3 py.test tests/integration_test.py
integration-dind: build build-py3
- docker run -d --name dpy-dind --privileged dockerswarm/dind:1.8.1 docker -d -H tcp://0.0.0.0:2375
- docker run --env="DOCKER_HOST=tcp://docker:2375" --link=dpy-dind:docker docker-py py.test tests/integration_test.py
- docker run --env="DOCKER_HOST=tcp://docker:2375" --link=dpy-dind:docker docker-py3 py.test tests/integration_test.py
+ docker run -d --name dpy-dind --env="DOCKER_HOST=tcp://localhost:2375" --privileged dockerswarm/dind:1.8.1 docker -d -H tcp://0.0.0.0:2375
+ docker run --volumes-from dpy-dind --env="DOCKER_HOST=tcp://docker:2375" --link=dpy-dind:docker docker-py py.test tests/integration_test.py
+ docker run --volumes-from dpy-dind --env="DOCKER_HOST=tcp://docker:2375" --link=dpy-dind:docker docker-py3 py.test tests/integration_test.py
docker rm -vf dpy-dind
+integration-dind-ssl: build-dind-certs build build-py3
+ docker run -d --name dpy-dind-certs dpy-dind-certs
+ docker run -d --env="DOCKER_HOST=tcp://localhost:2375" --env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --volumes-from dpy-dind-certs --name dpy-dind-ssl -v /tmp --privileged dockerswarm/dind:1.8.1 docker daemon --tlsverify --tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem --tlskey=/certs/server-key.pem -H tcp://0.0.0.0:2375
+ docker run --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --link=dpy-dind-ssl:docker docker-py py.test tests/integration_test.py
+ docker run --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --link=dpy-dind-ssl:docker docker-py3 py.test tests/integration_test.py
+ docker rm -vf dpy-dind-ssl dpy-dind-certs
+
flake8: build
- docker run docker-py flake8 docker tests \ No newline at end of file
+ docker run docker-py flake8 docker tests
diff --git a/docker/client.py b/docker/client.py
index d219472..d339f3b 100644
--- a/docker/client.py
+++ b/docker/client.py
@@ -188,6 +188,8 @@ class Client(
self._raise_for_status(response)
if six.PY3:
sock = response.raw._fp.fp.raw
+ if self.base_url.startswith("https://"):
+ sock = sock._sock
else:
sock = response.raw._fp.fp._sock
try:
@@ -244,10 +246,7 @@ class Client(
# Disable timeout on the underlying socket to prevent
# Read timed out(s) for long running processes
socket = self._get_raw_response_socket(response)
- if six.PY3:
- socket._sock.settimeout(None)
- else:
- socket.settimeout(None)
+ self._disable_socket_timeout(socket)
while True:
header = response.raw.read(constants.STREAM_HEADER_SIZE_BYTES)
@@ -276,6 +275,19 @@ class Client(
for out in response.iter_content(chunk_size=1, decode_unicode=True):
yield out
+ def _disable_socket_timeout(self, socket):
+ """ Depending on the combination of python version and whether we're
+ connecting over http or https, we might need to access _sock, which
+ may or may not exist; or we may need to just settimeout on socket
+ itself, which also may or may not have settimeout on it.
+
+ To avoid missing the correct one, we try both.
+ """
+ if hasattr(socket, "settimeout"):
+ socket.settimeout(None)
+ if hasattr(socket, "_sock") and hasattr(socket._sock, "settimeout"):
+ socket._sock.settimeout(None)
+
def _get_result(self, container, stream, res):
cont = self.inspect_container(container)
return self._get_result_tty(stream, res, cont['Config']['Tty'])
diff --git a/pytest.ini b/pytest.ini
index 21b47a6..f9c7990 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,2 +1,2 @@
[pytest]
-addopts = --tb=short -rxs
+addopts = --tb=short -rxs -s
diff --git a/tests/Dockerfile-dind-certs b/tests/Dockerfile-dind-certs
new file mode 100644
index 0000000..9e8c042
--- /dev/null
+++ b/tests/Dockerfile-dind-certs
@@ -0,0 +1,20 @@
+FROM python:2.7
+RUN mkdir /tmp/certs
+VOLUME /certs
+
+WORKDIR /tmp/certs
+RUN openssl genrsa -aes256 -passout pass:foobar -out ca-key.pem 4096
+RUN echo "[req]\nprompt=no\ndistinguished_name = req_distinguished_name\n[req_distinguished_name]\ncountryName=AU" > /tmp/config
+RUN openssl req -new -x509 -passin pass:foobar -config /tmp/config -days 365 -key ca-key.pem -sha256 -out ca.pem
+RUN openssl genrsa -out server-key.pem -passout pass:foobar 4096
+RUN openssl req -subj "/CN=docker" -sha256 -new -key server-key.pem -out server.csr
+RUN echo subjectAltName = DNS:docker,DNS:localhost > extfile.cnf
+RUN openssl x509 -req -days 365 -passin pass:foobar -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
+RUN openssl genrsa -out key.pem 4096
+RUN openssl req -passin pass:foobar -subj '/CN=client' -new -key key.pem -out client.csr
+RUN echo extendedKeyUsage = clientAuth > extfile.cnf
+RUN openssl x509 -req -passin pass:foobar -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf
+RUN chmod -v 0400 ca-key.pem key.pem server-key.pem
+RUN chmod -v 0444 ca.pem server-cert.pem cert.pem
+
+CMD cp -R /tmp/certs/* /certs && while true; do sleep 1; done
diff --git a/tests/integration_test.py b/tests/integration_test.py
index 8a92708..c264a40 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -14,6 +14,7 @@
import base64
import contextlib
+import errno
import json
import io
import os
@@ -21,6 +22,7 @@ import random
import shutil
import signal
import socket
+import struct
import tarfile
import tempfile
import threading
@@ -76,7 +78,17 @@ def setup_module():
try:
c.inspect_image(BUSYBOX)
except NotFound:
- c.pull(BUSYBOX)
+ os.write(2, "\npulling busybox\n".encode('utf-8'))
+ for data in c.pull('busybox', stream=True):
+ data = json.loads(data.decode('utf-8'))
+ os.write(2, ("%c[2K\r" % 27).encode('utf-8'))
+ status = data.get("status")
+ progress = data.get("progress")
+ detail = "{0} - {1}".format(status, progress).encode('utf-8')
+ os.write(2, detail)
+ os.write(2, "\npulled busybox\n".encode('utf-8'))
+
+ # Double make sure we now have busybox
c.inspect_image(BUSYBOX)
c.close()
@@ -887,7 +899,6 @@ class TestContainerTop(BaseTestCase):
self.client.start(container)
res = self.client.top(container['Id'])
- print(res)
self.assertEqual(
res['Titles'],
['UID', 'PID', 'PPID', 'C', 'STIME', 'TTY', 'TIME', 'CMD']
@@ -1213,6 +1224,64 @@ class TestRunContainerStreaming(BaseTestCase):
self.assertTrue(sock.fileno() > -1)
+class TestRunContainerReadingSocket(BaseTestCase):
+ def runTest(self):
+ line = 'hi there and stuff and things, words!'
+ command = "echo '{0}'".format(line)
+ container = self.client.create_container(BUSYBOX, command,
+ detach=True, tty=False)
+ ident = container['Id']
+ self.tmp_containers.append(ident)
+
+ opts = {"stdout": 1, "stream": 1, "logs": 1}
+ pty_stdout = self.client.attach_socket(ident, opts)
+ self.client.start(ident)
+
+ recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK)
+
+ def read(n=4096):
+ """Code stolen from dockerpty to read the socket"""
+ try:
+ if hasattr(pty_stdout, 'recv'):
+ return pty_stdout.recv(n)
+ return os.read(pty_stdout.fileno(), n)
+ except EnvironmentError as e:
+ if e.errno not in recoverable_errors:
+ raise
+
+ def next_packet_size():
+ """Code stolen from dockerpty to get the next packet size"""
+ data = six.binary_type()
+ while len(data) < 8:
+ next_data = read(8 - len(data))
+ if not next_data:
+ return 0
+ data = data + next_data
+
+ if data is None:
+ return 0
+
+ if len(data) == 8:
+ _, actual = struct.unpack('>BxxxL', data)
+ return actual
+
+ next_size = next_packet_size()
+ self.assertEqual(next_size, len(line)+1)
+
+ data = six.binary_type()
+ while len(data) < next_size:
+ next_data = read(next_size - len(data))
+ if not next_data:
+ assert False, "Failed trying to read in the dataz"
+ data += next_data
+ self.assertEqual(data.decode('utf-8'), "{0}\n".format(line))
+ pty_stdout.close()
+
+ # Prevent segfault at the end of the test run
+ if hasattr(pty_stdout, "_response"):
+ del pty_stdout._response
+
+
class TestPauseUnpauseContainer(BaseTestCase):
def runTest(self):
container = self.client.create_container(BUSYBOX, ['sleep', '9999'])