From d28d836960037522a6613e8dccf3b9dc973a5338 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 15 Nov 2025 21:34:25 +0100 Subject: [PATCH] Idempotency for export no longer works. --- changelogs/fragments/1199-docker_image-push.yml | 3 +++ plugins/modules/docker_image.py | 2 ++ plugins/modules/docker_image_export.py | 8 +++++++- .../targets/docker_image/tasks/tests/options.yml | 4 ++++ .../targets/docker_image_export/tasks/tests/basic.yml | 4 ++++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelogs/fragments/1199-docker_image-push.yml b/changelogs/fragments/1199-docker_image-push.yml index 0fc67985..f861ea7e 100644 --- a/changelogs/fragments/1199-docker_image-push.yml +++ b/changelogs/fragments/1199-docker_image-push.yml @@ -1,2 +1,5 @@ bugfixes: - "docker_image, docker_image_push - adjust image push detection to Docker 29 (https://github.com/ansible-collections/community.docker/pull/1199)." +known_issues: + - "docker_image, docker_image_export - idempotency for archiving images depends on whether the image IDs used by the image storage backend correspond to the IDs used in the tarball's ``manifest.json`` files. + The new default backend in Docker 29 apparently uses image IDs that no longer correspond, whence idempotency no longer works (https://github.com/ansible-collections/community.docker/pull/1199)." diff --git a/plugins/modules/docker_image.py b/plugins/modules/docker_image.py index 77e18174..2fc62b79 100644 --- a/plugins/modules/docker_image.py +++ b/plugins/modules/docker_image.py @@ -21,6 +21,8 @@ description: notes: - Building images is done using Docker daemon's API. It is not possible to use BuildKit / buildx this way. Use M(community.docker.docker_image_build) to build images with BuildKit. + - Exporting images is generally not idempotent. It depends on whether the image ID equals the IDs found in the generated tarball's C(manifest.json). + This was the case with the default storage backend up to Docker 28, but seems to have changed in Docker 29. extends_documentation_fragment: - community.docker._docker.api_documentation - community.docker._attributes diff --git a/plugins/modules/docker_image_export.py b/plugins/modules/docker_image_export.py index 51c1af97..4f83527f 100644 --- a/plugins/modules/docker_image_export.py +++ b/plugins/modules/docker_image_export.py @@ -28,7 +28,13 @@ attributes: diff_mode: support: none idempotent: - support: full + support: partial + details: + - Whether the module is idempotent depends on the storage API used for images, + which determines how the image ID is computed. The idempotency check needs + that the image ID equals the ID stored in archive's C(manifest.json). + This seemed to have worked fine with the default storage backend up to Docker 28, + but seems to have changed in Docker 29. options: names: diff --git a/tests/integration/targets/docker_image/tasks/tests/options.yml b/tests/integration/targets/docker_image/tasks/tests/options.yml index 845c95d9..b391801a 100644 --- a/tests/integration/targets/docker_image/tasks/tests/options.yml +++ b/tests/integration/targets/docker_image/tasks/tests/options.yml @@ -256,6 +256,10 @@ - ansible.builtin.assert: that: - archive_image_2 is not changed + when: docker_cli_version is version("29.0.0", "<") + # Apparently idempotency no longer works with the default storage backend + # in Docker 29.0.0. + # https://github.com/ansible-collections/community.docker/pull/1199 - name: Archive image 3rd time, should overwrite due to different id community.docker.docker_image: diff --git a/tests/integration/targets/docker_image_export/tasks/tests/basic.yml b/tests/integration/targets/docker_image_export/tasks/tests/basic.yml index e81dd691..45345673 100644 --- a/tests/integration/targets/docker_image_export/tasks/tests/basic.yml +++ b/tests/integration/targets/docker_image_export/tasks/tests/basic.yml @@ -67,3 +67,7 @@ manifests_json: "{{ manifests.results | map(attribute='stdout') | map('from_json') }}" manifest_json_images: "{{ item.2 | map(attribute='Config') | map('regex_replace', '.json$', '') | map('regex_replace', '^blobs/sha256/', '') | sort }}" export_image_ids: "{{ item.1 | map('regex_replace', '^sha256:', '') | unique | sort }}" + when: docker_cli_version is version("29.0.0", "<") + # Apparently idempotency no longer works with the default storage backend + # in Docker 29.0.0. + # https://github.com/ansible-collections/community.docker/pull/1199