Kaydet (Commit) 116d1370 authored tarafından Joffrey F's avatar Joffrey F

* Merge branch 'tls' of github.com:momer/docker-py into momer-tls

* Exported TLS configuration in tls.TLSConfig
* Merged exceptions packagee into pre-existing errors module
* Flake8 fixes
* Bug fixes
...@@ -24,8 +24,10 @@ import six ...@@ -24,8 +24,10 @@ import six
from .auth import auth from .auth import auth
from .unixconn import unixconn from .unixconn import unixconn
from .ssladapter import ssladapter
from .utils import utils from .utils import utils
from . import errors from . import errors
from .tls import TLSConfig
if not six.PY3: if not six.PY3:
import websocket import websocket
...@@ -37,10 +39,15 @@ STREAM_HEADER_SIZE_BYTES = 8 ...@@ -37,10 +39,15 @@ STREAM_HEADER_SIZE_BYTES = 8
class Client(requests.Session): class Client(requests.Session):
def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION, def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
timeout=DEFAULT_TIMEOUT_SECONDS): timeout=DEFAULT_TIMEOUT_SECONDS, tls=False):
super(Client, self).__init__() super(Client, self).__init__()
if base_url is None: if base_url is None:
base_url = "http+unix://var/run/docker.sock" base_url = "http+unix://var/run/docker.sock"
if tls and not base_url.startswith('https://'):
raise errors.TLSParameterError(
'If using TLS, the base_url argument must begin with '
'"https://".')
if 'unix:///' in base_url: if 'unix:///' in base_url:
base_url = base_url.replace('unix:/', 'unix:') base_url = base_url.replace('unix:/', 'unix:')
if base_url.startswith('unix:'): if base_url.startswith('unix:'):
...@@ -54,6 +61,12 @@ class Client(requests.Session): ...@@ -54,6 +61,12 @@ class Client(requests.Session):
self._timeout = timeout self._timeout = timeout
self._auth_configs = auth.load_config() self._auth_configs = auth.load_config()
""" Use SSLAdapter for the ability to specify SSL version """
if isinstance(tls, TLSConfig):
tls.configure_client(self)
elif tls:
self.mount('https://', ssladapter.SSLAdapter(self.ssl_version))
else:
self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout)) self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout))
def _set_request_timeout(self, kwargs): def _set_request_timeout(self, kwargs):
......
...@@ -63,3 +63,14 @@ class InvalidConfigFile(DockerException): ...@@ -63,3 +63,14 @@ class InvalidConfigFile(DockerException):
class DeprecatedMethod(DockerException): class DeprecatedMethod(DockerException):
pass pass
class TLSParameterError(DockerException):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg + (". TLS configurations should map the Docker CLI "
"client configurations. See "
"http://docs.docker.com/examples/https/ for "
"API details.")
from .ssladapter import SSLAdapter # flake8: noqa
""" 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)
import os
from . import errors
from .ssladapter import ssladapter
class TLSConfig(object):
def __init__(self, tls, tls_cert=None, tls_key=None, tls_verify=False,
tls_ca_cert=None, ssl_version=None):
# Argument compatibility/mapping with
# http://docs.docker.com/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
# http://tinyurl.com/kxga8hb
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_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 errors.TLSParameterError(
'You must provide either both "tls_cert"/"tls_key" files, '
'or neither, in order to use TLS.')
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.
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 errors.TLSParameterError(
'If "tls_verify" is set, then "tls_ca_cert" must be blank'
' (to check public CA list) OR a path to a Cert File.'
)
else:
self.verify = False
def configure_client(self, client):
client.verify = self.verify
client.ssl_version = self.ssl_version
client.cert = self.cert
self.mount('https://', ssladapter.SSLAdapter(self.ssl_version))
...@@ -22,7 +22,8 @@ setup( ...@@ -22,7 +22,8 @@ setup(
name="docker-py", name="docker-py",
version=version, version=version,
description="Python client for Docker.", description="Python client for Docker.",
packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils'], packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils',
'docker.ssladapter'],
install_requires=requirements + test_requirements, install_requires=requirements + test_requirements,
zip_safe=False, zip_safe=False,
test_suite='tests', test_suite='tests',
......
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