summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoffrey F <f.joffrey@gmail.com>2018-08-09 17:24:22 -0700
committerGitHub <noreply@github.com>2018-08-09 17:24:22 -0700
commite0495a91e49d19dc357513536c2882b7eaf28a05 (patch)
treedb48e50d0867f1ae2360fa2b9643eaf2d8366868
parent1e389b7cfe12eb04685d331a640cd8dac77206d1 (diff)
parent05fa0be8ef5541462b59da9658c617c48bd60924 (diff)
downloaddocker-py-e0495a91e49d19dc357513536c2882b7eaf28a05.tar.gz
Merge pull request #2110 from docker/3.5.0-release3.5.0
3.5.0 release
-rw-r--r--.travis.yml4
-rw-r--r--docker/api/build.py16
-rw-r--r--docker/api/container.py2
-rw-r--r--docker/api/service.py40
-rw-r--r--docker/models/containers.py1
-rw-r--r--docker/models/services.py23
-rw-r--r--docker/types/__init__.py4
-rw-r--r--docker/types/containers.py17
-rw-r--r--docker/types/services.py33
-rw-r--r--docker/version.py2
-rw-r--r--docs/change-log.md27
-rw-r--r--requirements.txt6
-rw-r--r--setup.py11
-rw-r--r--test-requirements.txt3
-rw-r--r--tests/integration/api_container_test.py10
-rw-r--r--tests/integration/api_service_test.py35
-rw-r--r--tests/unit/dockertypes_test.py6
-rw-r--r--tests/unit/models_containers_test.py2
-rw-r--r--tests/unit/models_services_test.py8
-rw-r--r--tests/unit/types_containers_test.py6
-rw-r--r--tox.ini2
21 files changed, 223 insertions, 35 deletions
diff --git a/.travis.yml b/.travis.yml
index 842e352..1c837a2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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:
diff --git a/docker/api/build.py b/docker/api/build.py
index 419255f..0486dce 100644
--- a/docker/api/build.py
+++ b/docker/api/build.py
@@ -293,20 +293,28 @@ class BuildApiMixin(object):
# 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]
diff --git a/docker/api/container.py b/docker/api/container.py
index d4f75f5..d841606 100644
--- a/docker/api/container.py
+++ b/docker/api/container.py
@@ -547,6 +547,8 @@ class ContainerApiMixin(object):
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.
diff --git a/docker/api/service.py b/docker/api/service.py
index 03b0ca6..8b956b6 100644
--- a/docker/api/service.py
+++ b/docker/api/service.py
@@ -2,7 +2,8 @@ from .. import auth, errors, utils
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(
@@ -18,10 +19,24 @@ def _check_api_features(version, task_template, update_config, endpoint_spec):
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']):
@@ -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.
@@ -114,6 +129,8 @@ class ServiceApiMixin(object):
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
@@ -129,7 +146,8 @@ class ServiceApiMixin(object):
"""
_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')
@@ -160,6 +178,9 @@ class ServiceApiMixin(object):
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
)
@@ -336,7 +357,8 @@ class ServiceApiMixin(object):
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.
@@ -354,6 +376,8 @@ class ServiceApiMixin(object):
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
@@ -370,7 +394,8 @@ class ServiceApiMixin(object):
"""
_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:
@@ -416,6 +441,11 @@ class ServiceApiMixin(object):
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'):
diff --git a/docker/models/containers.py b/docker/models/containers.py
index b33a718..de6222e 100644
--- a/docker/models/containers.py
+++ b/docker/models/containers.py
@@ -995,6 +995,7 @@ RUN_HOST_CONFIG_KWARGS = [
'tmpfs',
'ulimits',
'userns_mode',
+ 'uts_mode',
'version',
'volumes_from',
'runtime'
diff --git a/docker/models/services.py b/docker/models/services.py
index 458d2c8..fa029f3 100644
--- a/docker/models/services.py
+++ b/docker/models/services.py
@@ -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
@@ -153,6 +153,9 @@ class ServiceCollection(Collection):
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``.
@@ -180,6 +183,8 @@ class ServiceCollection(Collection):
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.
@@ -302,6 +307,12 @@ CREATE_SERVICE_KWARGS = [
'endpoint_spec',
]
+PLACEMENT_KWARGS = [
+ 'constraints',
+ 'preferences',
+ 'platforms',
+]
+
def _get_create_service_kwargs(func_name, kwargs):
# Copy over things which can be copied directly
@@ -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'] = {
diff --git a/docker/types/__init__.py b/docker/types/__init__.py
index 0b0d847..6451233 100644
--- a/docker/types/__init__.py
+++ b/docker/types/__init__.py
@@ -5,7 +5,7 @@ from .healthcheck import Healthcheck
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
diff --git a/docker/types/containers.py b/docker/types/containers.py
index 2521420..9dfea8c 100644
--- a/docker/types/containers.py
+++ b/docker/types/containers.py
@@ -115,11 +115,11 @@ class HostConfig(dict):
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):
@@ -392,6 +392,11 @@ class HostConfig(dict):
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')
@@ -573,7 +578,7 @@ class ContainerConfig(dict):
'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,
diff --git a/docker/types/services.py b/docker/types/services.py
index 31f4750..c66d41a 100644
--- a/docker/types/services.py
+++ b/docker/types/services.py
@@ -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
@@ -385,9 +386,9 @@ class UpdateConfig(dict):
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
@@ -413,6 +414,30 @@ class UpdateConfig(dict):
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',
diff --git a/docker/version.py b/docker/version.py
index d451374..022daff 100644
--- a/docker/version.py
+++ b/docker/version.py
@@ -1,2 +1,2 @@
-version = "3.4.1"
+version = "3.5.0"
version_info = tuple([int(d) for d in version.split("-")[0].split(".")])
diff --git a/docs/change-log.md b/docs/change-log.md
index 2bd11a7..1b2d620 100644
--- a/docs/change-log.md
+++ b/docs/change-log.md
@@ -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
-----
diff --git a/requirements.txt b/requirements.txt
index 6c5e7d0..289dea9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -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
@@ -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' \ No newline at end of file
diff --git a/setup.py b/setup.py
index 57b2b5a..1b208e5 100644
--- a/setup.py
+++ b/setup.py
@@ -10,10 +10,10 @@ ROOT_DIR = os.path.dirname(__file__)
SOURCE_DIR = os.path.join(ROOT_DIR)
requirements = [
- 'requests >= 2.14.2, != 2.18.0',
'six >= 1.4.0',
'websocket-client >= 0.32.0',
- 'docker-pycreds >= 0.3.0'
+ 'docker-pycreds >= 0.3.0',
+ 'requests >= 2.14.2, != 2.18.0',
]
extras_require = {
@@ -27,7 +27,10 @@ extras_require = {
# Python 3.6 is only compatible with v220 ; Python < 3.5 is not supported
# on v220 ; ALL versions are broken for v222 (as of 2018-01-26)
':sys_platform == "win32" and python_version < "3.6"': 'pypiwin32==219',
- ':sys_platform == "win32" and python_version >= "3.6"': 'pypiwin32==220',
+ ':sys_platform == "win32" and python_version >= "3.6"': 'pypiwin32==223',
+
+ # urllib3 drops support for Python 3.3 in 1.23
+ ':python_version == "3.3"': 'urllib3 < 1.23',
# If using docker-py over TLS, highly recommend this option is
# pip-installed or pinned.
@@ -38,6 +41,7 @@ extras_require = {
# installing the extra dependencies, install the following instead:
# 'requests[security] >= 2.5.2, != 2.11.0, != 2.12.2'
'tls': ['pyOpenSSL>=0.14', 'cryptography>=1.3.4', 'idna>=2.0.0'],
+
}
version = None
@@ -81,6 +85,7 @@ setup(
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
'Topic :: Utilities',
'License :: OSI Approved :: Apache Software License',
],
diff --git a/test-requirements.txt b/test-requirements.txt
index 09680b6..9ad59cc 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,6 +1,7 @@
coverage==3.7.1
flake8==3.4.1
mock==1.0.1
-pytest==2.9.1
+pytest==2.9.1; python_version == '3.3'
+pytest==3.6.3; python_version > '3.3'
pytest-cov==2.1.0
pytest-timeout==1.2.1
diff --git a/tests/integration/api_container_test.py b/tests/integration/api_container_test.py
index ff70148..6ce846b 100644
--- a/tests/integration/api_container_test.py
+++ b/tests/integration/api_container_test.py
@@ -490,6 +490,16 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(ctnr)
assert rule in self.client.logs(ctnr).decode('utf-8')
+ def test_create_with_uts_mode(self):
+ container = self.client.create_container(
+ BUSYBOX, ['echo'], host_config=self.client.create_host_config(
+ uts_mode='host'
+ )
+ )
+ self.tmp_containers.append(container)
+ config = self.client.inspect_container(container)
+ assert config['HostConfig']['UTSMode'] == 'host'
+
@pytest.mark.xfail(
IS_WINDOWS_PLATFORM, reason='Test not designed for Windows platform'
diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py
index 85f9dcc..a53ca1c 100644
--- a/tests/integration/api_service_test.py
+++ b/tests/integration/api_service_test.py
@@ -281,6 +281,20 @@ class ServiceTest(BaseAPIIntegrationTest):
assert update_config['Delay'] == uc['Delay']
assert update_config['FailureAction'] == uc['FailureAction']
+ @requires_api_version('1.28')
+ def test_create_service_with_failure_action_rollback(self):
+ container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ update_config = docker.types.UpdateConfig(failure_action='rollback')
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, update_config=update_config, name=name
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'UpdateConfig' in svc_info['Spec']
+ uc = svc_info['Spec']['UpdateConfig']
+ assert update_config['FailureAction'] == uc['FailureAction']
+
@requires_api_version('1.25')
def test_create_service_with_update_config_monitor(self):
container_spec = docker.types.ContainerSpec('busybox', ['true'])
@@ -298,6 +312,27 @@ class ServiceTest(BaseAPIIntegrationTest):
assert update_config['Monitor'] == uc['Monitor']
assert update_config['MaxFailureRatio'] == uc['MaxFailureRatio']
+ @requires_api_version('1.28')
+ def test_create_service_with_rollback_config(self):
+ container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ rollback_cfg = docker.types.RollbackConfig(
+ parallelism=10, delay=5, failure_action='pause',
+ monitor=300000000, max_failure_ratio=0.4
+ )
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, rollback_config=rollback_cfg, name=name
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'RollbackConfig' in svc_info['Spec']
+ rc = svc_info['Spec']['RollbackConfig']
+ assert rollback_cfg['Parallelism'] == rc['Parallelism']
+ assert rollback_cfg['Delay'] == rc['Delay']
+ assert rollback_cfg['FailureAction'] == rc['FailureAction']
+ assert rollback_cfg['Monitor'] == rc['Monitor']
+ assert rollback_cfg['MaxFailureRatio'] == rc['MaxFailureRatio']
+
def test_create_service_with_restart_policy(self):
container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
policy = docker.types.RestartPolicy(
diff --git a/tests/unit/dockertypes_test.py b/tests/unit/dockertypes_test.py
index 2be0578..cdacf8c 100644
--- a/tests/unit/dockertypes_test.py
+++ b/tests/unit/dockertypes_test.py
@@ -85,6 +85,12 @@ class HostConfigTest(unittest.TestCase):
with pytest.raises(ValueError):
create_host_config(version='1.23', userns_mode='host12')
+ def test_create_host_config_with_uts(self):
+ config = create_host_config(version='1.15', uts_mode='host')
+ assert config.get('UTSMode') == 'host'
+ with pytest.raises(ValueError):
+ create_host_config(version='1.15', uts_mode='host12')
+
def test_create_host_config_with_oom_score_adj(self):
config = create_host_config(version='1.22', oom_score_adj=100)
assert config.get('OomScoreAdj') == 100
diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py
index 48a5288..22dd241 100644
--- a/tests/unit/models_containers_test.py
+++ b/tests/unit/models_containers_test.py
@@ -95,6 +95,7 @@ class ContainerCollectionTest(unittest.TestCase):
ulimits=[{"Name": "nofile", "Soft": 1024, "Hard": 2048}],
user='bob',
userns_mode='host',
+ uts_mode='host',
version='1.23',
volume_driver='some_driver',
volumes=[
@@ -174,6 +175,7 @@ class ContainerCollectionTest(unittest.TestCase):
'Tmpfs': {'/blah': ''},
'Ulimits': [{"Name": "nofile", "Soft": 1024, "Hard": 2048}],
'UsernsMode': 'host',
+ 'UTSMode': 'host',
'VolumesFrom': ['container'],
},
healthcheck={'test': 'true'},
diff --git a/tests/unit/models_services_test.py b/tests/unit/models_services_test.py
index 247bb4a..a4ac50c 100644
--- a/tests/unit/models_services_test.py
+++ b/tests/unit/models_services_test.py
@@ -26,6 +26,8 @@ class CreateServiceKwargsTest(unittest.TestCase):
'mounts': [{'some': 'mounts'}],
'stop_grace_period': 5,
'constraints': ['foo=bar'],
+ 'preferences': ['bar=baz'],
+ 'platforms': [('x86_64', 'linux')],
})
task_template = kwargs.pop('task_template')
@@ -41,7 +43,11 @@ class CreateServiceKwargsTest(unittest.TestCase):
'ContainerSpec', 'Resources', 'RestartPolicy', 'Placement',
'LogDriver', 'Networks'
])
- assert task_template['Placement'] == {'Constraints': ['foo=bar']}
+ assert task_template['Placement'] == {
+ 'Constraints': ['foo=bar'],
+ 'Preferences': ['bar=baz'],
+ 'Platforms': [{'Architecture': 'x86_64', 'OS': 'linux'}],
+ }
assert task_template['LogDriver'] == {
'Name': 'logdriver',
'Options': {'foo': 'bar'}
diff --git a/tests/unit/types_containers_test.py b/tests/unit/types_containers_test.py
new file mode 100644
index 0000000..b0ad0a7
--- /dev/null
+++ b/tests/unit/types_containers_test.py
@@ -0,0 +1,6 @@
+from docker.types.containers import ContainerConfig
+
+
+def test_uid_0_is_not_elided():
+ x = ContainerConfig(image='i', version='v', command='true', user=0)
+ assert x['User'] == '0'
diff --git a/tox.ini b/tox.ini
index 41d8860..5396147 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py27, py33, py34, py35, py36, flake8
+envlist = py27, py34, py35, py36, py37, flake8
skipsdist=True
[testenv]