mirror of
https://github.com/containers/ansible-podman-collections.git
synced 2026-02-04 07:11:49 +00:00
Fix image idempotency in pull (#983)
Fix #981 Signed-off-by: Sagi Shnaidman <sshnaidm@redhat.com>
This commit is contained in:
parent
cf7008fb0e
commit
c9dd956776
3 changed files with 94 additions and 4 deletions
|
|
@ -569,11 +569,27 @@ class PodmanImageManager:
|
|||
"""Ensure image is present (pull or build if needed)."""
|
||||
image = self.find_image()
|
||||
|
||||
# Get digest before any operations
|
||||
digest_before = None
|
||||
if image:
|
||||
inspect_data = self.inspector.inspect_image(self.repository.full_name)
|
||||
if inspect_data and len(inspect_data) > 0:
|
||||
digest_before = inspect_data[0].get("Digest") or inspect_data[0].get("digest")
|
||||
# If Digest is not available, try to get from RepoDigests
|
||||
if not digest_before:
|
||||
repo_digests = inspect_data[0].get("RepoDigests", [])
|
||||
if repo_digests:
|
||||
# Extract digest from first RepoDigest (format: repo@sha256:...)
|
||||
for repo_digest in repo_digests:
|
||||
if "@" in repo_digest:
|
||||
digest_before = repo_digest.split("@", 1)[1]
|
||||
break
|
||||
|
||||
if not image or self._should_rebuild_image(image):
|
||||
if self.params.get("state") == "build" or self.params.get("path"):
|
||||
self._build_image()
|
||||
else:
|
||||
self._pull_image()
|
||||
self._pull_image(digest_before)
|
||||
|
||||
if self.params.get("push"):
|
||||
self._push_image()
|
||||
|
|
@ -611,7 +627,7 @@ class PodmanImageManager:
|
|||
self.results["changed"] = True
|
||||
self.results["actions"].append(f"Built image {self.repository.full_name} from {path or 'context'}")
|
||||
|
||||
def _pull_image(self):
|
||||
def _pull_image(self, digest_before=None):
|
||||
"""Pull an image."""
|
||||
if not self.params.get("pull", True):
|
||||
self.module.fail_json(msg=f"Image {self.repository.full_name} not found locally and pull is disabled")
|
||||
|
|
@ -623,8 +639,27 @@ class PodmanImageManager:
|
|||
self.results["image"] = self.inspector.inspect_image(self.repository.full_name)
|
||||
self.results["podman_actions"].append(podman_command)
|
||||
|
||||
self.results["changed"] = True
|
||||
self.results["actions"].append(f"Pulled image {self.repository.full_name}")
|
||||
# Check if digest actually changed
|
||||
digest_after = None
|
||||
if self.results["image"] and len(self.results["image"]) > 0:
|
||||
digest_after = self.results["image"][0].get("Digest") or self.results["image"][0].get("digest")
|
||||
# If Digest is not available, try to get from RepoDigests
|
||||
if not digest_after:
|
||||
repo_digests = self.results["image"][0].get("RepoDigests", [])
|
||||
if repo_digests:
|
||||
# Extract digest from first RepoDigest (format: repo@sha256:...)
|
||||
for repo_digest in repo_digests:
|
||||
if "@" in repo_digest:
|
||||
digest_after = repo_digest.split("@", 1)[1]
|
||||
break
|
||||
|
||||
changed = digest_before != digest_after
|
||||
self.results["changed"] = changed
|
||||
if changed:
|
||||
self.results["actions"].append(f"Pulled image {self.repository.full_name}")
|
||||
else:
|
||||
self.results["changed"] = True
|
||||
self.results["actions"].append(f"Pulled image {self.repository.full_name}")
|
||||
|
||||
def _push_image(self):
|
||||
"""Push an image."""
|
||||
|
|
|
|||
|
|
@ -589,6 +589,7 @@
|
|||
- include_tasks: additional_tests.yml
|
||||
|
||||
- include_tasks: test_issue_947.yml
|
||||
- include_tasks: test_issue_981.yml
|
||||
|
||||
always:
|
||||
- name: Cleanup images
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
# Test for issue #981: podman_image with force=true should be idempotent
|
||||
# https://github.com/containers/ansible-podman-collections/issues/981
|
||||
|
||||
- name: Test issue # 981 - Remove alpine image if exists
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: docker.io/library/alpine
|
||||
tag: latest
|
||||
state: absent
|
||||
ignore_errors: true
|
||||
|
||||
- name: Test issue # 981 - Pull alpine image first time
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: docker.io/library/alpine
|
||||
tag: latest
|
||||
register: issue_981_pull1
|
||||
|
||||
- name: Test issue # 981 - Pull alpine with force=true (same digest, should not change)
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: docker.io/library/alpine
|
||||
tag: latest
|
||||
force: true
|
||||
register: issue_981_pull2
|
||||
|
||||
- name: Test issue # 981 - Pull alpine with force=true again (same digest, should not change)
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: docker.io/library/alpine
|
||||
tag: latest
|
||||
force: true
|
||||
register: issue_981_pull3
|
||||
|
||||
- name: Test issue # 981 - Verify force=true idempotency
|
||||
assert:
|
||||
that:
|
||||
- issue_981_pull1 is changed
|
||||
- issue_981_pull1.actions | length > 0
|
||||
- "'Pulled image' in issue_981_pull1.actions[0]"
|
||||
- issue_981_pull2 is not changed
|
||||
- issue_981_pull2.actions | length == 0
|
||||
- issue_981_pull3 is not changed
|
||||
- issue_981_pull3.actions | length == 0
|
||||
fail_msg: "Issue #981 not fixed: force=true is not idempotent when digest hasn't changed"
|
||||
success_msg: "Issue #981 fixed: force=true is idempotent when digest hasn't changed"
|
||||
|
||||
- name: Test issue # 981 - Cleanup
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: docker.io/library/alpine
|
||||
tag: latest
|
||||
state: absent
|
||||
Loading…
Add table
Add a link
Reference in a new issue