mirror of
https://github.com/containers/ansible-podman-collections.git
synced 2026-02-03 23:01:48 +00:00
Add podman image scp option (#970)
* Add podman image scp option Fix #536 --------- Signed-off-by: Sagi Shnaidman <sshnaidm@redhat.com>
This commit is contained in:
parent
c2530a63f3
commit
ee52d9de78
6 changed files with 226 additions and 1 deletions
1
.github/workflows/podman_image.yml
vendored
1
.github/workflows/podman_image.yml
vendored
|
|
@ -36,3 +36,4 @@ jobs:
|
|||
with:
|
||||
module_name: 'podman_image'
|
||||
display_name: 'Podman image'
|
||||
extra_collections: 'ansible.posix'
|
||||
|
|
|
|||
11
.github/workflows/reusable-module-test.yml
vendored
11
.github/workflows/reusable-module-test.yml
vendored
|
|
@ -27,6 +27,11 @@ on:
|
|||
required: false
|
||||
type: string
|
||||
default: '["git+https://github.com/ansible/ansible.git@stable-2.18", "git+https://github.com/ansible/ansible.git@devel"]'
|
||||
extra_collections:
|
||||
description: 'Space-separated list of extra Ansible collections to install before running tests (e.g., "ansible.posix community.general")'
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
jobs:
|
||||
test_module:
|
||||
|
|
@ -78,6 +83,12 @@ jobs:
|
|||
~/.local/bin/ansible-galaxy collection build --output-path /tmp/just_new_collection --force
|
||||
~/.local/bin/ansible-galaxy collection install -vvv --force /tmp/just_new_collection/*.tar.gz
|
||||
|
||||
- name: Install extra Ansible collections (optional)
|
||||
if: ${{ inputs.extra_collections != '' }}
|
||||
run: |
|
||||
echo "Installing extra collections: ${{ inputs.extra_collections }}"
|
||||
~/.local/bin/ansible-galaxy collection install -vvv --force ${{ inputs.extra_collections }}
|
||||
|
||||
- name: Run collection tests for ${{ inputs.module_name }}
|
||||
run: |
|
||||
export PATH=~/.local/bin:$PATH
|
||||
|
|
|
|||
|
|
@ -318,6 +318,44 @@ class PodmanImagePusher:
|
|||
|
||||
def push_image(self, image_name, push_config):
|
||||
"""Push an image to a registry."""
|
||||
transport = (push_config or {}).get("transport")
|
||||
|
||||
# Special handling for scp transport which uses 'podman image scp'
|
||||
if transport == "scp":
|
||||
args = []
|
||||
|
||||
# Allow passing global --ssh options to podman
|
||||
ssh_opts = push_config.get("ssh") if push_config else None
|
||||
if ssh_opts:
|
||||
args.extend(["--ssh", ssh_opts])
|
||||
|
||||
args.extend(["image", "scp"])
|
||||
|
||||
# Extra args (e.g., --quiet) if provided
|
||||
if push_config.get("extra_args"):
|
||||
args.extend(shlex.split(push_config["extra_args"]))
|
||||
|
||||
# Source image (local)
|
||||
args.append(image_name)
|
||||
|
||||
# Destination host spec
|
||||
dest = push_config.get("dest")
|
||||
if not dest:
|
||||
self.module.fail_json(msg="When using transport 'scp', push_args.dest must be provided")
|
||||
|
||||
# If user did not include '::' in dest, append it to copy into remote storage with same name
|
||||
dest_spec = dest if "::" in dest else f"{dest}::"
|
||||
args.append(dest_spec)
|
||||
|
||||
action = " ".join(args)
|
||||
rc, out, err = run_podman_command(self.module, self.executable, args, ignore_errors=True)
|
||||
if rc != 0:
|
||||
self.module.fail_json(
|
||||
msg=f"Failed to scp image {image_name} to {dest}", stdout=out, stderr=err, actions=[action]
|
||||
)
|
||||
return out + err, action
|
||||
|
||||
# Default push behavior for all other transports
|
||||
args = ["push"]
|
||||
|
||||
self._add_auth_args(args)
|
||||
|
|
|
|||
|
|
@ -154,6 +154,10 @@ DOCUMENTATION = r"""
|
|||
type: dict
|
||||
default: {}
|
||||
suboptions:
|
||||
ssh:
|
||||
description:
|
||||
- SSH options to use when pushing images with SCP transport.
|
||||
type: str
|
||||
compress:
|
||||
description:
|
||||
- Compress tarball image layers when pushing to a directory using the 'dir' transport.
|
||||
|
|
@ -184,11 +188,12 @@ DOCUMENTATION = r"""
|
|||
type: str
|
||||
choices:
|
||||
- dir
|
||||
- docker
|
||||
- docker-archive
|
||||
- docker-daemon
|
||||
- oci-archive
|
||||
- ostree
|
||||
- docker
|
||||
- scp
|
||||
extra_args:
|
||||
description:
|
||||
- Extra args to pass to push, if executed. Does not idempotently check for new push args.
|
||||
|
|
@ -329,6 +334,15 @@ EXAMPLES = r"""
|
|||
tag: 3
|
||||
dest: docker.io/acme
|
||||
|
||||
- name: Push image to a remote host via scp transport
|
||||
containers.podman.podman_image:
|
||||
name: testimage
|
||||
pull: false
|
||||
push: true
|
||||
push_args:
|
||||
dest: user@server
|
||||
transport: scp
|
||||
|
||||
- name: Pull an image for a specific CPU architecture
|
||||
containers.podman.podman_image:
|
||||
name: nginx
|
||||
|
|
@ -484,6 +498,7 @@ def main():
|
|||
type="dict",
|
||||
default={},
|
||||
options=dict(
|
||||
ssh=dict(type="str"),
|
||||
compress=dict(type="bool"),
|
||||
format=dict(type="str", choices=["oci", "v2s1", "v2s2"]),
|
||||
remove_signatures=dict(type="bool"),
|
||||
|
|
@ -502,6 +517,7 @@ def main():
|
|||
"oci-archive",
|
||||
"ostree",
|
||||
"docker",
|
||||
"scp",
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -186,6 +186,10 @@
|
|||
- extra_args_build is changed
|
||||
- "'Built image test-extra-args:latest from' in extra_args_build.actions[0]"
|
||||
|
||||
# SCP transport tests
|
||||
- name: Include scp transport tests
|
||||
include_tasks: scp.yml
|
||||
|
||||
# Test push functionality with different transports
|
||||
- name: Test push to directory transport
|
||||
containers.podman.podman_image:
|
||||
|
|
|
|||
155
tests/integration/targets/podman_image/tasks/scp.yml
Normal file
155
tests/integration/targets/podman_image/tasks/scp.yml
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
- name: Validate scp transport behavior in podman_image
|
||||
block:
|
||||
- name: Fail when scp transport is used without destination
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: testimage
|
||||
pull: false
|
||||
push: true
|
||||
push_args:
|
||||
transport: scp
|
||||
register: scp_missing_dest
|
||||
ignore_errors: true
|
||||
|
||||
- name: Ensure scp without dest fails with clear message
|
||||
assert:
|
||||
that:
|
||||
- scp_missing_dest is failed
|
||||
- "'push_args.dest must be provided' in scp_missing_dest.msg"
|
||||
|
||||
|
||||
- name: Build a local image to test scp transport idempotence
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: testimage_scp
|
||||
path: /var/tmp/build
|
||||
register: built_local
|
||||
|
||||
- name: Try to scp push to a fake remote (should fail on CI env without remote)
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: testimage_scp
|
||||
pull: false
|
||||
push: true
|
||||
push_args:
|
||||
dest: user@server
|
||||
transport: scp
|
||||
register: scp_push_fake
|
||||
ignore_errors: true
|
||||
|
||||
- name: Ensure scp push to fake remote fails but reports action
|
||||
assert:
|
||||
that:
|
||||
- built_local is changed
|
||||
- scp_push_fake is failed
|
||||
- scp_push_fake.actions is defined
|
||||
|
||||
- name: Prepare SSH access to localhost for scp tests
|
||||
block:
|
||||
|
||||
- name: Ensure SSH keys exist
|
||||
ansible.builtin.shell: >-
|
||||
ssh-keygen -b 2048 -t rsa -f {{ lookup('env','HOME') }}/.ssh/id_rsa -N "" || true
|
||||
args:
|
||||
creates: "{{ lookup('env','HOME') }}/.ssh/id_rsa"
|
||||
|
||||
- name: Get public key for user
|
||||
ansible.builtin.command: >-
|
||||
cat {{ lookup('env','HOME') }}/.ssh/id_rsa.pub
|
||||
register: public_key
|
||||
|
||||
- name: Authorize our public key for localhost for user
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ lookup('env','USER') }}"
|
||||
state: present
|
||||
key: "{{ public_key.stdout }}"
|
||||
|
||||
- name: Authorize our public key for localhost for root user
|
||||
become: true
|
||||
ansible.posix.authorized_key:
|
||||
user: root
|
||||
state: present
|
||||
key: "{{ public_key.stdout }}"
|
||||
|
||||
- name: Start SSH service (Ubuntu uses 'ssh')
|
||||
ansible.builtin.systemd_service:
|
||||
name: ssh
|
||||
state: started
|
||||
become: true
|
||||
ignore_errors: true
|
||||
|
||||
- name: Start SSH service (fallback to 'sshd')
|
||||
ansible.builtin.systemd_service:
|
||||
name: sshd
|
||||
state: started
|
||||
become: true
|
||||
ignore_errors: true
|
||||
|
||||
- name: Verify we can SSH to localhost non-interactively
|
||||
ansible.builtin.command: >-
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null {{ lookup('env','USER') }}@localhost true
|
||||
|
||||
- name: Build a local image for scp to localhost
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: testimage_scp_local
|
||||
path: /var/tmp/build
|
||||
register: built_localhost
|
||||
|
||||
- name: Add system connection for Podman < 5
|
||||
ansible.builtin.command: podman system connection add local --identity {{ lookup('env','HOME') }}/.ssh/id_rsa {{ lookup('env','USER') }}@127.0.0.1
|
||||
|
||||
- name: Add system connection for root user for Podman < 5
|
||||
ansible.builtin.command: podman system connection add rootlocal --identity {{ lookup('env','HOME') }}/.ssh/id_rsa root@127.0.0.1
|
||||
|
||||
- name: Push image to localhost via scp transport
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: testimage_scp_local
|
||||
pull: false
|
||||
push: true
|
||||
push_args:
|
||||
dest: "local::newimage"
|
||||
transport: scp
|
||||
register: scp_localhost_push
|
||||
|
||||
- name: Validate scp localhost push executed
|
||||
assert:
|
||||
that:
|
||||
- built_localhost is changed
|
||||
- scp_localhost_push is changed
|
||||
- scp_localhost_push.actions is defined
|
||||
- scp_localhost_push.podman_actions is defined
|
||||
- scp_localhost_push.actions | select('search', 'image scp') | list | length > 0
|
||||
|
||||
- name: Push image to localhost via scp transport root user
|
||||
containers.podman.podman_image:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: testimage_scp_local
|
||||
pull: false
|
||||
push: true
|
||||
push_args:
|
||||
dest: "rootlocal"
|
||||
transport: scp
|
||||
register: scp_localhost_push
|
||||
|
||||
- name: Validate scp localhost push executed
|
||||
assert:
|
||||
that:
|
||||
- built_localhost is changed
|
||||
- scp_localhost_push is changed
|
||||
- scp_localhost_push.actions is defined
|
||||
- scp_localhost_push.podman_actions is defined
|
||||
- scp_localhost_push.actions | select('search', 'image scp') | list | length > 0
|
||||
|
||||
- name: Ensure image is available for root user
|
||||
become: true
|
||||
ansible.builtin.command: >-
|
||||
podman images --format '{{ '{{.Repository}}:{{.Tag}}' }}' testimage_scp_local
|
||||
register: scp_localhost_root_check
|
||||
|
||||
- name: Validate image is available for root user
|
||||
assert:
|
||||
that:
|
||||
- "'testimage_scp_local:latest' in scp_localhost_root_check.stdout"
|
||||
- scp_localhost_root_check.stderr == ''
|
||||
Loading…
Add table
Add a link
Reference in a new issue