Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions docker/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
import re
import shlex
import struct
import os

import requests
import requests.exceptions
import six

from .auth import auth
from .unixconn import unixconn
from .ssladapter import ssladapter
from .utils import utils
from .exceptions import exceptions

if not six.PY3:
import websocket
Expand Down Expand Up @@ -69,9 +72,20 @@ def is_server_error(self):


class Client(requests.Session):
def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
timeout=DEFAULT_TIMEOUT_SECONDS):
def __init__(self,
base_url=None,
version=DEFAULT_DOCKER_API_VERSION,
timeout=DEFAULT_TIMEOUT_SECONDS,
tls=False,
tls_cert=None,
tls_key=None,
tls_verify=False,
tls_ca_cert=None,
ssl_version=None):
super(Client, self).__init__()

if (tls or tls_verify) and not base_url.startswith('https://'):
raise exceptions.TLSParameterError('If using TLS, the base_url argument must begin with "https://".')
if base_url is None:
base_url = "http+unix://var/run/docker.sock"
if 'unix:///' in base_url:
Expand All @@ -87,7 +101,46 @@ def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
self._timeout = timeout
self._auth_configs = auth.load_config()

self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout))
""" Argument compatibility/mapping with http://docs.docker.io/examples/https/

This diverges from the Docker CLI in that users can specify 'tls' here, but also
disable any public/default CA pool verification by leaving tls_verify=False
"""
""" urllib3 sets a default ssl_version if ssl_version is None
https://github.com/shazow/urllib3/blob/62ecd1523ec383802cb13b09bd7084d2da997420/urllib3/util/ssl_.py#L83
"""
self.ssl_version = ssl_version

""" "tls" and "tls_verify" must have both or neither cert/key files
In either case, Alert the user when both are expected, but any are missing."""
if (tls or tls_verify) and (tls_cert or tls_key):
if not (tls_cert and tls_key) or (not os.path.isfile(tls_cert) or not os.path.isfile(tls_key)):
raise exceptions.TLSParameterError(
'You must provide either both "tls_cert"/"tls_key" files, or neither, in order to use TLS.')
else:
self.cert = (tls_cert, tls_key)

"""
Either set tls_verify to True (public/default CA checks) or to the path of a CA Cert file.
ref: https://github.com/kennethreitz/requests/blob/739d153ef77765392fa109bebead4260c05f3193/requests/adapters.py#L135-L137
ref: https://github.com/kennethreitz/requests/blob/master/requests/sessions.py#L433-L439
"""
if tls_verify:
if not tls_ca_cert:
self.verify = True
elif os.path.isfile(tls_ca_cert):
self.verify = tls_ca_cert
else:
raise exceptions.TLSParameterError(
'If "tls_verify" is set, then "tls_ca_cert" must be blank (to check default/public CA list) OR a path to a CA Cert File.')
else:
self.verify = False

""" Use SSLAdapter for the ability to specify SSL version """
if tls or tls_verify:
self.mount('https://', ssladapter.SSLAdapter(self.ssl_version))
else:
self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout))

def _set_request_timeout(self, kwargs):
"""Prepare the kwargs for an HTTP request by inserting the timeout
Expand Down
1 change: 1 addition & 0 deletions docker/exceptions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .exceptions import TLSParameterError
6 changes: 6 additions & 0 deletions docker/exceptions/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class TLSParameterError(ValueError):
def __init__(self, msg):
self.msg = msg

def __str__(self):
return self.msg + "\n\nTLS configurations should map the Docker CLI client configurations. See http://docs.docker.io/examples/https/ for API details."
1 change: 1 addition & 0 deletions docker/ssladapter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .ssladapter import SSLAdapter
23 changes: 23 additions & 0 deletions docker/ssladapter/ssladapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
""" Resolves OpenSSL issues in some servers:
https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/
https://github.com/kennethreitz/requests/pull/799
"""
from requests.adapters import HTTPAdapter
try:
from requests.packages.urllib3.poolmanager import PoolManager
except ImportError:
from urllib3.poolmanager import PoolManager


class SSLAdapter(HTTPAdapter):
'''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
def __init__(self, ssl_version=None, **kwargs):
self.ssl_version = ssl_version

super(SSLAdapter, self).__init__(**kwargs)

def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(num_pools=connections,
maxsize=maxsize,
block=block,
ssl_version=self.ssl_version)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
name="docker-py",
version='0.3.0',
description="Python client for Docker.",
packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils'],
packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils', 'docker.ssladapter', 'docker.exceptions'],
install_requires=requirements + test_requirements,
zip_safe=False,
test_suite='tests',
Expand Down