Skip to content

Commit e0495a9

Browse files
authored
Merge pull request #2110 from docker/3.5.0-release
3.5.0 release
2 parents 1e389b7 + 05fa0be commit e0495a9

21 files changed

+223
-35
lines changed

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ matrix:
1010
env: TOXENV=py35
1111
- python: 3.6
1212
env: TOXENV=py36
13+
- python: 3.7
14+
env: TOXENV=py37
15+
dist: xenial
16+
sudo: true
1317
- env: TOXENV=flake8
1418

1519
install:

docker/api/build.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,20 +293,28 @@ def _set_auth_headers(self, headers):
293293
# Send the full auth configuration (if any exists), since the build
294294
# could use any (or all) of the registries.
295295
if self._auth_configs:
296+
auth_cfgs = self._auth_configs
296297
auth_data = {}
297-
if self._auth_configs.get('credsStore'):
298+
if auth_cfgs.get('credsStore'):
298299
# Using a credentials store, we need to retrieve the
299300
# credentials for each registry listed in the config.json file
300301
# Matches CLI behavior: https://github.com/docker/docker/blob/
301302
# 67b85f9d26f1b0b2b240f2d794748fac0f45243c/cliconfig/
302303
# credentials/native_store.go#L68-L83
303-
for registry in self._auth_configs.get('auths', {}).keys():
304+
for registry in auth_cfgs.get('auths', {}).keys():
304305
auth_data[registry] = auth.resolve_authconfig(
305-
self._auth_configs, registry,
306+
auth_cfgs, registry,
306307
credstore_env=self.credstore_env,
307308
)
308309
else:
309-
auth_data = self._auth_configs.get('auths', {}).copy()
310+
for registry in auth_cfgs.get('credHelpers', {}).keys():
311+
auth_data[registry] = auth.resolve_authconfig(
312+
auth_cfgs, registry,
313+
credstore_env=self.credstore_env
314+
)
315+
for registry, creds in auth_cfgs.get('auths', {}).items():
316+
if registry not in auth_data:
317+
auth_data[registry] = creds
310318
# See https://github.com/docker/docker-py/issues/1683
311319
if auth.INDEX_NAME in auth_data:
312320
auth_data[auth.INDEX_URL] = auth_data[auth.INDEX_NAME]

docker/api/container.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,8 @@ def create_host_config(self, *args, **kwargs):
547547
userns_mode (str): Sets the user namespace mode for the container
548548
when user namespace remapping option is enabled. Supported
549549
values are: ``host``
550+
uts_mode (str): Sets the UTS namespace mode for the container.
551+
Supported values are: ``host``
550552
volumes_from (:py:class:`list`): List of container names or IDs to
551553
get volumes from.
552554
runtime (str): Runtime to use with this container.

docker/api/service.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
from ..types import ServiceMode
33

44

5-
def _check_api_features(version, task_template, update_config, endpoint_spec):
5+
def _check_api_features(version, task_template, update_config, endpoint_spec,
6+
rollback_config):
67

78
def raise_version_error(param, min_version):
89
raise errors.InvalidVersion(
@@ -18,10 +19,24 @@ def raise_version_error(param, min_version):
1819
if 'Monitor' in update_config:
1920
raise_version_error('UpdateConfig.monitor', '1.25')
2021

22+
if utils.version_lt(version, '1.28'):
23+
if update_config.get('FailureAction') == 'rollback':
24+
raise_version_error(
25+
'UpdateConfig.failure_action rollback', '1.28'
26+
)
27+
2128
if utils.version_lt(version, '1.29'):
2229
if 'Order' in update_config:
2330
raise_version_error('UpdateConfig.order', '1.29')
2431

32+
if rollback_config is not None:
33+
if utils.version_lt(version, '1.28'):
34+
raise_version_error('rollback_config', '1.28')
35+
36+
if utils.version_lt(version, '1.29'):
37+
if 'Order' in update_config:
38+
raise_version_error('RollbackConfig.order', '1.29')
39+
2540
if endpoint_spec is not None:
2641
if utils.version_lt(version, '1.32') and 'Ports' in endpoint_spec:
2742
if any(p.get('PublishMode') for p in endpoint_spec['Ports']):
@@ -99,7 +114,7 @@ class ServiceApiMixin(object):
99114
def create_service(
100115
self, task_template, name=None, labels=None, mode=None,
101116
update_config=None, networks=None, endpoint_config=None,
102-
endpoint_spec=None
117+
endpoint_spec=None, rollback_config=None
103118
):
104119
"""
105120
Create a service.
@@ -114,6 +129,8 @@ def create_service(
114129
or global). Defaults to replicated.
115130
update_config (UpdateConfig): Specification for the update strategy
116131
of the service. Default: ``None``
132+
rollback_config (RollbackConfig): Specification for the rollback
133+
strategy of the service. Default: ``None``
117134
networks (:py:class:`list`): List of network names or IDs to attach
118135
the service to. Default: ``None``.
119136
endpoint_spec (EndpointSpec): Properties that can be configured to
@@ -129,7 +146,8 @@ def create_service(
129146
"""
130147

131148
_check_api_features(
132-
self._version, task_template, update_config, endpoint_spec
149+
self._version, task_template, update_config, endpoint_spec,
150+
rollback_config
133151
)
134152

135153
url = self._url('/services/create')
@@ -160,6 +178,9 @@ def create_service(
160178
if update_config is not None:
161179
data['UpdateConfig'] = update_config
162180

181+
if rollback_config is not None:
182+
data['RollbackConfig'] = rollback_config
183+
163184
return self._result(
164185
self._post_json(url, data=data, headers=headers), True
165186
)
@@ -336,7 +357,8 @@ def tasks(self, filters=None):
336357
def update_service(self, service, version, task_template=None, name=None,
337358
labels=None, mode=None, update_config=None,
338359
networks=None, endpoint_config=None,
339-
endpoint_spec=None, fetch_current_spec=False):
360+
endpoint_spec=None, fetch_current_spec=False,
361+
rollback_config=None):
340362
"""
341363
Update a service.
342364
@@ -354,6 +376,8 @@ def update_service(self, service, version, task_template=None, name=None,
354376
or global). Defaults to replicated.
355377
update_config (UpdateConfig): Specification for the update strategy
356378
of the service. Default: ``None``.
379+
rollback_config (RollbackConfig): Specification for the rollback
380+
strategy of the service. Default: ``None``
357381
networks (:py:class:`list`): List of network names or IDs to attach
358382
the service to. Default: ``None``.
359383
endpoint_spec (EndpointSpec): Properties that can be configured to
@@ -370,7 +394,8 @@ def update_service(self, service, version, task_template=None, name=None,
370394
"""
371395

372396
_check_api_features(
373-
self._version, task_template, update_config, endpoint_spec
397+
self._version, task_template, update_config, endpoint_spec,
398+
rollback_config
374399
)
375400

376401
if fetch_current_spec:
@@ -416,6 +441,11 @@ def update_service(self, service, version, task_template=None, name=None,
416441
else:
417442
data['UpdateConfig'] = current.get('UpdateConfig')
418443

444+
if rollback_config is not None:
445+
data['RollbackConfig'] = rollback_config
446+
else:
447+
data['RollbackConfig'] = current.get('RollbackConfig')
448+
419449
if networks is not None:
420450
converted_networks = utils.convert_service_networks(networks)
421451
if utils.version_lt(self._version, '1.25'):

docker/models/containers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ def prune(self, filters=None):
995995
'tmpfs',
996996
'ulimits',
997997
'userns_mode',
998+
'uts_mode',
998999
'version',
9991000
'volumes_from',
10001001
'runtime'

docker/models/services.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import copy
22
from docker.errors import create_unexpected_kwargs_error, InvalidArgument
3-
from docker.types import TaskTemplate, ContainerSpec, ServiceMode
3+
from docker.types import TaskTemplate, ContainerSpec, Placement, ServiceMode
44
from .resource import Model, Collection
55

66

@@ -153,6 +153,9 @@ def create(self, image, command=None, **kwargs):
153153
command (list of str or str): Command to run.
154154
args (list of str): Arguments to the command.
155155
constraints (list of str): Placement constraints.
156+
preferences (list of str): Placement preferences.
157+
platforms (list of tuple): A list of platforms constraints
158+
expressed as ``(arch, os)`` tuples
156159
container_labels (dict): Labels to apply to the container.
157160
endpoint_spec (EndpointSpec): Properties that can be configured to
158161
access and load balance a service. Default: ``None``.
@@ -180,6 +183,8 @@ def create(self, image, command=None, **kwargs):
180183
containers to terminate before forcefully killing them.
181184
update_config (UpdateConfig): Specification for the update strategy
182185
of the service. Default: ``None``
186+
rollback_config (RollbackConfig): Specification for the rollback
187+
strategy of the service. Default: ``None``
183188
user (str): User to run commands as.
184189
workdir (str): Working directory for commands to run.
185190
tty (boolean): Whether a pseudo-TTY should be allocated.
@@ -302,6 +307,12 @@ def list(self, **kwargs):
302307
'endpoint_spec',
303308
]
304309

310+
PLACEMENT_KWARGS = [
311+
'constraints',
312+
'preferences',
313+
'platforms',
314+
]
315+
305316

306317
def _get_create_service_kwargs(func_name, kwargs):
307318
# Copy over things which can be copied directly
@@ -321,10 +332,12 @@ def _get_create_service_kwargs(func_name, kwargs):
321332
if 'container_labels' in kwargs:
322333
container_spec_kwargs['labels'] = kwargs.pop('container_labels')
323334

324-
if 'constraints' in kwargs:
325-
task_template_kwargs['placement'] = {
326-
'Constraints': kwargs.pop('constraints')
327-
}
335+
placement = {}
336+
for key in copy.copy(kwargs):
337+
if key in PLACEMENT_KWARGS:
338+
placement[key] = kwargs.pop(key)
339+
placement = Placement(**placement)
340+
task_template_kwargs['placement'] = placement
328341

329342
if 'log_driver' in kwargs:
330343
task_template_kwargs['log_driver'] = {

docker/types/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .networks import EndpointConfig, IPAMConfig, IPAMPool, NetworkingConfig
66
from .services import (
77
ConfigReference, ContainerSpec, DNSConfig, DriverConfig, EndpointSpec,
8-
Mount, Placement, Privileges, Resources, RestartPolicy, SecretReference,
9-
ServiceMode, TaskTemplate, UpdateConfig
8+
Mount, Placement, Privileges, Resources, RestartPolicy, RollbackConfig,
9+
SecretReference, ServiceMode, TaskTemplate, UpdateConfig
1010
)
1111
from .swarm import SwarmSpec, SwarmExternalCA

docker/types/containers.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,11 @@ def __init__(self, version, binds=None, port_bindings=None,
115115
device_read_iops=None, device_write_iops=None,
116116
oom_kill_disable=False, shm_size=None, sysctls=None,
117117
tmpfs=None, oom_score_adj=None, dns_opt=None, cpu_shares=None,
118-
cpuset_cpus=None, userns_mode=None, pids_limit=None,
119-
isolation=None, auto_remove=False, storage_opt=None,
120-
init=None, init_path=None, volume_driver=None,
121-
cpu_count=None, cpu_percent=None, nano_cpus=None,
122-
cpuset_mems=None, runtime=None, mounts=None,
118+
cpuset_cpus=None, userns_mode=None, uts_mode=None,
119+
pids_limit=None, isolation=None, auto_remove=False,
120+
storage_opt=None, init=None, init_path=None,
121+
volume_driver=None, cpu_count=None, cpu_percent=None,
122+
nano_cpus=None, cpuset_mems=None, runtime=None, mounts=None,
123123
cpu_rt_period=None, cpu_rt_runtime=None,
124124
device_cgroup_rules=None):
125125

@@ -392,6 +392,11 @@ def __init__(self, version, binds=None, port_bindings=None,
392392
raise host_config_value_error("userns_mode", userns_mode)
393393
self['UsernsMode'] = userns_mode
394394

395+
if uts_mode:
396+
if uts_mode != "host":
397+
raise host_config_value_error("uts_mode", uts_mode)
398+
self['UTSMode'] = uts_mode
399+
395400
if pids_limit:
396401
if not isinstance(pids_limit, int):
397402
raise host_config_type_error('pids_limit', pids_limit, 'int')
@@ -573,7 +578,7 @@ def __init__(
573578
'Hostname': hostname,
574579
'Domainname': domainname,
575580
'ExposedPorts': ports,
576-
'User': six.text_type(user) if user else None,
581+
'User': six.text_type(user) if user is not None else None,
577582
'Tty': tty,
578583
'OpenStdin': stdin_open,
579584
'StdinOnce': stdin_once,

docker/types/services.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,11 @@ class UpdateConfig(dict):
368368
369369
parallelism (int): Maximum number of tasks to be updated in one
370370
iteration (0 means unlimited parallelism). Default: 0.
371-
delay (int): Amount of time between updates.
371+
delay (int): Amount of time between updates, in nanoseconds.
372372
failure_action (string): Action to take if an updated task fails to
373373
run, or stops running during the update. Acceptable values are
374-
``continue`` and ``pause``. Default: ``continue``
374+
``continue``, ``pause``, as well as ``rollback`` since API v1.28.
375+
Default: ``continue``
375376
monitor (int): Amount of time to monitor each updated task for
376377
failures, in nanoseconds.
377378
max_failure_ratio (float): The fraction of tasks that may fail during
@@ -385,9 +386,9 @@ def __init__(self, parallelism=0, delay=None, failure_action='continue',
385386
self['Parallelism'] = parallelism
386387
if delay is not None:
387388
self['Delay'] = delay
388-
if failure_action not in ('pause', 'continue'):
389+
if failure_action not in ('pause', 'continue', 'rollback'):
389390
raise errors.InvalidArgument(
390-
'failure_action must be either `pause` or `continue`.'
391+
'failure_action must be one of `pause`, `continue`, `rollback`'
391392
)
392393
self['FailureAction'] = failure_action
393394

@@ -413,6 +414,30 @@ def __init__(self, parallelism=0, delay=None, failure_action='continue',
413414
self['Order'] = order
414415

415416

417+
class RollbackConfig(UpdateConfig):
418+
"""
419+
Used to specify the way containe rollbacks should be performed by a service
420+
421+
Args:
422+
parallelism (int): Maximum number of tasks to be rolled back in one
423+
iteration (0 means unlimited parallelism). Default: 0
424+
delay (int): Amount of time between rollbacks, in nanoseconds.
425+
failure_action (string): Action to take if a rolled back task fails to
426+
run, or stops running during the rollback. Acceptable values are
427+
``continue``, ``pause`` or ``rollback``.
428+
Default: ``continue``
429+
monitor (int): Amount of time to monitor each rolled back task for
430+
failures, in nanoseconds.
431+
max_failure_ratio (float): The fraction of tasks that may fail during
432+
a rollback before the failure action is invoked, specified as a
433+
floating point number between 0 and 1. Default: 0
434+
order (string): Specifies the order of operations when rolling out a
435+
rolled back task. Either ``start_first`` or ``stop_first`` are
436+
accepted.
437+
"""
438+
pass
439+
440+
416441
class RestartConditionTypesEnum(object):
417442
_values = (
418443
'none',

docker/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version = "3.4.1"
1+
version = "3.5.0"
22
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])

docs/change-log.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
Change log
22
==========
33

4+
3.5.0
5+
-----
6+
7+
[List of PRs / issues for this release](https://github.com/docker/docker-py/milestone=53?closed=1)
8+
9+
### Deprecation warning
10+
11+
* Support for Python 3.3 will be dropped in the 4.0.0 release
12+
13+
### Features
14+
15+
* Updated dependencies to ensure support for Python 3.7 environments
16+
* Added support for the `uts_mode` parameter in `HostConfig`
17+
* The `UpdateConfig` constructor now allows `rollback` as a valid
18+
value for `failure_action`
19+
* Added support for `rollback_config` in `APIClient.create_service`,
20+
`APIClient.update_service`, `DockerClient.services.create` and
21+
`Service.update`.
22+
23+
### Bugfixes
24+
25+
* Credential helpers are now properly leveraged by the `build` method
26+
* Fixed a bug that caused placement preferences to be ignored when provided
27+
to `DockerClient.services.create`
28+
* Fixed a bug that caused a `user` value of `0` to be ignored in
29+
`APIClient.create_container` and `DockerClient.containers.create`
30+
431
3.4.1
532
-----
633

requirements.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ appdirs==1.4.3
22
asn1crypto==0.22.0
33
backports.ssl-match-hostname==3.5.0.1
44
cffi==1.10.0
5-
cryptography==1.9
5+
cryptography==1.9; python_version == '3.3'
6+
cryptography==2.3; python_version > '3.3'
67
docker-pycreds==0.3.0
78
enum34==1.1.6
89
idna==2.5
@@ -12,7 +13,8 @@ pycparser==2.17
1213
pyOpenSSL==17.0.0
1314
pyparsing==2.2.0
1415
pypiwin32==219; sys_platform == 'win32' and python_version < '3.6'
15-
pypiwin32==220; sys_platform == 'win32' and python_version >= '3.6'
16+
pypiwin32==223; sys_platform == 'win32' and python_version >= '3.6'
1617
requests==2.14.2
1718
six==1.10.0
1819
websocket-client==0.40.0
20+
urllib3==1.21.1; python_version == '3.3'

0 commit comments

Comments
 (0)