From e4e0433d2f95de2258a24b36f50b0cfd31c0c119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Moser?= Date: Tue, 17 Jul 2018 02:47:21 +0200 Subject: [PATCH] [2.6] Fix docker container init check requirements (#42533) * docker_container: fix init check requirements (#40839) * docker_container: ensure 'init' is supported Check docker-py version too. Move API version check in docker_container module since 'init' module parameter isn't defined by other docker modules. docker-py supports 'init' since 2.2.0: https://github.com/docker/docker-py/blob/2.2.0/docs/change-log.md * docker_container: fix compat with docker-py<2.2 Exception was: TypeError: create_host_config() got an unexpected keyword argument 'init' fatal: [localhost]: FAILED! => { "changed": false, "module_stderr": "Traceback (most recent call last): File ansible_module_docker_container.py, line 2089, in main() File ansible_module_docker_container.py, line 2084, in main cm = ContainerManager(client) File ansible_module_docker_container.py, line 1704, in __init__ self.present(state) File ansible_module_docker_container.py, line 1724, in present new_container = self.container_create(self.parameters.image, self.parameters.create_parameters) File ansible_module_docker_container.py, line 826, in create_parameters host_config=self._host_config(), File ansible_module_docker_container.py, line 932, in _host_config return self.client.create_host_config(**params) File lib/python3.6/site-packages/docker/api/container.py, line 157, in create_host_config return utils.create_host_config(*args, **kwargs) TypeError: create_host_config() got an unexpected keyword argument 'init'", "module_stdout": "", "msg": "MODULE FAILURE", "rc": 1 } (cherry picked from commit 3301a0b53073c25157e54bb98273ba8ec72c2125) * add changelog fragment --- .../fragments/40839-docker_container_init.yml | 2 ++ lib/ansible/module_utils/docker_common.py | 4 --- .../modules/cloud/docker/docker_container.py | 33 +++++++++++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/40839-docker_container_init.yml diff --git a/changelogs/fragments/40839-docker_container_init.yml b/changelogs/fragments/40839-docker_container_init.yml new file mode 100644 index 00000000000..733e866a1bf --- /dev/null +++ b/changelogs/fragments/40839-docker_container_init.yml @@ -0,0 +1,2 @@ +bugfixes: +- fixes docker_container compatibilty with docker-py < 2.2 diff --git a/lib/ansible/module_utils/docker_common.py b/lib/ansible/module_utils/docker_common.py index 1d65de6c43e..b97fa3f35d1 100644 --- a/lib/ansible/module_utils/docker_common.py +++ b/lib/ansible/module_utils/docker_common.py @@ -187,10 +187,6 @@ class AnsibleDockerClient(Client): except Exception as exc: self.fail("Error connecting: %s" % exc) - docker_api_version = self.version()["ApiVersion"] - if self.module.params.get("init") and LooseVersion(docker_api_version) < LooseVersion("1.25"): - self.fail("docker API version is %s. Minimum version required is 1.25 to set init option." % (docker_api_version,)) - def log(self, msg, pretty_print=False): pass # if self.debug: diff --git a/lib/ansible/modules/cloud/docker/docker_container.py b/lib/ansible/modules/cloud/docker/docker_container.py index a81c6aaa95b..489786e1d3b 100644 --- a/lib/ansible/modules/cloud/docker/docker_container.py +++ b/lib/ansible/modules/cloud/docker/docker_container.py @@ -598,6 +598,7 @@ docker_container: import os import re import shlex +from distutils.version import LooseVersion from ansible.module_utils.basic import human_to_bytes from ansible.module_utils.docker_common import HAS_DOCKER_PY_2, HAS_DOCKER_PY_3, AnsibleDockerClient, DockerBaseClass @@ -609,6 +610,7 @@ try: from docker.types import Ulimit, LogConfig else: from docker.utils.types import Ulimit, LogConfig + from ansible.module_utils.docker_common import docker_version except: # missing docker-py handled in ansible.module_utils.docker pass @@ -907,10 +909,9 @@ class TaskParameters(DockerBaseClass): devices='devices', pid_mode='pid_mode', tmpfs='tmpfs', - init='init' ) - if HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3: + if self.client.HAS_AUTO_REMOVE_OPT: # auto_remove is only supported in docker>=2 host_config_params['auto_remove'] = 'auto_remove' @@ -919,6 +920,9 @@ class TaskParameters(DockerBaseClass): host_config_params['cpu_shares'] = 'cpu_shares' host_config_params['volume_driver'] = 'volume_driver' + if self.client.HAS_INIT_OPT: + host_config_params['init'] = 'init' + params = dict() for key, value in host_config_params.items(): if getattr(self, value, None) is not None: @@ -1980,6 +1984,26 @@ class ContainerManager(DockerBaseClass): return response +class AnsibleDockerClientContainer(AnsibleDockerClient): + + def __init__(self, **kwargs): + super(AnsibleDockerClientContainer, self).__init__(**kwargs) + + docker_api_version = self.version()['ApiVersion'] + init_supported = LooseVersion(docker_api_version) >= LooseVersion('1.25') + if self.module.params.get("init") and not init_supported: + self.fail('docker API version is %s. Minimum version required is 1.25 to set init option.' % (docker_api_version,)) + + init_supported = init_supported and LooseVersion(docker_version) >= LooseVersion('2.2') + if self.module.params.get("init") and not init_supported: + self.fail('docker-py version is %s. Minimum version required is 2.2 to set init option.' % (docker_version,)) + + self.HAS_INIT_OPT = init_supported + self.HAS_AUTO_REMOVE_OPT = HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3 + if self.module.params.get('auto_remove') and not self.HAS_AUTO_REMOVE_OPT: + self.fail("'auto_remove' is not compatible with the 'docker-py' Python package. It requires the newer 'docker' Python package.") + + def main(): argument_spec = dict( auto_remove=dict(type='bool', default=False), @@ -2064,15 +2088,12 @@ def main(): ('state', 'present', ['image']) ] - client = AnsibleDockerClient( + client = AnsibleDockerClientContainer( argument_spec=argument_spec, required_if=required_if, supports_check_mode=True ) - if (not (HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3)) and client.module.params.get('auto_remove'): - client.module.fail_json(msg="'auto_remove' is not compatible with the 'docker-py' Python package. It requires the newer 'docker' Python package.") - cm = ContainerManager(client) client.module.exit_json(**cm.results)