Kaydet (Commit) 7f3692ce authored tarafından Stephen Moore's avatar Stephen Moore Kaydeden (comit) Joffrey F

Fix attach method over SSL connections

Signed-off-by: 's avatarStephen Moore <stephen@delfick.com>
üst b1f25317
...@@ -11,7 +11,10 @@ build: ...@@ -11,7 +11,10 @@ build:
build-py3: build-py3:
docker build -t docker-py3 -f Dockerfile-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 unit-test: build
docker run docker-py py.test tests/test.py tests/utils_test.py docker run docker-py py.test tests/test.py tests/utils_test.py
...@@ -26,10 +29,17 @@ integration-test-py3: build-py3 ...@@ -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 docker run -v /var/run/docker.sock:/var/run/docker.sock docker-py3 py.test tests/integration_test.py
integration-dind: build build-py3 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 -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 --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-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 --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 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 flake8: build
docker run docker-py flake8 docker tests docker run docker-py flake8 docker tests
\ No newline at end of file
...@@ -188,6 +188,8 @@ class Client( ...@@ -188,6 +188,8 @@ class Client(
self._raise_for_status(response) self._raise_for_status(response)
if six.PY3: if six.PY3:
sock = response.raw._fp.fp.raw sock = response.raw._fp.fp.raw
if self.base_url.startswith("https://"):
sock = sock._sock
else: else:
sock = response.raw._fp.fp._sock sock = response.raw._fp.fp._sock
try: try:
...@@ -244,10 +246,7 @@ class Client( ...@@ -244,10 +246,7 @@ class Client(
# Disable timeout on the underlying socket to prevent # Disable timeout on the underlying socket to prevent
# Read timed out(s) for long running processes # Read timed out(s) for long running processes
socket = self._get_raw_response_socket(response) socket = self._get_raw_response_socket(response)
if six.PY3: self._disable_socket_timeout(socket)
socket._sock.settimeout(None)
else:
socket.settimeout(None)
while True: while True:
header = response.raw.read(constants.STREAM_HEADER_SIZE_BYTES) header = response.raw.read(constants.STREAM_HEADER_SIZE_BYTES)
...@@ -276,6 +275,19 @@ class Client( ...@@ -276,6 +275,19 @@ class Client(
for out in response.iter_content(chunk_size=1, decode_unicode=True): for out in response.iter_content(chunk_size=1, decode_unicode=True):
yield out 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): def _get_result(self, container, stream, res):
cont = self.inspect_container(container) cont = self.inspect_container(container)
return self._get_result_tty(stream, res, cont['Config']['Tty']) return self._get_result_tty(stream, res, cont['Config']['Tty'])
......
[pytest] [pytest]
addopts = --tb=short -rxs addopts = --tb=short -rxs -s
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
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
import base64 import base64
import contextlib import contextlib
import errno
import json import json
import io import io
import os import os
...@@ -21,6 +22,7 @@ import random ...@@ -21,6 +22,7 @@ import random
import shutil import shutil
import signal import signal
import socket import socket
import struct
import tarfile import tarfile
import tempfile import tempfile
import threading import threading
...@@ -76,7 +78,17 @@ def setup_module(): ...@@ -76,7 +78,17 @@ def setup_module():
try: try:
c.inspect_image(BUSYBOX) c.inspect_image(BUSYBOX)
except NotFound: 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.inspect_image(BUSYBOX)
c.close() c.close()
...@@ -887,7 +899,6 @@ class TestContainerTop(BaseTestCase): ...@@ -887,7 +899,6 @@ class TestContainerTop(BaseTestCase):
self.client.start(container) self.client.start(container)
res = self.client.top(container['Id']) res = self.client.top(container['Id'])
print(res)
self.assertEqual( self.assertEqual(
res['Titles'], res['Titles'],
['UID', 'PID', 'PPID', 'C', 'STIME', 'TTY', 'TIME', 'CMD'] ['UID', 'PID', 'PPID', 'C', 'STIME', 'TTY', 'TIME', 'CMD']
...@@ -1213,6 +1224,64 @@ class TestRunContainerStreaming(BaseTestCase): ...@@ -1213,6 +1224,64 @@ class TestRunContainerStreaming(BaseTestCase):
self.assertTrue(sock.fileno() > -1) 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): class TestPauseUnpauseContainer(BaseTestCase):
def runTest(self): def runTest(self):
container = self.client.create_container(BUSYBOX, ['sleep', '9999']) container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment