Skip to content

Commit

Permalink
Merge pull request #2110 from docker/3.5.0-release
Browse files Browse the repository at this point in the history
3.5.0 release
  • Loading branch information
shin- authored Aug 10, 2018
2 parents 1e389b7 + 05fa0be commit e0495a9
Show file tree
Hide file tree
Showing 21 changed files with 223 additions and 35 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ matrix:
env: TOXENV=py35
- python: 3.6
env: TOXENV=py36
- python: 3.7
env: TOXENV=py37
dist: xenial
sudo: true
- env: TOXENV=flake8

install:
Expand Down
16 changes: 12 additions & 4 deletions docker/api/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,20 +293,28 @@ def _set_auth_headers(self, headers):
# Send the full auth configuration (if any exists), since the build
# could use any (or all) of the registries.
if self._auth_configs:
auth_cfgs = self._auth_configs
auth_data = {}
if self._auth_configs.get('credsStore'):
if auth_cfgs.get('credsStore'):
# Using a credentials store, we need to retrieve the
# credentials for each registry listed in the config.json file
# Matches CLI behavior: https://github.com/docker/docker/blob/
# 67b85f9d26f1b0b2b240f2d794748fac0f45243c/cliconfig/
# credentials/native_store.go#L68-L83
for registry in self._auth_configs.get('auths', {}).keys():
for registry in auth_cfgs.get('auths', {}).keys():
auth_data[registry] = auth.resolve_authconfig(
self._auth_configs, registry,
auth_cfgs, registry,
credstore_env=self.credstore_env,
)
else:
auth_data = self._auth_configs.get('auths', {}).copy()
for registry in auth_cfgs.get('credHelpers', {}).keys():
auth_data[registry] = auth.resolve_authconfig(
auth_cfgs, registry,
credstore_env=self.credstore_env
)
for registry, creds in auth_cfgs.get('auths', {}).items():
if registry not in auth_data:
auth_data[registry] = creds
# See https://github.com/docker/docker-py/issues/1683
if auth.INDEX_NAME in auth_data:
auth_data[auth.INDEX_URL] = auth_data[auth.INDEX_NAME]
Expand Down
2 changes: 2 additions & 0 deletions docker/api/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,8 @@ def create_host_config(self, *args, **kwargs):
userns_mode (str): Sets the user namespace mode for the container
when user namespace remapping option is enabled. Supported
values are: ``host``
uts_mode (str): Sets the UTS namespace mode for the container.
Supported values are: ``host``
volumes_from (:py:class:`list`): List of container names or IDs to
get volumes from.
runtime (str): Runtime to use with this container.
Expand Down
40 changes: 35 additions & 5 deletions docker/api/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from ..types import ServiceMode


def _check_api_features(version, task_template, update_config, endpoint_spec):
def _check_api_features(version, task_template, update_config, endpoint_spec,
rollback_config):

def raise_version_error(param, min_version):
raise errors.InvalidVersion(
Expand All @@ -18,10 +19,24 @@ def raise_version_error(param, min_version):
if 'Monitor' in update_config:
raise_version_error('UpdateConfig.monitor', '1.25')

if utils.version_lt(version, '1.28'):
if update_config.get('FailureAction') == 'rollback':
raise_version_error(
'UpdateConfig.failure_action rollback', '1.28'
)

if utils.version_lt(version, '1.29'):
if 'Order' in update_config:
raise_version_error('UpdateConfig.order', '1.29')

if rollback_config is not None:
if utils.version_lt(version, '1.28'):
raise_version_error('rollback_config', '1.28')

if utils.version_lt(version, '1.29'):
if 'Order' in update_config:
raise_version_error('RollbackConfig.order', '1.29')

if endpoint_spec is not None:
if utils.version_lt(version, '1.32') and 'Ports' in endpoint_spec:
if any(p.get('PublishMode') for p in endpoint_spec['Ports']):
Expand Down Expand Up @@ -99,7 +114,7 @@ class ServiceApiMixin(object):
def create_service(
self, task_template, name=None, labels=None, mode=None,
update_config=None, networks=None, endpoint_config=None,
endpoint_spec=None
endpoint_spec=None, rollback_config=None
):
"""
Create a service.
Expand All @@ -114,6 +129,8 @@ def create_service(
or global). Defaults to replicated.
update_config (UpdateConfig): Specification for the update strategy
of the service. Default: ``None``
rollback_config (RollbackConfig): Specification for the rollback
strategy of the service. Default: ``None``
networks (:py:class:`list`): List of network names or IDs to attach
the service to. Default: ``None``.
endpoint_spec (EndpointSpec): Properties that can be configured to
Expand All @@ -129,7 +146,8 @@ def create_service(
"""

_check_api_features(
self._version, task_template, update_config, endpoint_spec
self._version, task_template, update_config, endpoint_spec,
rollback_config
)

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

if rollback_config is not None:
data['RollbackConfig'] = rollback_config

return self._result(
self._post_json(url, data=data, headers=headers), True
)
Expand Down Expand Up @@ -336,7 +357,8 @@ def tasks(self, filters=None):
def update_service(self, service, version, task_template=None, name=None,
labels=None, mode=None, update_config=None,
networks=None, endpoint_config=None,
endpoint_spec=None, fetch_current_spec=False):
endpoint_spec=None, fetch_current_spec=False,
rollback_config=None):
"""
Update a service.
Expand All @@ -354,6 +376,8 @@ def update_service(self, service, version, task_template=None, name=None,
or global). Defaults to replicated.
update_config (UpdateConfig): Specification for the update strategy
of the service. Default: ``None``.
rollback_config (RollbackConfig): Specification for the rollback
strategy of the service. Default: ``None``
networks (:py:class:`list`): List of network names or IDs to attach
the service to. Default: ``None``.
endpoint_spec (EndpointSpec): Properties that can be configured to
Expand All @@ -370,7 +394,8 @@ def update_service(self, service, version, task_template=None, name=None,
"""

_check_api_features(
self._version, task_template, update_config, endpoint_spec
self._version, task_template, update_config, endpoint_spec,
rollback_config
)

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

if rollback_config is not None:
data['RollbackConfig'] = rollback_config
else:
data['RollbackConfig'] = current.get('RollbackConfig')

if networks is not None:
converted_networks = utils.convert_service_networks(networks)
if utils.version_lt(self._version, '1.25'):
Expand Down
1 change: 1 addition & 0 deletions docker/models/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ def prune(self, filters=None):
'tmpfs',
'ulimits',
'userns_mode',
'uts_mode',
'version',
'volumes_from',
'runtime'
Expand Down
23 changes: 18 additions & 5 deletions docker/models/services.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import copy
from docker.errors import create_unexpected_kwargs_error, InvalidArgument
from docker.types import TaskTemplate, ContainerSpec, ServiceMode
from docker.types import TaskTemplate, ContainerSpec, Placement, ServiceMode
from .resource import Model, Collection


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

PLACEMENT_KWARGS = [
'constraints',
'preferences',
'platforms',
]


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

if 'constraints' in kwargs:
task_template_kwargs['placement'] = {
'Constraints': kwargs.pop('constraints')
}
placement = {}
for key in copy.copy(kwargs):
if key in PLACEMENT_KWARGS:
placement[key] = kwargs.pop(key)
placement = Placement(**placement)
task_template_kwargs['placement'] = placement

if 'log_driver' in kwargs:
task_template_kwargs['log_driver'] = {
Expand Down
4 changes: 2 additions & 2 deletions docker/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .networks import EndpointConfig, IPAMConfig, IPAMPool, NetworkingConfig
from .services import (
ConfigReference, ContainerSpec, DNSConfig, DriverConfig, EndpointSpec,
Mount, Placement, Privileges, Resources, RestartPolicy, SecretReference,
ServiceMode, TaskTemplate, UpdateConfig
Mount, Placement, Privileges, Resources, RestartPolicy, RollbackConfig,
SecretReference, ServiceMode, TaskTemplate, UpdateConfig
)
from .swarm import SwarmSpec, SwarmExternalCA
17 changes: 11 additions & 6 deletions docker/types/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ def __init__(self, version, binds=None, port_bindings=None,
device_read_iops=None, device_write_iops=None,
oom_kill_disable=False, shm_size=None, sysctls=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, volume_driver=None,
cpu_count=None, cpu_percent=None, nano_cpus=None,
cpuset_mems=None, runtime=None, mounts=None,
cpuset_cpus=None, userns_mode=None, uts_mode=None,
pids_limit=None, isolation=None, auto_remove=False,
storage_opt=None, init=None, init_path=None,
volume_driver=None, cpu_count=None, cpu_percent=None,
nano_cpus=None, cpuset_mems=None, runtime=None, mounts=None,
cpu_rt_period=None, cpu_rt_runtime=None,
device_cgroup_rules=None):

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

if uts_mode:
if uts_mode != "host":
raise host_config_value_error("uts_mode", uts_mode)
self['UTSMode'] = uts_mode

if pids_limit:
if not isinstance(pids_limit, int):
raise host_config_type_error('pids_limit', pids_limit, 'int')
Expand Down Expand Up @@ -573,7 +578,7 @@ def __init__(
'Hostname': hostname,
'Domainname': domainname,
'ExposedPorts': ports,
'User': six.text_type(user) if user else None,
'User': six.text_type(user) if user is not None else None,
'Tty': tty,
'OpenStdin': stdin_open,
'StdinOnce': stdin_once,
Expand Down
33 changes: 29 additions & 4 deletions docker/types/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,11 @@ class UpdateConfig(dict):
parallelism (int): Maximum number of tasks to be updated in one
iteration (0 means unlimited parallelism). Default: 0.
delay (int): Amount of time between updates.
delay (int): Amount of time between updates, in nanoseconds.
failure_action (string): Action to take if an updated task fails to
run, or stops running during the update. Acceptable values are
``continue`` and ``pause``. Default: ``continue``
``continue``, ``pause``, as well as ``rollback`` since API v1.28.
Default: ``continue``
monitor (int): Amount of time to monitor each updated task for
failures, in nanoseconds.
max_failure_ratio (float): The fraction of tasks that may fail during
Expand All @@ -385,9 +386,9 @@ def __init__(self, parallelism=0, delay=None, failure_action='continue',
self['Parallelism'] = parallelism
if delay is not None:
self['Delay'] = delay
if failure_action not in ('pause', 'continue'):
if failure_action not in ('pause', 'continue', 'rollback'):
raise errors.InvalidArgument(
'failure_action must be either `pause` or `continue`.'
'failure_action must be one of `pause`, `continue`, `rollback`'
)
self['FailureAction'] = failure_action

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


class RollbackConfig(UpdateConfig):
"""
Used to specify the way containe rollbacks should be performed by a service
Args:
parallelism (int): Maximum number of tasks to be rolled back in one
iteration (0 means unlimited parallelism). Default: 0
delay (int): Amount of time between rollbacks, in nanoseconds.
failure_action (string): Action to take if a rolled back task fails to
run, or stops running during the rollback. Acceptable values are
``continue``, ``pause`` or ``rollback``.
Default: ``continue``
monitor (int): Amount of time to monitor each rolled back task for
failures, in nanoseconds.
max_failure_ratio (float): The fraction of tasks that may fail during
a rollback before the failure action is invoked, specified as a
floating point number between 0 and 1. Default: 0
order (string): Specifies the order of operations when rolling out a
rolled back task. Either ``start_first`` or ``stop_first`` are
accepted.
"""
pass


class RestartConditionTypesEnum(object):
_values = (
'none',
Expand Down
2 changes: 1 addition & 1 deletion docker/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "3.4.1"
version = "3.5.0"
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])
27 changes: 27 additions & 0 deletions docs/change-log.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
Change log
==========

3.5.0
-----

[List of PRs / issues for this release](https://github.com/docker/docker-py/milestone=53?closed=1)

### Deprecation warning

* Support for Python 3.3 will be dropped in the 4.0.0 release

### Features

* Updated dependencies to ensure support for Python 3.7 environments
* Added support for the `uts_mode` parameter in `HostConfig`
* The `UpdateConfig` constructor now allows `rollback` as a valid
value for `failure_action`
* Added support for `rollback_config` in `APIClient.create_service`,
`APIClient.update_service`, `DockerClient.services.create` and
`Service.update`.

### Bugfixes

* Credential helpers are now properly leveraged by the `build` method
* Fixed a bug that caused placement preferences to be ignored when provided
to `DockerClient.services.create`
* Fixed a bug that caused a `user` value of `0` to be ignored in
`APIClient.create_container` and `DockerClient.containers.create`

3.4.1
-----

Expand Down
6 changes: 4 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ appdirs==1.4.3
asn1crypto==0.22.0
backports.ssl-match-hostname==3.5.0.1
cffi==1.10.0
cryptography==1.9
cryptography==1.9; python_version == '3.3'
cryptography==2.3; python_version > '3.3'
docker-pycreds==0.3.0
enum34==1.1.6
idna==2.5
Expand All @@ -12,7 +13,8 @@ pycparser==2.17
pyOpenSSL==17.0.0
pyparsing==2.2.0
pypiwin32==219; sys_platform == 'win32' and python_version < '3.6'
pypiwin32==220; sys_platform == 'win32' and python_version >= '3.6'
pypiwin32==223; sys_platform == 'win32' and python_version >= '3.6'
requests==2.14.2
six==1.10.0
websocket-client==0.40.0
urllib3==1.21.1; python_version == '3.3'
Loading

0 comments on commit e0495a9

Please sign in to comment.