Compare commits

...

3 Commits
5.1.0 ... main

Author SHA1 Message Date
Felix Fontein
b00fc741e1
Make tests more lenient. (#1252) 2026-03-27 14:29:49 +01:00
spatterlight
9c313bb9d0
Docker image export platform (#1251)
* docker_image_export: Add 'platform' option

docker_image_export: Add 'platform' option

* docker_image_export: Add 'platform' option

* Update changelogs/fragments/1064-docker-image-export-platform.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/docker_image_export.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* docker_image_export: Add 'platform' option

* docker_image_export: Add 'platform' option

* docker_image_export: Add 'platform' option

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-27 13:16:04 +01:00
Felix Fontein
91b350019a The next expected release will be 5.2.0. 2026-03-23 20:40:52 +01:00
7 changed files with 89 additions and 12 deletions

View File

@ -0,0 +1,2 @@
minor_changes:
- docker_image_export - adds ``platform`` parameter to allow exporting a specific platform variant from a multi-arch image (https://github.com/ansible-collections/community.docker/issues/1064, https://github.com/ansible-collections/community.docker/pull/1251).

View File

@ -7,7 +7,7 @@
namespace: community
name: docker
version: 5.1.0
version: 5.2.0
readme: README.md
authors:
- Ansible Docker Working Group

View File

@ -31,9 +31,12 @@ attributes:
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).
the image ID to equal 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.
- This module is B(not idempotent) when used with multi-architecture images,
regardless of Docker version.
- Full idempotency requires Docker 28 or earlier B(and) a single-architecture image.
options:
names:
@ -61,6 +64,13 @@ options:
- Export the image even if the C(.tar) file already exists and seems to contain the right image.
type: bool
default: false
platform:
description:
- Ask for this specific platform when exporting.
- For example, C(linux/amd64), C(linux/arm64).
- Requires Docker API 1.48 or newer.
type: str
version_added: 5.2.0
requirements:
- "Docker API >= 1.25"
@ -98,6 +108,7 @@ images:
sample: []
"""
import json
import traceback
import typing as t
@ -119,6 +130,9 @@ from ansible_collections.community.docker.plugins.module_utils._image_archive im
api_image_id,
load_archived_image_manifest,
)
from ansible_collections.community.docker.plugins.module_utils._platform import (
_Platform,
)
from ansible_collections.community.docker.plugins.module_utils._util import (
DockerBaseClass,
is_image_name_id,
@ -137,6 +151,7 @@ class ImageExportManager(DockerBaseClass):
self.path = parameters["path"]
self.force = parameters["force"]
self.tag = parameters["tag"]
self.platform = parameters["platform"]
if not is_valid_tag(self.tag, allow_empty=True):
self.fail(f'"{self.tag}" is not a valid docker tag')
@ -198,15 +213,31 @@ class ImageExportManager(DockerBaseClass):
except Exception as exc: # pylint: disable=broad-exception-caught
self.fail(f"Error writing image archive {self.path} - {exc}")
def _platform_param(self) -> str:
platform = _Platform.parse_platform_string(self.platform)
platform_spec: dict[str, str] = {}
if platform.os:
platform_spec["os"] = platform.os
if platform.arch:
platform_spec["architecture"] = platform.arch
if platform.variant:
platform_spec["variant"] = platform.variant
return json.dumps(platform_spec)
def export_images(self) -> None:
image_names = [name["joined"] for name in self.names]
image_names_str = ", ".join(image_names)
if len(image_names) == 1:
self.log(f"Getting archive of image {image_names[0]}")
params: dict[str, t.Any] = {}
if self.platform:
params["platform"] = self._platform_param()
try:
chunks = self.client._stream_raw_result(
self.client._get(
self.client._url("/images/{0}/get", image_names[0]), stream=True
self.client._url("/images/{0}/get", image_names[0]),
stream=True,
params=params,
),
chunk_size=DEFAULT_DATA_CHUNK_SIZE,
decode=False,
@ -215,12 +246,15 @@ class ImageExportManager(DockerBaseClass):
self.fail(f"Error getting image {image_names[0]} - {exc}")
else:
self.log(f"Getting archive of images {image_names_str}")
params = {"names": image_names}
if self.platform:
params["platform"] = self._platform_param()
try:
chunks = self.client._stream_raw_result(
self.client._get(
self.client._url("/images/get"),
stream=True,
params={"names": image_names},
params=params,
),
chunk_size=DEFAULT_DATA_CHUNK_SIZE,
decode=False,
@ -277,11 +311,17 @@ def main() -> None:
"aliases": ["name"],
},
"tag": {"type": "str", "default": "latest"},
"platform": {"type": "str"},
}
option_minimal_versions = {
"platform": {"docker_api_version": "1.48"},
}
client = AnsibleDockerClient(
argument_spec=argument_spec,
supports_check_mode=True,
option_minimal_versions=option_minimal_versions,
)
try:

View File

@ -7,6 +7,10 @@
community.docker.current_container_facts:
register: result
- name: Print facts returned by module
ansible.builtin.debug:
var: result.ansible_facts
# The following two tasks are useful if we ever have to debug why this fails.
- name: Print all Ansible facts
@ -20,13 +24,10 @@
- /proc/self/cpuset
- /proc/1/cgroup
- /proc/1/environ
ignore_errors: true # not all of these files always exist
loop_control:
loop_var: path
- name: Print facts returned by module
ansible.builtin.debug:
var: result.ansible_facts
- name: Validate results
ansible.builtin.assert:
that:

View File

@ -27,8 +27,8 @@
- /proc/self/cgroup
- /proc/self/cpuset
- /proc/self/mountinfo
ignore_errors: true # not all of these files always exist
register: slurp
ignore_errors: true
- name: Print files
ansible.builtin.debug:

View File

@ -957,7 +957,7 @@
- when: device_read_bps_1 is failed
ansible.builtin.assert:
that:
- "'error setting cgroup config for procHooks process' in device_read_bps_1.msg and 'blkio.throttle.read_bps_device: no such device' in device_read_bps_1.msg"
- "'error setting cgroup config for procHooks process' in device_read_bps_1.msg and ': no such device' in device_read_bps_1.msg"
####################################################################
## device_read_iops ################################################
@ -1040,7 +1040,7 @@
- when: device_read_iops_1 is failed
ansible.builtin.assert:
that:
- "'error setting cgroup config for procHooks process' in device_read_iops_1.msg and 'blkio.throttle.read_iops_device: no such device' in device_read_iops_1.msg"
- "'error setting cgroup config for procHooks process' in device_read_iops_1.msg and ': no such device' in device_read_iops_1.msg"
####################################################################
## device_write_bps and device_write_iops ##########################
@ -1110,7 +1110,7 @@
- when: device_write_limit_1 is failed
ansible.builtin.assert:
that:
- "'error setting cgroup config for procHooks process' in device_write_limit_1.msg and 'blkio.throttle.write_bps_device: no such device' in device_write_limit_1.msg"
- "'error setting cgroup config for procHooks process' in device_write_limit_1.msg and ': no such device' in device_write_limit_1.msg"
####################################################################
## device_requests #################################################

View File

@ -0,0 +1,34 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- when: docker_api_version is version('1.48', '>=')
block:
- name: Pull image for platform test
community.docker.docker_image_pull:
name: "{{ docker_test_image_hello_world }}"
platform: linux/amd64
- name: Export image with platform (check mode)
community.docker.docker_image_export:
name: "{{ docker_test_image_hello_world }}"
path: "{{ remote_tmp_dir }}/platform-test.tar"
platform: linux/amd64
register: result_check
check_mode: true
- ansible.builtin.assert:
that:
- result_check is changed
- name: Export image with platform
community.docker.docker_image_export:
name: "{{ docker_test_image_hello_world }}"
path: "{{ remote_tmp_dir }}/platform-test.tar"
platform: linux/amd64
register: result
- ansible.builtin.assert:
that:
- result is changed