From bc8f6a690655742e2065e8beabcc889f58256f30 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Fri, 7 Aug 2026 12:26:34 +0200 Subject: [PATCH] Do not fail on empty 'docker compose images' output. (#1305) --- changelogs/fragments/1305-docker-compose.yml | 2 ++ plugins/module_utils/_common_cli.py | 3 +++ plugins/module_utils/_compose_v2.py | 17 +++++++++++------ 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/1305-docker-compose.yml diff --git a/changelogs/fragments/1305-docker-compose.yml b/changelogs/fragments/1305-docker-compose.yml new file mode 100644 index 00000000..8516bdd5 --- /dev/null +++ b/changelogs/fragments/1305-docker-compose.yml @@ -0,0 +1,2 @@ +bugfixes: + - "Handle empty 'docker compose images' stdout in case of errors (https://github.com/ansible-collections/community.docker/pull/1305)." diff --git a/plugins/module_utils/_common_cli.py b/plugins/module_utils/_common_cli.py index 0b2a1f25..67407ef4 100644 --- a/plugins/module_utils/_common_cli.py +++ b/plugins/module_utils/_common_cli.py @@ -186,12 +186,15 @@ class AnsibleDockerClientBase: cwd: str | None = None, environ_update: dict[str, str] | None = None, warn_on_stderr: bool = False, + parse_empty_as_none: bool = False, ) -> tuple[int, t.Any, bytes]: rc, stdout, stderr = self.call_cli( *args, check_rc=check_rc, data=data, cwd=cwd, environ_update=environ_update ) if warn_on_stderr and stderr: self.warn(to_text(stderr)) + if parse_empty_as_none and not stdout.strip(): + return rc, None, stderr try: data = json.loads(stdout) except Exception as exc: # pylint: disable=broad-exception-caught diff --git a/plugins/module_utils/_compose_v2.py b/plugins/module_utils/_compose_v2.py index 82d703bb..13929c8c 100644 --- a/plugins/module_utils/_compose_v2.py +++ b/plugins/module_utils/_compose_v2.py @@ -707,7 +707,7 @@ def update_failed( result: dict[str, t.Any], events: Sequence[Event], args: list[str], - stdout: str | bytes, + stdout: str | bytes | None, stderr: str | bytes, rc: int, cli: str, @@ -739,7 +739,7 @@ def update_failed( result["failed"] = True result["msg"] = "\n".join(errors) result["cmd"] = " ".join(quote(arg) for arg in [cli] + args) - result["stdout"] = to_text(stdout) + result["stdout"] = to_text(stdout) if stdout is not None else "" result["stderr"] = to_text(stderr) result["rc"] = rc return True @@ -900,7 +900,7 @@ class BaseComposeManager(DockerBaseClass): return args def _handle_failed_cli_call( - self, args: list[str], rc: int, stdout: str | bytes, stderr: bytes + self, args: list[str], rc: int, stdout: str | bytes | None, stderr: bytes ) -> t.NoReturn: events = parse_json_events(stderr, warn_function=self.client.warn) result: dict[str, t.Any] = {} @@ -945,15 +945,20 @@ class BaseComposeManager(DockerBaseClass): def list_images(self) -> list[str]: args = self.get_base_args() + ["images", "--format", "json"] rc, images, stderr = self.client.call_cli_json( - *args, cwd=self.project_src, check_rc=not self.use_json_events + *args, + cwd=self.project_src, + check_rc=not self.use_json_events, + parse_empty_as_none=True, ) if self.use_json_events and rc != 0: self._handle_failed_cli_call(args, rc, images, stderr) + if images is None: + return [] if isinstance(images, dict): # Handle breaking change in Docker Compose 2.37.0; see # https://github.com/ansible-collections/community.docker/issues/1082 # and https://github.com/docker/compose/issues/12916 for details - images = list(images.values()) + return list(images.values()) return images def parse_events( @@ -994,7 +999,7 @@ class BaseComposeManager(DockerBaseClass): result: dict[str, t.Any], events: Sequence[Event], args: list[str], - stdout: str | bytes, + stdout: str | bytes | None, stderr: bytes, rc: int, ) -> bool: