mirror of
https://github.com/containers/ansible-podman-collections.git
synced 2026-03-21 18:19:07 +00:00
Add --platform option to podman_image
Fix #1003 Signed-off-by: Sagi Shnaidman <sshnaidm@redhat.com>
This commit is contained in:
parent
cc98f4430c
commit
88999e2bcf
4 changed files with 77 additions and 9 deletions
|
|
@ -136,9 +136,9 @@ class PodmanImageBuilder:
|
|||
self.executable = executable
|
||||
self.auth_config = auth_config or {}
|
||||
|
||||
def build_image(self, image_name, build_config, path=None, containerfile_hash=None):
|
||||
def build_image(self, image_name, build_config, path=None, containerfile_hash=None, platform=None):
|
||||
"""Build an image with the given configuration."""
|
||||
args = self._construct_build_args(image_name, build_config, path, containerfile_hash)
|
||||
args = self._construct_build_args(image_name, build_config, path, containerfile_hash, platform)
|
||||
|
||||
# Handle inline container file
|
||||
temp_file_path = None
|
||||
|
|
@ -162,13 +162,17 @@ class PodmanImageBuilder:
|
|||
if temp_file_path and os.path.exists(temp_file_path):
|
||||
os.remove(temp_file_path)
|
||||
|
||||
def _construct_build_args(self, image_name, build_config, path, containerfile_hash):
|
||||
def _construct_build_args(self, image_name, build_config, path, containerfile_hash, platform=None):
|
||||
"""Construct build command arguments."""
|
||||
args = ["build", "-t", image_name]
|
||||
|
||||
# Add authentication
|
||||
self._add_auth_args(args)
|
||||
|
||||
# Add platform for cross-platform builds
|
||||
if platform:
|
||||
args.extend(["--platform", platform])
|
||||
|
||||
# Add build-specific arguments
|
||||
if build_config.get("force_rm"):
|
||||
args.append("--force-rm")
|
||||
|
|
@ -268,11 +272,13 @@ class PodmanImagePuller:
|
|||
self.executable = executable
|
||||
self.auth_config = auth_config or {}
|
||||
|
||||
def pull_image(self, image_name, arch=None, pull_extra_args=None):
|
||||
def pull_image(self, image_name, arch=None, platform=None, pull_extra_args=None):
|
||||
"""Pull an image from a registry."""
|
||||
args = ["pull", image_name]
|
||||
|
||||
if arch:
|
||||
if platform:
|
||||
args.extend(["--platform", platform])
|
||||
elif arch:
|
||||
args.extend(["--arch", arch])
|
||||
|
||||
self._add_auth_args(args)
|
||||
|
|
@ -533,10 +539,28 @@ class PodmanImageManager:
|
|||
|
||||
# Check architecture if specified
|
||||
arch = self.params.get("arch")
|
||||
platform = self.params.get("platform")
|
||||
if arch:
|
||||
inspect_data = self.inspector.inspect_image(image_name)
|
||||
if inspect_data and inspect_data[0].get("Architecture") != arch:
|
||||
return None
|
||||
elif platform:
|
||||
# Platform format: os/arch or os/arch/variant (e.g. linux/amd64)
|
||||
inspect_data = self.inspector.inspect_image(image_name)
|
||||
if inspect_data:
|
||||
platform_parts = platform.split("/")
|
||||
required_os = platform_parts[0] if len(platform_parts) >= 1 else None
|
||||
required_arch = platform_parts[1] if len(platform_parts) >= 2 else None
|
||||
img_os = inspect_data[0].get("Os") or inspect_data[0].get("os")
|
||||
img_arch = inspect_data[0].get("Architecture") or inspect_data[0].get("architecture")
|
||||
# Normalize arch for comparison (e.g. x86_64 -> amd64, aarch64 -> arm64)
|
||||
arch_map = {"x86_64": "amd64", "aarch64": "arm64"}
|
||||
if img_arch and img_arch in arch_map:
|
||||
img_arch = arch_map[img_arch]
|
||||
if required_os and img_os != required_os:
|
||||
return None
|
||||
if required_arch and img_arch != required_arch:
|
||||
return None
|
||||
|
||||
return images
|
||||
|
||||
|
|
@ -618,7 +642,8 @@ class PodmanImageManager:
|
|||
# Build the image
|
||||
if not self.module.check_mode:
|
||||
image_id, output, podman_command = self.builder.build_image(
|
||||
self.repository.full_name, build_config, path, containerfile_hash
|
||||
self.repository.full_name, build_config, path, containerfile_hash,
|
||||
self.params.get("platform")
|
||||
)
|
||||
self.results["stdout"] = output
|
||||
self.results["image"] = self.inspector.inspect_image(image_id)
|
||||
|
|
@ -634,7 +659,10 @@ class PodmanImageManager:
|
|||
|
||||
if not self.module.check_mode:
|
||||
unused, podman_command = self.puller.pull_image(
|
||||
self.repository.full_name, self.params.get("arch"), self.params.get("pull_extra_args")
|
||||
self.repository.full_name,
|
||||
self.params.get("arch"),
|
||||
self.params.get("platform"),
|
||||
self.params.get("pull_extra_args"),
|
||||
)
|
||||
self.results["image"] = self.inspector.inspect_image(self.repository.full_name)
|
||||
self.results["podman_actions"].append(podman_command)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ DOCUMENTATION = r"""
|
|||
description:
|
||||
- CPU architecture for the container image
|
||||
type: str
|
||||
platform:
|
||||
description:
|
||||
- Platform for the container image (e.g. C(linux/amd64), C(linux/arm64)).
|
||||
- Specify the platform for selecting the image when pulling or building.
|
||||
- Mutually exclusive with C(arch).
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Name of the image to pull, push, or delete. It may contain a tag using the format C(image:tag).
|
||||
|
|
@ -348,6 +354,11 @@ EXAMPLES = r"""
|
|||
name: nginx
|
||||
arch: amd64
|
||||
|
||||
- name: Pull an image for a specific platform (e.g. x86 on M-series Mac)
|
||||
containers.podman.podman_image:
|
||||
name: nginx
|
||||
platform: linux/amd64
|
||||
|
||||
- name: Build a container from file inline
|
||||
containers.podman.podman_image:
|
||||
name: mycustom_image
|
||||
|
|
@ -456,6 +467,7 @@ def main():
|
|||
argument_spec=dict(
|
||||
name=dict(type="str", required=True),
|
||||
arch=dict(type="str"),
|
||||
platform=dict(type="str"),
|
||||
tag=dict(type="str", default="latest"),
|
||||
pull=dict(type="bool", default=True),
|
||||
pull_extra_args=dict(type="str"),
|
||||
|
|
@ -528,6 +540,7 @@ def main():
|
|||
mutually_exclusive=(
|
||||
["auth_file", "username"],
|
||||
["auth_file", "password"],
|
||||
["arch", "platform"],
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -380,6 +380,26 @@
|
|||
- item.Architecture == "arm"
|
||||
loop: "{{ imageinfo_arch.images }}"
|
||||
|
||||
- name: Pull an image for a specific platform
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: quay.io/coreos/etcd:v3.5.27
|
||||
platform: linux/amd64
|
||||
register: pull_platform1
|
||||
|
||||
- name: Pull the same image for the same platform
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: quay.io/coreos/etcd:v3.5.27
|
||||
platform: linux/amd64
|
||||
register: pull_platform2
|
||||
|
||||
- name: Ensure platform pull is idempotent
|
||||
assert:
|
||||
that:
|
||||
- pull_platform1 is changed
|
||||
- pull_platform2 is not changed
|
||||
|
||||
- name: Build Docker image
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
|
|
@ -599,9 +619,11 @@
|
|||
state: absent
|
||||
loop:
|
||||
- docker.io/library/ubuntu
|
||||
- docker.io/library/alpine
|
||||
- quay.io/sshnaidm1/alpine-sh
|
||||
- quay.io/coreos/etcd:v3.3.11
|
||||
- quay.io/coreos/etcd:v3.5.19
|
||||
- quay.io/coreos/etcd:v3.5.27
|
||||
- localhost/testimage
|
||||
- localhost/testimage2
|
||||
- localhost/testimage2:testtag
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ class TestPodmanImageModule:
|
|||
),
|
||||
# Valid authentication parameters
|
||||
({"name": "alpine", "username": "testuser", "password": "testpass"}, True),
|
||||
# Valid platform parameter (issue #1003)
|
||||
({"name": "alpine", "platform": "linux/amd64"}, True),
|
||||
],
|
||||
)
|
||||
def test_module_parameter_validation(self, test_params, expected_valid):
|
||||
|
|
@ -138,19 +140,22 @@ class TestPodmanImageModule:
|
|||
mutually_exclusive_combinations = [
|
||||
({"auth_file": "/path/to/auth", "username": "user"}, True),
|
||||
({"auth_file": "/path/to/auth", "password": "pass"}, True),
|
||||
({"arch": "amd64", "platform": "linux/amd64"}, True), # arch and platform
|
||||
({"username": "user", "password": "pass"}, False), # This should be allowed
|
||||
({"auth_file": "/path/to/auth"}, False), # This should be allowed
|
||||
({"platform": "linux/amd64"}, False), # platform alone is allowed
|
||||
]
|
||||
|
||||
for params, should_be_exclusive in mutually_exclusive_combinations:
|
||||
# This tests the logic of mutual exclusion
|
||||
has_auth_file = "auth_file" in params
|
||||
has_credentials = "username" in params or "password" in params
|
||||
has_arch_and_platform = "arch" in params and "platform" in params
|
||||
|
||||
if should_be_exclusive:
|
||||
assert has_auth_file and has_credentials
|
||||
assert (has_auth_file and has_credentials) or has_arch_and_platform
|
||||
else:
|
||||
assert not (has_auth_file and has_credentials) or not has_auth_file
|
||||
assert not (has_auth_file and has_credentials) and not has_arch_and_platform
|
||||
|
||||
def test_required_together_logic(self):
|
||||
"""Test that username and password are required together."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue