Skip to content

Commit 5742774

Browse files
authored
Merge pull request #1463 from docker/2.1.0-release
2.1.0 release
2 parents 6661b7f + 5030a12 commit 5742774

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+2057
-328
lines changed

Jenkinsfile

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ def imageNameBase = "dockerbuildbot/docker-py"
44
def imageNamePy2
55
def imageNamePy3
66
def images = [:]
7-
def dockerVersions = ["1.12.0", "1.13.0-rc3"]
7+
8+
// Note: Swarm in dind seem notoriously flimsy with 1.12.1+, which is why we're
9+
// sticking with 1.12.0 for the 1.12 series
10+
def dockerVersions = ["1.12.0", "1.13.1"]
811

912
def buildImage = { name, buildargs, pyTag ->
1013
img = docker.image(name)
@@ -31,10 +34,16 @@ def buildImages = { ->
3134
}
3235
}
3336

37+
def getAPIVersion = { engineVersion ->
38+
def versionMap = ['1.12': '1.24', '1.13': '1.25']
39+
return versionMap[engineVersion.substring(0, 4)]
40+
}
41+
3442
def runTests = { Map settings ->
3543
def dockerVersion = settings.get("dockerVersion", null)
3644
def pythonVersion = settings.get("pythonVersion", null)
3745
def testImage = settings.get("testImage", null)
46+
def apiVersion = getAPIVersion(dockerVersion)
3847

3948
if (!testImage) {
4049
throw new Exception("Need test image object, e.g.: `runTests(testImage: img)`")
@@ -50,15 +59,16 @@ def runTests = { Map settings ->
5059
wrappedNode(label: "ubuntu && !zfs && amd64", cleanWorkspace: true) {
5160
stage("test python=${pythonVersion} / docker=${dockerVersion}") {
5261
checkout(scm)
53-
def dindContainerName = "dpy-dind-\$BUILD_NUMBER-\$EXECUTOR_NUMBER"
54-
def testContainerName = "dpy-tests-\$BUILD_NUMBER-\$EXECUTOR_NUMBER"
62+
def dindContainerName = "dpy-dind-\$BUILD_NUMBER-\$EXECUTOR_NUMBER-${pythonVersion}-${dockerVersion}"
63+
def testContainerName = "dpy-tests-\$BUILD_NUMBER-\$EXECUTOR_NUMBER-${pythonVersion}-${dockerVersion}"
5564
try {
5665
sh """docker run -d --name ${dindContainerName} -v /tmp --privileged \\
5766
dockerswarm/dind:${dockerVersion} docker daemon -H tcp://0.0.0.0:2375
5867
"""
5968
sh """docker run \\
6069
--name ${testContainerName} --volumes-from ${dindContainerName} \\
6170
-e 'DOCKER_HOST=tcp://docker:2375' \\
71+
-e 'DOCKER_TEST_API_VERSION=${apiVersion}' \\
6272
--link=${dindContainerName}:docker \\
6373
${testImage} \\
6474
py.test -v -rxs tests/integration

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ include README.rst
55
include LICENSE
66
recursive-include tests *.py
77
recursive-include tests/unit/testdata *
8+
recursive-include tests/integration/testdata *

Makefile

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,27 @@ integration-test-py3: build-py3
4444
.PHONY: integration-dind
4545
integration-dind: build build-py3
4646
docker rm -vf dpy-dind || :
47-
docker run -d --name dpy-dind --privileged dockerswarm/dind:1.13.0-rc3 docker daemon\
47+
docker run -d --name dpy-dind --privileged dockerswarm/dind:1.13.0 docker daemon\
4848
-H tcp://0.0.0.0:2375
49-
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --link=dpy-dind:docker docker-sdk-python\
50-
py.test tests/integration
51-
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --link=dpy-dind:docker docker-sdk-python3\
52-
py.test tests/integration
49+
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=1.25"\
50+
--link=dpy-dind:docker docker-sdk-python py.test tests/integration
51+
docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=1.25"\
52+
--link=dpy-dind:docker docker-sdk-python3 py.test tests/integration
5353
docker rm -vf dpy-dind
5454

5555
.PHONY: integration-dind-ssl
5656
integration-dind-ssl: build-dind-certs build build-py3
5757
docker run -d --name dpy-dind-certs dpy-dind-certs
5858
docker run -d --env="DOCKER_HOST=tcp://localhost:2375" --env="DOCKER_TLS_VERIFY=1"\
5959
--env="DOCKER_CERT_PATH=/certs" --volumes-from dpy-dind-certs --name dpy-dind-ssl\
60-
-v /tmp --privileged dockerswarm/dind:1.13.0-rc3 docker daemon --tlsverify\
60+
-v /tmp --privileged dockerswarm/dind:1.13.0 docker daemon --tlsverify\
6161
--tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem\
6262
--tlskey=/certs/server-key.pem -H tcp://0.0.0.0:2375
6363
docker run --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\
64-
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs"\
64+
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=1.25"\
6565
--link=dpy-dind-ssl:docker docker-sdk-python py.test tests/integration
6666
docker run --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\
67-
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs"\
67+
--env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=1.25"\
6868
--link=dpy-dind-ssl:docker docker-sdk-python3 py.test tests/integration
6969
docker rm -vf dpy-dind-ssl dpy-dind-certs
7070

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A Python library for the Docker Engine API. It lets you do anything the `docker`
66

77
## Installation
88

9-
The latest stable version [is available on PyPi](https://pypi.python.org/pypi/docker/). Either add `docker` to your `requirements.txt` file or install with pip:
9+
The latest stable version [is available on PyPI](https://pypi.python.org/pypi/docker/). Either add `docker` to your `requirements.txt` file or install with pip:
1010

1111
pip install docker
1212

docker/api/build.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import json
12
import logging
23
import os
34
import re
4-
import json
55

6+
from .. import auth
67
from .. import constants
78
from .. import errors
8-
from .. import auth
99
from .. import utils
1010

1111

@@ -18,7 +18,7 @@ def build(self, path=None, tag=None, quiet=False, fileobj=None,
1818
custom_context=False, encoding=None, pull=False,
1919
forcerm=False, dockerfile=None, container_limits=None,
2020
decode=False, buildargs=None, gzip=False, shmsize=None,
21-
labels=None):
21+
labels=None, cache_from=None):
2222
"""
2323
Similar to the ``docker build`` command. Either ``path`` or ``fileobj``
2424
needs to be set. ``path`` can be a local path (to a directory
@@ -92,6 +92,8 @@ def build(self, path=None, tag=None, quiet=False, fileobj=None,
9292
shmsize (int): Size of `/dev/shm` in bytes. The size must be
9393
greater than 0. If omitted the system uses 64MB.
9494
labels (dict): A dictionary of labels to set on the image.
95+
cache_from (list): A list of images used for build cache
96+
resolution.
9597
9698
Returns:
9799
A generator for the build output.
@@ -188,6 +190,14 @@ def build(self, path=None, tag=None, quiet=False, fileobj=None,
188190
'labels was only introduced in API version 1.23'
189191
)
190192

193+
if cache_from:
194+
if utils.version_gte(self._version, '1.25'):
195+
params.update({'cachefrom': json.dumps(cache_from)})
196+
else:
197+
raise errors.InvalidVersion(
198+
'cache_from was only introduced in API version 1.25'
199+
)
200+
191201
if context is not None:
192202
headers = {'Content-Type': 'application/tar'}
193203
if encoding:

docker/api/client.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from .exec_api import ExecApiMixin
1515
from .image import ImageApiMixin
1616
from .network import NetworkApiMixin
17+
from .plugin import PluginApiMixin
18+
from .secret import SecretApiMixin
1719
from .service import ServiceApiMixin
1820
from .swarm import SwarmApiMixin
1921
from .volume import VolumeApiMixin
@@ -46,11 +48,13 @@ class APIClient(
4648
ExecApiMixin,
4749
ImageApiMixin,
4850
NetworkApiMixin,
51+
PluginApiMixin,
52+
SecretApiMixin,
4953
ServiceApiMixin,
5054
SwarmApiMixin,
5155
VolumeApiMixin):
5256
"""
53-
A low-level client for the Docker Remote API.
57+
A low-level client for the Docker Engine API.
5458
5559
Example:
5660
@@ -225,10 +229,12 @@ def _post_json(self, url, data, **kwargs):
225229
# Go <1.1 can't unserialize null to a string
226230
# so we do this disgusting thing here.
227231
data2 = {}
228-
if data is not None:
232+
if data is not None and isinstance(data, dict):
229233
for k, v in six.iteritems(data):
230234
if v is not None:
231235
data2[k] = v
236+
elif data is not None:
237+
data2 = data
232238

233239
if 'headers' not in kwargs:
234240
kwargs['headers'] = {}
@@ -302,11 +308,13 @@ def _multiplexed_buffer_helper(self, response):
302308
"""A generator of multiplexed data blocks read from a buffered
303309
response."""
304310
buf = self._result(response, binary=True)
311+
buf_length = len(buf)
305312
walker = 0
306313
while True:
307-
if len(buf[walker:]) < 8:
314+
if buf_length - walker < STREAM_HEADER_SIZE_BYTES:
308315
break
309-
_, length = struct.unpack_from('>BxxxL', buf[walker:])
316+
header = buf[walker:walker + STREAM_HEADER_SIZE_BYTES]
317+
_, length = struct.unpack_from('>BxxxL', header)
310318
start = walker + STREAM_HEADER_SIZE_BYTES
311319
end = start + length
312320
walker = end

docker/api/container.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def commit(self, container, repository=None, tag=None, message=None,
108108
author (str): The name of the author
109109
changes (str): Dockerfile instructions to apply while committing
110110
conf (dict): The configuration for the container. See the
111-
`Remote API documentation
111+
`Engine API documentation
112112
<https://docs.docker.com/reference/api/docker_remote_api/>`_
113113
for full details.
114114
@@ -238,7 +238,7 @@ def create_container(self, image, command=None, hostname=None, user=None,
238238
memswap_limit=None, cpuset=None, host_config=None,
239239
mac_address=None, labels=None, volume_driver=None,
240240
stop_signal=None, networking_config=None,
241-
healthcheck=None):
241+
healthcheck=None, stop_timeout=None):
242242
"""
243243
Creates a container. Parameters are similar to those for the ``docker
244244
run`` command except it doesn't support the attach options (``-a``).
@@ -313,9 +313,10 @@ def create_container(self, image, command=None, hostname=None, user=None,
313313
314314
**Using volumes**
315315
316-
Volume declaration is done in two parts. Provide a list of mountpoints
317-
to the with the ``volumes`` parameter, and declare mappings in the
318-
``host_config`` section.
316+
Volume declaration is done in two parts. Provide a list of
317+
paths to use as mountpoints inside the container with the
318+
``volumes`` parameter, and declare mappings from paths on the host
319+
in the ``host_config`` section.
319320
320321
.. code-block:: python
321322
@@ -392,7 +393,8 @@ def create_container(self, image, command=None, hostname=None, user=None,
392393
version 1.10. Use ``host_config`` instead.
393394
dns_opt (:py:class:`list`): Additional options to be added to the
394395
container's ``resolv.conf`` file
395-
volumes (str or list):
396+
volumes (str or list): List of paths inside the container to use
397+
as volumes.
396398
volumes_from (:py:class:`list`): List of container names or Ids to
397399
get volumes from.
398400
network_disabled (bool): Disable networking
@@ -411,6 +413,8 @@ def create_container(self, image, command=None, hostname=None, user=None,
411413
volume_driver (str): The name of a volume driver/plugin.
412414
stop_signal (str): The stop signal to use to stop the container
413415
(e.g. ``SIGINT``).
416+
stop_timeout (int): Timeout to stop the container, in seconds.
417+
Default: 10
414418
networking_config (dict): A networking configuration generated
415419
by :py:meth:`create_networking_config`.
416420
@@ -437,6 +441,7 @@ def create_container(self, image, command=None, hostname=None, user=None,
437441
network_disabled, entrypoint, cpu_shares, working_dir, domainname,
438442
memswap_limit, cpuset, host_config, mac_address, labels,
439443
volume_driver, stop_signal, networking_config, healthcheck,
444+
stop_timeout
440445
)
441446
return self.create_container_from_config(config, name)
442447

@@ -457,6 +462,8 @@ def create_host_config(self, *args, **kwargs):
457462
:py:meth:`create_container`.
458463
459464
Args:
465+
auto_remove (bool): enable auto-removal of the container on daemon
466+
side when the container's process exits.
460467
binds (dict): Volumes to bind. See :py:meth:`create_container`
461468
for more information.
462469
blkio_weight_device: Block IO weight (relative device weight) in
@@ -542,6 +549,8 @@ def create_host_config(self, *args, **kwargs):
542549
security_opt (:py:class:`list`): A list of string values to
543550
customize labels for MLS systems, such as SELinux.
544551
shm_size (str or int): Size of /dev/shm (e.g. ``1G``).
552+
storage_opt (dict): Storage driver options per container as a
553+
key-value mapping.
545554
sysctls (dict): Kernel parameters to set in the container.
546555
tmpfs (dict): Temporary filesystems to mount, as a dictionary
547556
mapping a path inside the container to options for that path.
@@ -906,16 +915,35 @@ def put_archive(self, container, path, data):
906915
Raises:
907916
:py:class:`docker.errors.APIError`
908917
If the server returns an error.
909-
910-
Raises:
911-
:py:class:`~docker.errors.APIError` If an error occurs.
912918
"""
913919
params = {'path': path}
914920
url = self._url('/containers/{0}/archive', container)
915921
res = self._put(url, params=params, data=data)
916922
self._raise_for_status(res)
917923
return res.status_code == 200
918924

925+
@utils.minimum_version('1.25')
926+
def prune_containers(self, filters=None):
927+
"""
928+
Delete stopped containers
929+
930+
Args:
931+
filters (dict): Filters to process on the prune list.
932+
933+
Returns:
934+
(dict): A dict containing a list of deleted container IDs and
935+
the amount of disk space reclaimed in bytes.
936+
937+
Raises:
938+
:py:class:`docker.errors.APIError`
939+
If the server returns an error.
940+
"""
941+
params = {}
942+
if filters:
943+
params['filters'] = utils.convert_filters(filters)
944+
url = self._url('/containers/prune')
945+
return self._result(self._post(url, params=params), True)
946+
919947
@utils.check_resource
920948
def remove_container(self, container, v=False, link=False, force=False):
921949
"""

docker/api/image.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,31 @@ def load_image(self, data):
274274
res = self._post(self._url("/images/load"), data=data)
275275
self._raise_for_status(res)
276276

277+
@utils.minimum_version('1.25')
278+
def prune_images(self, filters=None):
279+
"""
280+
Delete unused images
281+
282+
Args:
283+
filters (dict): Filters to process on the prune list.
284+
Available filters:
285+
- dangling (bool): When set to true (or 1), prune only
286+
unused and untagged images.
287+
288+
Returns:
289+
(dict): A dict containing a list of deleted image IDs and
290+
the amount of disk space reclaimed in bytes.
291+
292+
Raises:
293+
:py:class:`docker.errors.APIError`
294+
If the server returns an error.
295+
"""
296+
url = self._url("/images/prune")
297+
params = {}
298+
if filters is not None:
299+
params['filters'] = utils.convert_filters(filters)
300+
return self._result(self._post(url, params=params), True)
301+
277302
def pull(self, repository, tag=None, stream=False,
278303
insecure_registry=False, auth_config=None, decode=False):
279304
"""

docker/api/network.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,28 @@ def create_network(self, name, driver=None, options=None, ipam=None,
133133
res = self._post_json(url, data=data)
134134
return self._result(res, json=True)
135135

136+
@minimum_version('1.25')
137+
def prune_networks(self, filters=None):
138+
"""
139+
Delete unused networks
140+
141+
Args:
142+
filters (dict): Filters to process on the prune list.
143+
144+
Returns:
145+
(dict): A dict containing a list of deleted network names and
146+
the amount of disk space reclaimed in bytes.
147+
148+
Raises:
149+
:py:class:`docker.errors.APIError`
150+
If the server returns an error.
151+
"""
152+
params = {}
153+
if filters:
154+
params['filters'] = utils.convert_filters(filters)
155+
url = self._url('/networks/prune')
156+
return self._result(self._post(url, params=params), True)
157+
136158
@minimum_version('1.21')
137159
def remove_network(self, net_id):
138160
"""

0 commit comments

Comments
 (0)