Skip to content

Commit eb46429

Browse files
authored
Add podman_container_copy module (#813)
Signed-off-by: kubealex <[email protected]>
1 parent 202a0fb commit eb46429

File tree

4 files changed

+342
-0
lines changed

4 files changed

+342
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Podman Container Copy module
2+
3+
on:
4+
push:
5+
paths:
6+
- '.github/workflows/podman_container_copy.yml'
7+
- 'ci/*.yml'
8+
- 'ci/run_containers_tests.sh'
9+
- 'ci/playbooks/containers/podman_container_copy.yml'
10+
- 'plugins/modules/podman_container_copy.py'
11+
- 'tests/integration/targets/podman_container_copy/**'
12+
branches:
13+
- master
14+
pull_request:
15+
paths:
16+
- '.github/workflows/podman_container_copy.yml'
17+
- 'ci/*.yml'
18+
- 'ci/run_containers_tests.sh'
19+
- 'ci/playbooks/containers/podman_container_copy.yml'
20+
- 'plugins/modules/podman_container_copy.py'
21+
- 'tests/integration/targets/podman_container_copy/**'
22+
schedule:
23+
- cron: 4 0 * * * # Run daily at 0:03 UTC
24+
25+
jobs:
26+
27+
test_podman_container_copy:
28+
name: Podman Container Copy ${{ matrix.ansible-version }}-${{ matrix.os || 'ubuntu-22.04' }}
29+
runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
30+
defaults:
31+
run:
32+
shell: bash
33+
strategy:
34+
fail-fast: false
35+
matrix:
36+
ansible-version:
37+
- ansible<2.10
38+
# - git+https://github.com/ansible/[email protected]
39+
- git+https://github.com/ansible/ansible.git@devel
40+
os:
41+
- ubuntu-22.04
42+
python-version:
43+
- 3.11
44+
45+
steps:
46+
47+
- name: Check out repository
48+
uses: actions/checkout@v3
49+
50+
- name: Set up Python ${{ matrix.python-version }}
51+
uses: actions/setup-python@v4
52+
with:
53+
python-version: ${{ matrix.python-version }}
54+
55+
- name: Upgrade pip and display Python and PIP versions
56+
run: |
57+
sudo apt-get update
58+
sudo apt-get install -y python*-wheel python*-yaml
59+
python -m pip install --upgrade pip
60+
python -V
61+
pip --version
62+
- name: Set up pip cache
63+
uses: actions/cache@v3
64+
with:
65+
path: ~/.cache/pip
66+
key: ${{ runner.os }}-pip-${{ github.ref }}-units-VMs
67+
restore-keys: |
68+
${{ runner.os }}-pip-
69+
${{ runner.os }}-
70+
- name: Install Ansible ${{ matrix.ansible-version }}
71+
run: python3 -m pip install --user --force-reinstall --upgrade '${{ matrix.ansible-version }}'
72+
73+
- name: Build and install the collection tarball
74+
run: |
75+
rm -rf /tmp/just_new_collection
76+
~/.local/bin/ansible-galaxy collection build --output-path /tmp/just_new_collection --force
77+
~/.local/bin/ansible-galaxy collection install -vvv --force /tmp/just_new_collection/*.tar.gz
78+
- name: Run collection tests for Podman Container Copy module
79+
run: |
80+
export PATH=~/.local/bin:$PATH
81+
echo "Run ansible version"
82+
command -v ansible
83+
ansible --version
84+
export ANSIBLE_CONFIG=$(pwd)/ci/ansible-dev.cfg
85+
if [[ '${{ matrix.ansible-version }}' == 'ansible<2.10' ]]; then
86+
export ANSIBLE_CONFIG=$(pwd)/ci/ansible-2.9.cfg
87+
fi
88+
echo $ANSIBLE_CONFIG
89+
command -v ansible-playbook
90+
pip --version
91+
python --version
92+
ansible-playbook --version
93+
ansible-playbook -vv ci/playbooks/pre.yml \
94+
-e host=localhost \
95+
-i localhost, \
96+
-e ansible_connection=local \
97+
-e setup_python=false
98+
TEST2RUN=podman_container_copy ./ci/run_containers_tests.sh
99+
shell: bash
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
- hosts: all
3+
gather_facts: true
4+
tasks:
5+
- include_role:
6+
name: podman_container_copy
7+
vars:
8+
ansible_python_interpreter: "{{ _ansible_python_interpreter }}"
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/python
2+
# Copyright (c) 2024 Ansible Project
3+
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
4+
5+
from __future__ import absolute_import, division, print_function
6+
__metaclass__ = type
7+
8+
9+
DOCUMENTATION = r'''
10+
module: podman_container_copy
11+
author:
12+
- Alessandro Rossi (@kubealex)
13+
short_description: Copy file to/from a container
14+
notes:
15+
- Podman may required elevated privileges in order to run properly.
16+
description:
17+
- Copy file or folder from the host to a container and vice-versa.
18+
options:
19+
executable:
20+
description:
21+
- Path to C(podman) executable if it is not in the C($PATH) on the machine running C(podman)
22+
default: 'podman'
23+
type: str
24+
src:
25+
description:
26+
- Path of the file/folder to copy from/to the container
27+
type: str
28+
required: True
29+
dest:
30+
description:
31+
- Path of the destination file/folder to copy from/to the container
32+
required: True
33+
type: str
34+
container:
35+
description:
36+
- Name/ID of the container to copy from/to
37+
required: True
38+
type: str
39+
from_container:
40+
description:
41+
- Specify whether or not the file must be copied from the container to the host
42+
required: False
43+
default: False
44+
type: bool
45+
archive:
46+
description:
47+
- Chown copied files to the primary uid/gid of the destination container.
48+
required: False
49+
default: True
50+
type: bool
51+
overwrite:
52+
description:
53+
- Allow to overwrite directories with non-directories and vice versa
54+
required: False
55+
default: False
56+
type: bool
57+
'''
58+
59+
EXAMPLES = r"""
60+
- name: Copy file "test.yml" on the host to the "apache" container's root folder
61+
containers.podman.podman_search:
62+
src: test.yml
63+
dest: /
64+
container: apache
65+
- name: Copy file "test.yml" in the "apache" container's root folder to the playbook's folder
66+
containers.podman.podman_search:
67+
src: /test.yml
68+
dest: ./
69+
container: apache
70+
from_container: True
71+
"""
72+
73+
from ansible.module_utils.basic import AnsibleModule
74+
75+
76+
def copy_file(module, executable, src, dest, container, from_container, archive, overwrite):
77+
if from_container:
78+
command = [executable, 'cp', '{0}:{1}'.format(container, src), dest]
79+
else:
80+
command = [executable, 'cp', src, '{0}:{1}'.format(container, dest)]
81+
82+
if not archive:
83+
command.append('--archive=False')
84+
85+
if overwrite:
86+
command.append('--overwrite')
87+
88+
rc, out, err = module.run_command(command)
89+
90+
if rc != 0:
91+
module.fail_json(msg='Unable to copy file to/from container - {out}'.format(out=err))
92+
else:
93+
changed = True
94+
return changed, out, err
95+
96+
97+
def main():
98+
module = AnsibleModule(
99+
argument_spec=dict(
100+
executable=dict(type='str', default='podman'),
101+
src=dict(type='str', required=True),
102+
dest=dict(type='str', required=True),
103+
container=dict(type='str', required=True),
104+
from_container=dict(type='bool', required=False, default=False),
105+
archive=dict(type='bool', required=False, default=True),
106+
overwrite=dict(type='bool', required=False, default=False)
107+
),
108+
supports_check_mode=False,
109+
)
110+
111+
executable = module.params['executable']
112+
src = module.params['src']
113+
dest = module.params['dest']
114+
container = module.params['container']
115+
from_container = module.params['from_container']
116+
archive = module.params['archive']
117+
overwrite = module.params['overwrite']
118+
119+
executable = module.get_bin_path(executable, required=True)
120+
121+
changed, out, err = copy_file(module, executable, src, dest, container, from_container, archive, overwrite)
122+
123+
results = dict(
124+
changed=changed
125+
)
126+
127+
module.exit_json(**results)
128+
129+
130+
if __name__ == '__main__':
131+
main()
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
- name: Test podman container copy host-container
3+
block:
4+
- name: Generate random value for container name
5+
ansible.builtin.set_fact:
6+
container_name: "{{ 'ansible-test-podman-%0x' % ((2**32) | random) }}"
7+
file_name: sample_file
8+
9+
- name: Start container
10+
containers.podman.podman_container:
11+
executable: "{{ test_executable | default('podman') }}"
12+
name: "{{ container_name }}"
13+
image: alpine:3.7
14+
state: started
15+
command: sleep 1d
16+
17+
- name: Create local file to copy
18+
ansible.builtin.copy:
19+
content: |
20+
This file tests if host -> container copy is working
21+
dest: "{{ playbook_dir }}/{{ file_name }}"
22+
mode: "0755"
23+
24+
- name: Copy local file to containers root folder
25+
containers.podman.podman_container_copy:
26+
executable: "{{ test_executable | default('podman') }}"
27+
src: "{{ playbook_dir }}/{{ file_name }}"
28+
dest: "/{{ file_name }}"
29+
container: "{{ container_name }}"
30+
31+
- name: Verify that the file exists in the container
32+
containers.podman.podman_container_exec:
33+
executable: "{{ test_executable | default('podman') }}"
34+
name: "{{ container_name }}"
35+
command: "cat /{{ file_name }}"
36+
37+
always:
38+
- name: Remove container
39+
containers.podman.podman_container:
40+
executable: "{{ test_executable | default('podman') }}"
41+
name: "{{ container_name }}"
42+
state: absent
43+
44+
- name: Remove local file
45+
ansible.builtin.file:
46+
path: "{{ playbook_dir }}/{{ file_name }}"
47+
state: absent
48+
49+
- name: Test podman container copy container-host
50+
block:
51+
- name: Generate random value for container name
52+
ansible.builtin.set_fact:
53+
container_name: "{{ 'ansible-test-podman-%0x' % ((2**32) | random) }}"
54+
file_name: sample_file
55+
56+
- name: Start container
57+
containers.podman.podman_container:
58+
executable: "{{ test_executable | default('podman') }}"
59+
name: "{{ container_name }}"
60+
image: alpine:3.7
61+
state: started
62+
command: sleep 1d
63+
64+
- name: Create file in the container for further copy
65+
containers.podman.podman_container_exec:
66+
executable: "{{ test_executable | default('podman') }}"
67+
name: "{{ container_name }}"
68+
command: sh -c 'echo "This file tests if container -> host copy is working" > /{{ file_name }}'
69+
70+
- name: Verify that the file exists in the container
71+
containers.podman.podman_container_exec:
72+
executable: "{{ test_executable | default('podman') }}"
73+
name: "{{ container_name }}"
74+
command: "cat /{{ file_name }}"
75+
76+
- name: Copy local file to containers root folder
77+
containers.podman.podman_container_copy:
78+
executable: "{{ test_executable | default('podman') }}"
79+
src: "/{{ file_name }}"
80+
dest: "{{ playbook_dir }}/{{ file_name }}"
81+
container: "{{ container_name }}"
82+
from_container: true
83+
84+
- name: Check file
85+
ansible.builtin.stat:
86+
path: "{{ playbook_dir }}/{{ file_name }}"
87+
register: copied_file
88+
89+
- name: Check it's present
90+
ansible.builtin.assert:
91+
that:
92+
- copied_file.stat.exists
93+
94+
always:
95+
- name: Remove container
96+
containers.podman.podman_container:
97+
executable: "{{ test_executable | default('podman') }}"
98+
name: "{{ container_name }}"
99+
state: absent
100+
101+
- name: Remove local file
102+
ansible.builtin.file:
103+
path: "{{ playbook_dir }}/{{ file_name }}"
104+
state: absent

0 commit comments

Comments
 (0)