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
6 changes: 3 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def images = [:]

// Note: Swarm in dind seem notoriously flimsy with 1.12.1+, which is why we're
// sticking with 1.12.0 for the 1.12 series
def dockerVersions = ["1.12.0", "1.13.1"]
def dockerVersions = ["1.12.0", "1.13.1", "17.04.0-ce-rc1"]

def buildImage = { name, buildargs, pyTag ->
img = docker.image(name)
Expand Down Expand Up @@ -35,8 +35,8 @@ def buildImages = { ->
}

def getAPIVersion = { engineVersion ->
def versionMap = ['1.12': '1.24', '1.13': '1.26']
return versionMap[engineVersion.substring(0, 4)]
def versionMap = ['1.12.': '1.24', '1.13.': '1.26', '17.04': '1.27']
return versionMap[engineVersion.substring(0, 5)]
}

def runTests = { Map settings ->
Expand Down
15 changes: 9 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@ integration-test: build
integration-test-py3: build-py3
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python3 py.test tests/integration/${file}

TEST_API_VERSION ?= 1.27
TEST_ENGINE_VERSION ?= 17.04.0-ce-rc1

.PHONY: integration-dind
integration-dind: build build-py3
docker rm -vf dpy-dind || :
docker run -d --name dpy-dind --privileged dockerswarm/dind:1.13.1 docker daemon\
docker run -d --name dpy-dind --privileged dockerswarm/dind:${TEST_ENGINE_VERSION} docker daemon\
-H tcp://0.0.0.0:2375 --experimental
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=1.26"\
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
--link=dpy-dind:docker docker-sdk-python py.test tests/integration
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=1.26"\
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
--link=dpy-dind:docker docker-sdk-python3 py.test tests/integration
docker rm -vf dpy-dind

Expand All @@ -57,14 +60,14 @@ 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.13.1 docker daemon --tlsverify\
-v /tmp --privileged dockerswarm/dind:${TEST_ENGINE_VERSION} docker daemon --tlsverify\
--tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem\
--tlskey=/certs/server-key.pem -H tcp://0.0.0.0:2375 --experimental
docker run --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=1.26"\
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
--link=dpy-dind-ssl:docker docker-sdk-python py.test tests/integration
docker run --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=1.26"\
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\
--link=dpy-dind-ssl:docker docker-sdk-python3 py.test tests/integration
docker rm -vf dpy-dind-ssl dpy-dind-certs

Expand Down
12 changes: 12 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: '{branch}-{build}'

install:
- "SET PATH=C:\\Python27-x64;C:\\Python27-x64\\Scripts;%PATH%"
- "python --version"
- "pip install tox==2.1.1 virtualenv==13.1.2"

# Build the binary after tests
build: false

test_script:
- "tox"
2 changes: 1 addition & 1 deletion docker/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class APIClient(
base_url (str): URL to the Docker server. For example,
``unix:///var/run/docker.sock`` or ``tcp://127.0.0.1:1234``.
version (str): The version of the API to use. Set to ``auto`` to
automatically detect the server's version. Default: ``1.24``
automatically detect the server's version. Default: ``1.26``
timeout (int): Default timeout for API calls, in seconds.
tls (bool or :py:class:`~docker.tls.TLSConfig`): Enable TLS. Pass
``True`` to enable it with default options, or pass a
Expand Down
4 changes: 2 additions & 2 deletions docker/api/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,8 @@ def create_host_config(self, *args, **kwargs):
cap_add (list of str): Add kernel capabilities. For example,
``["SYS_ADMIN", "MKNOD"]``.
cap_drop (list of str): Drop kernel capabilities.
cpu_group (int): The length of a CPU period in microseconds.
cpu_period (int): Microseconds of CPU time that the container can
cpu_period (int): The length of a CPU period in microseconds.
cpu_quota (int): Microseconds of CPU time that the container can
get in a CPU period.
cpu_shares (int): CPU shares (relative weight).
cpuset_cpus (str): CPUs in which to allow execution (``0-3``,
Expand Down
3 changes: 2 additions & 1 deletion docker/api/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ def events(self, since=None, until=None, filters=None, decode=None):
'until': until,
'filters': filters
}
url = self._url('/events')

return self._stream_helper(
self._get(self._url('/events'), params=params, stream=True),
self._get(url, params=params, stream=True, timeout=None),
decode=decode
)

Expand Down
12 changes: 10 additions & 2 deletions docker/api/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,23 @@ def remove_network(self, net_id):
self._raise_for_status(res)

@minimum_version('1.21')
def inspect_network(self, net_id):
def inspect_network(self, net_id, verbose=None):
"""
Get detailed information about a network.

Args:
net_id (str): ID of network
verbose (bool): Show the service details across the cluster in
swarm mode.
"""
params = {}
if verbose is not None:
if version_lt(self._version, '1.28'):
raise InvalidVersion('verbose was introduced in API 1.28')
params['verbose'] = verbose

url = self._url("/networks/{0}", net_id)
res = self._get(url)
res = self._get(url, params=params)
return self._result(res, json=True)

@check_resource
Expand Down
4 changes: 2 additions & 2 deletions docker/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class DockerClient(object):
base_url (str): URL to the Docker server. For example,
``unix:///var/run/docker.sock`` or ``tcp://127.0.0.1:1234``.
version (str): The version of the API to use. Set to ``auto`` to
automatically detect the server's version. Default: ``1.24``
automatically detect the server's version. Default: ``1.26``
timeout (int): Default timeout for API calls, in seconds.
tls (bool or :py:class:`~docker.tls.TLSConfig`): Enable TLS. Pass
``True`` to enable it with default options, or pass a
Expand Down Expand Up @@ -58,7 +58,7 @@ def from_env(cls, **kwargs):

Args:
version (str): The version of the API to use. Set to ``auto`` to
automatically detect the server's version. Default: ``1.24``
automatically detect the server's version. Default: ``1.26``
timeout (int): Default timeout for API calls, in seconds.
ssl_version (int): A valid `SSL version`_.
assert_hostname (bool): Verify the hostname of the server.
Expand Down
2 changes: 1 addition & 1 deletion docker/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def __str__(self):

@property
def status_code(self):
if self.response:
if self.response is not None:
return self.response.status_code

def is_client_error(self):
Expand Down
16 changes: 10 additions & 6 deletions docker/models/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,10 +456,13 @@ def run(self, image, command=None, stdout=True, stderr=False,
cap_add (list of str): Add kernel capabilities. For example,
``["SYS_ADMIN", "MKNOD"]``.
cap_drop (list of str): Drop kernel capabilities.
cpu_group (int): The length of a CPU period in microseconds.
cpu_period (int): Microseconds of CPU time that the container can
cpu_count (int): CPU count (Windows only).
cpu_quota (int): Microseconds of CPU time that the container can
get in a CPU period.
cpu_percent (int): CPU percent (Windows only).
cpu_period (int): The length of a CPU period in microseconds.
cpu_shares (int): CPU shares (relative weight).
cpus (float): Number of CPUs.
cpuset_cpus (str): CPUs in which to allow execution (``0-3``,
``0,1``).
detach (bool): Run container in the background and return a
Expand Down Expand Up @@ -510,14 +513,12 @@ def run(self, image, command=None, stdout=True, stderr=False,
driver.

mac_address (str): MAC address to assign to the container.
mem_limit (float or str): Memory limit. Accepts float values
mem_limit (int or str): Memory limit. Accepts float values
(which represent the memory limit of the created container in
bytes) or a string with a units identification char
(``100000b``, ``1000k``, ``128m``, ``1g``). If a string is
specified without a units character, bytes are assumed as an
intended unit.
mem_limit (str or int): Maximum amount of memory container is
allowed to consume. (e.g. ``1G``).
mem_swappiness (int): Tune a container's memory swappiness
behavior. Accepts number between 0 and 100.
memswap_limit (str or int): Maximum amount of memory + swap a
Expand Down Expand Up @@ -585,7 +586,7 @@ def run(self, image, command=None, stdout=True, stderr=False,
stdin_open (bool): Keep ``STDIN`` open even if not attached.
stdout (bool): Return logs from ``STDOUT`` when ``detach=False``.
Default: ``True``.
stdout (bool): Return logs from ``STDERR`` when ``detach=False``.
stderr (bool): Return logs from ``STDERR`` when ``detach=False``.
Default: ``False``.
stop_signal (str): The stop signal to use to stop the container
(e.g. ``SIGINT``).
Expand Down Expand Up @@ -803,9 +804,12 @@ def prune(self, filters=None):
'cap_add',
'cap_drop',
'cgroup_parent',
'cpu_count',
'cpu_percent',
'cpu_period',
'cpu_quota',
'cpu_shares',
'cpus',
'cpuset_cpus',
'device_read_bps',
'device_read_iops',
Expand Down
116 changes: 77 additions & 39 deletions docker/types/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def __init__(self, version, binds=None, port_bindings=None,
tmpfs=None, oom_score_adj=None, dns_opt=None, cpu_shares=None,
cpuset_cpus=None, userns_mode=None, pids_limit=None,
isolation=None, auto_remove=False, storage_opt=None,
init=None, init_path=None):
init=None, init_path=None, volume_driver=None,
cpu_count=None, cpu_percent=None, cpus=None):

if mem_limit is not None:
self['Memory'] = parse_bytes(mem_limit)
Expand Down Expand Up @@ -428,6 +429,35 @@ def __init__(self, version, binds=None, port_bindings=None,
raise host_config_version_error('init_path', '1.25')
self['InitPath'] = init_path

if volume_driver is not None:
if version_lt(version, '1.21'):
raise host_config_version_error('volume_driver', '1.21')
self['VolumeDriver'] = volume_driver
if cpu_count:
if not isinstance(cpu_count, int):
raise host_config_type_error('cpu_count', cpu_count, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('cpu_count', '1.25')

self['CpuCount'] = cpu_count

if cpu_percent:
if not isinstance(cpu_percent, int):
raise host_config_type_error('cpu_percent', cpu_percent, 'int')
if version_lt(version, '1.25'):
raise host_config_version_error('cpu_percent', '1.25')

self['CpuPercent'] = cpu_percent

if cpus:
if not isinstance(cpus, (float, int)):
raise host_config_type_error('cpus', cpus, 'float')
if version_lt(version, '1.25'):
raise host_config_version_error('cpus', '1.25')

self['NanoCpus'] = int(1000000000 * cpus)



def host_config_type_error(param, param_value, expected):
error_msg = 'Invalid type for {0} param: expected {1} but found {2}'
Expand Down Expand Up @@ -456,43 +486,27 @@ def __init__(
stop_signal=None, networking_config=None, healthcheck=None,
stop_timeout=None
):
if isinstance(command, six.string_types):
command = split_command(command)

if isinstance(entrypoint, six.string_types):
entrypoint = split_command(entrypoint)

if isinstance(environment, dict):
environment = format_environment(environment)

if labels is not None and version_lt(version, '1.18'):
raise errors.InvalidVersion(
'labels were only introduced in API version 1.18'
)
if version_gte(version, '1.10'):
message = ('{0!r} parameter has no effect on create_container().'
' It has been moved to host_config')
if dns is not None:
raise errors.InvalidVersion(message.format('dns'))
if volumes_from is not None:
raise errors.InvalidVersion(message.format('volumes_from'))

if cpuset is not None or cpu_shares is not None:
if version_gte(version, '1.18'):
if version_lt(version, '1.18'):
if labels is not None:
raise errors.InvalidVersion(
'labels were only introduced in API version 1.18'
)
else:
if cpuset is not None or cpu_shares is not None:
warnings.warn(
'The cpuset_cpus and cpu_shares options have been moved to'
' host_config in API version 1.18, and will be removed',
DeprecationWarning
)

if stop_signal is not None and version_lt(version, '1.21'):
raise errors.InvalidVersion(
'stop_signal was only introduced in API version 1.21'
)

if stop_timeout is not None and version_lt(version, '1.25'):
raise errors.InvalidVersion(
'stop_timeout was only introduced in API version 1.25'
)

if healthcheck is not None and version_lt(version, '1.24'):
raise errors.InvalidVersion(
'Health options were only introduced in API version 1.24'
)

if version_lt(version, '1.19'):
if volume_driver is not None:
raise errors.InvalidVersion(
Expand All @@ -513,6 +527,38 @@ def __init__(
'version 1.19'
)

if version_lt(version, '1.21'):
if stop_signal is not None:
raise errors.InvalidVersion(
'stop_signal was only introduced in API version 1.21'
)
else:
if volume_driver is not None:
warnings.warn(
'The volume_driver option has been moved to'
' host_config in API version 1.21, and will be removed',
DeprecationWarning
)

if stop_timeout is not None and version_lt(version, '1.25'):
raise errors.InvalidVersion(
'stop_timeout was only introduced in API version 1.25'
)

if healthcheck is not None and version_lt(version, '1.24'):
raise errors.InvalidVersion(
'Health options were only introduced in API version 1.24'
)

if isinstance(command, six.string_types):
command = split_command(command)

if isinstance(entrypoint, six.string_types):
entrypoint = split_command(entrypoint)

if isinstance(environment, dict):
environment = format_environment(environment)

if isinstance(labels, list):
labels = dict((lbl, six.text_type('')) for lbl in labels)

Expand Down Expand Up @@ -566,14 +612,6 @@ def __init__(
attach_stdin = True
stdin_once = True

if version_gte(version, '1.10'):
message = ('{0!r} parameter has no effect on create_container().'
' It has been moved to host_config')
if dns is not None:
raise errors.InvalidVersion(message.format('dns'))
if volumes_from is not None:
raise errors.InvalidVersion(message.format('volumes_from'))

self.update({
'Hostname': hostname,
'Domainname': domainname,
Expand Down
10 changes: 7 additions & 3 deletions docker/utils/build.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os

from ..constants import IS_WINDOWS_PLATFORM
from .fnmatch import fnmatch
from .utils import create_archive

Expand Down Expand Up @@ -39,7 +40,7 @@ def exclude_paths(root, patterns, dockerfile=None):
# If the Dockerfile is in a subdirectory that is excluded, get_paths
# will not descend into it and the file will be skipped. This ensures
# it doesn't happen.
set([dockerfile])
set([dockerfile.replace('/', os.path.sep)])
if os.path.exists(os.path.join(root, dockerfile)) else set()
)

Expand Down Expand Up @@ -130,9 +131,12 @@ def match_path(path, pattern):
if pattern:
pattern = os.path.relpath(pattern)

pattern_components = pattern.split(os.path.sep)
if len(pattern_components) == 1 and IS_WINDOWS_PLATFORM:
pattern_components = pattern.split('/')

if '**' not in pattern:
pattern_components = pattern.split(os.path.sep)
path_components = path.split(os.path.sep)[:len(pattern_components)]
else:
path_components = path.split(os.path.sep)
return fnmatch('/'.join(path_components), pattern)
return fnmatch('/'.join(path_components), '/'.join(pattern_components))
Loading