CLI modules: improve docker version/info output processing, avoid querying for API version if it's not needed (#935)

* Don't assume that docker version/info JSON output contains the expected fields.

* Allow CLI modules to not require the API version.

* Add changelog fragment.
This commit is contained in:
Felix Fontein 2024-07-20 15:51:02 +02:00 committed by GitHub
parent a30fd93a44
commit 22bbfbaf8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 30 additions and 9 deletions

View File

@ -0,0 +1,4 @@
bugfixes:
- "docker_compose_v2* modules, docker_image_build - provide better error message when required fields are not present in ``docker version``
or ``docker info`` output. This can happen if Podman is used instead of Docker
(https://github.com/ansible-collections/community.docker/issues/891, https://github.com/ansible-collections/community.docker/pull/935)."

View File

@ -13,6 +13,7 @@ import shlex
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six import string_types
from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion
@ -48,7 +49,7 @@ class DockerException(Exception):
class AnsibleDockerClientBase(object):
def __init__(self, common_args, min_docker_api_version=None):
def __init__(self, common_args, min_docker_api_version=None, needs_api_version=True):
self._environment = {}
if common_args['tls_hostname']:
self._environment['DOCKER_TLS_HOSTNAME'] = common_args['tls_hostname']
@ -84,11 +85,19 @@ class AnsibleDockerClientBase(object):
dummy, self._version, dummy = self.call_cli_json('version', '--format', '{{ json . }}', check_rc=True)
self._info = None
self.docker_api_version_str = self._version['Server']['ApiVersion']
if needs_api_version:
if not isinstance(self._version.get('Server'), dict) or not isinstance(self._version['Server'].get('ApiVersion'), string_types):
self.fail('Cannot determine Docker Daemon information. Are you maybe using podman instead of docker?')
self.docker_api_version_str = to_native(self._version['Server']['ApiVersion'])
self.docker_api_version = LooseVersion(self.docker_api_version_str)
min_docker_api_version = min_docker_api_version or '1.25'
if self.docker_api_version < LooseVersion(min_docker_api_version):
self.fail('Docker API version is %s. Minimum version required is %s.' % (self.docker_api_version_str, min_docker_api_version))
else:
self.docker_api_version_str = None
self.docker_api_version = None
if min_docker_api_version is not None:
self.fail('Internal error: cannot have needs_api_version=False with min_docker_api_version not None')
def log(self, msg, pretty_print=False):
pass
@ -168,7 +177,10 @@ class AnsibleDockerClientBase(object):
return self._info
def get_client_plugin_info(self, component):
for plugin in self.get_cli_info()['ClientInfo'].get('Plugins') or []:
cli_info = self.get_cli_info()
if not isinstance(cli_info.get('ClientInfo'), dict):
self.fail('Cannot determine Docker client information. Are you maybe using podman instead of docker?')
for plugin in cli_info['ClientInfo'].get('Plugins') or []:
if plugin.get('Name') == component:
return plugin
return None
@ -267,7 +279,7 @@ class AnsibleDockerClientBase(object):
class AnsibleModuleDockerClient(AnsibleDockerClientBase):
def __init__(self, argument_spec=None, supports_check_mode=False, mutually_exclusive=None,
required_together=None, required_if=None, required_one_of=None, required_by=None,
min_docker_api_version=None, fail_results=None):
min_docker_api_version=None, fail_results=None, needs_api_version=True):
# Modules can put information in here which will always be returned
# in case client.fail() is called.
@ -304,7 +316,9 @@ class AnsibleModuleDockerClient(AnsibleDockerClientBase):
self.diff = self.module._diff
common_args = dict((k, self.module.params[k]) for k in DOCKER_COMMON_ARGS)
super(AnsibleModuleDockerClient, self).__init__(common_args, min_docker_api_version=min_docker_api_version)
super(AnsibleModuleDockerClient, self).__init__(
common_args, min_docker_api_version=min_docker_api_version, needs_api_version=needs_api_version,
)
# def call_cli(self, *args, check_rc=False, data=None, cwd=None, environ_update=None):
def call_cli(self, *args, **kwargs):

View File

@ -636,6 +636,7 @@ def main():
client = AnsibleModuleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
needs_api_version=False,
**argspec_ex
)

View File

@ -151,6 +151,7 @@ def main():
client = AnsibleModuleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
needs_api_version=False,
**argspec_ex
)

View File

@ -539,6 +539,7 @@ def main():
client = AnsibleModuleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
needs_api_version=False,
)
try: