Skip to content

Commit

Permalink
Adding podman_copy with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DilasserT committed Sep 8, 2024
1 parent 46d4378 commit 04f1404
Show file tree
Hide file tree
Showing 3 changed files with 389 additions and 0 deletions.
8 changes: 8 additions & 0 deletions ci/playbooks/containers/podman_copy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- hosts: all
gather_facts: true
tasks:
- include_role:
name: podman_copy
vars:
ansible_python_interpreter: "{{ _ansible_python_interpreter }}"
167 changes: 167 additions & 0 deletions plugins/modules/podman_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#!/usr/bin/python
# coding: utf-8 -*-

# Copyright (c) 2021, Sagi Shnaidman <[email protected]>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r'''
module: podman_copy
short_description: Copy from/to containers
author: Thomas Dilasser (@DilasserT)
description:
- podman copies files from/to the container from/to the local machine.
options:
path:
description:
- Filesystem path.
type: str
required: true
container_path:
description:
- Path inside the container
type: str
required: true
into_container:
description:
- Copy in the container.
type: bool
from_container:
description:
- Copy from the container.
type: bool
container:
description:
- container name.
type: str
required: true
archive:
description:
- Chown copied file to the primary uid/gid of the destined container.
type: bool
default: true
overwrite:
description:
- Allow to overwrite directories with non-directories and vice versa
type: bool
default: False
force:
description:
- Overwrite file if it exists.
type: bool
default: false
executable:
description:
- Path to C(podman) executable if it is not in the C($PATH) on the
machine running C(podman)
default: 'podman'
type: str
requirements:
- "Podman installed on host"
'''

RETURN = '''
'''

EXAMPLES = '''
# What modules does for example
- containers.podman.podman_copy:
path: /path/to/file
container_path: /path/to/file/in/container
container: container-name
from_container: true
- containers.podman.podman_copy:
path: /path/to/file
container_path: /path/to/file/in/container
container: container-name
into_container: true
'''

import os # noqa: E402
import json
from ansible.module_utils.basic import AnsibleModule # noqa: E402


def copy(module, executable):
changed = True
command = [executable, 'cp']
if not module.params['archive']:
command += ["--archive=false"]
if module.params['overwrite']:
command += ["--overwrite=true"]
container_name = module.params['container']
if module.params['into_container']:
command += [module.params['path']]
command += [module.params['container'] + ":" + module.params['container_path']]
command_inspect = [executable, 'container', 'inspect']
command_inspect.extend([container_name])
rc, out, err = module.run_command(command_inspect)
if rc != 0:
module.fail_json(msg="Unable to gather info for %s: %s" % (",".join(module.params['container']), err))
else:
json_out = json.loads(out) if out else None
if json_out is None:
module.fail_json(msg="Unable to gather info for %s: %s" % (",".join(module.params['container']), err))

full_path = json_out[0]['GraphDriver']['Data']['MergedDir']
if module.params['path'][0] == "/":
full_path += module.params['container_path']
else:
full_path += "/"
full_path += module.params['container_path']

if os.path.exists(full_path) and not module.params['force']:
changed = False
return changed, '', ''

else:
command += [module.params['container'] + ":" + module.params['container_path']]
command += [module.params['path']]
if os.path.exists(module.params['path']) and not module.params['force']:
changed = False
return changed, '', ''

rc, out, err = module.run_command(command)
if rc != 0:
module.fail_json(msg="Error during copy %s: %s" % (
module.params['container'], err))
return changed, out, err


def main():
module = AnsibleModule(
argument_spec=dict(
path=dict(type='str', required=True),
container_path=dict(type='str', required=True),
container=dict(type='str', required=True),
into_container=dict(type='bool'),
from_container=dict(type='bool'),
force=dict(type='bool', default=False),
archive=dict(type='bool', default=True),
overwrite=dict(type='bool', default=False),
executable=dict(type='str', default='podman')
),
supports_check_mode=True,
mutually_exclusive=[
('from_container', 'into_container'),
],
required_one_of=[
('from_container', 'into_container'),
],
)

executable = module.get_bin_path(module.params['executable'], required=True)
changed, out, err = copy(module, executable)

results = {
"changed": changed,
"stdout": out,
"stderr": err,
}
module.exit_json(**results)


if __name__ == '__main__':
main()
214 changes: 214 additions & 0 deletions tests/integration/targets/podman_copy/tasks/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
---
- name: Test podman copy
block:
- name: run container
containers.podman.podman_container:
name: container
image: alpine:3.7
user: 999:999
state: started
command: sleep 1d

- name: Create test file
file:
path: /tmp/podman_copy.txt
state: touch

- name: Get container info
containers.podman.podman_container_info:
name: container
register: cntr_info

- name: Copy into container
containers.podman.podman_copy:
path: '/tmp/podman_copy.txt'
container_path: '/podman_copy.txt'
container: container
into_container: true
register: copy1

- name: Check first copy
assert:
that:
- copy1 is success
- copy1 is changed

- name: Stat file in container
stat:
path: "{{ cntr_info['containers'][0]['GraphDriver']['Data']['MergedDir'] }}/podman_copy.txt"
register: file_check

- name: check file is in container with container perms
assert:
that:
- file_check.stat.islnk is defined
- file_check.stat.islnk == False
- file_check.stat.uid == 999
- file_check.stat.gid == 999

- name: Copy into container without force
containers.podman.podman_copy:
path: '/tmp/podman_copy.txt'
container_path: '/podman_copy.txt'
container: container
into_container: true
register: copy2

- name: Check second copy
assert:
that:
- copy2 is success
- copy2 is not changed

- name: Copy into container (forced)
containers.podman.podman_copy:
path: '/tmp/podman_copy.txt'
container_path: '/podman_copy.txt'
container: container
force: true
into_container: true
register: copy3

- name: Check third copy
assert:
that:
- copy3 is success
- copy3 is changed

- name: Copy into container without archive (forced)
containers.podman.podman_copy:
path: '/tmp/podman_copy.txt'
container_path: '/podman_copy.txt'
container: container
force: true
archive: false
into_container: true
register: copy4

- name: Check third copy
assert:
that:
- copy4 is success
- copy4 is changed

- name: Stat file in container for archive test
stat:
path: "{{ cntr_info['containers'][0]['GraphDriver']['Data']['MergedDir'] }}/podman_copy.txt"
register: file_check

- name: check file is in container and has root perms
assert:
that:
- file_check.stat.islnk is defined
- file_check.stat.uid == 0
- file_check.stat.gid == 0

- name: Create overwrite file
file:
path: "/tmp/overwrite_obj"
state: touch

- name: Create file to overwrite in container
containers.podman.podman_container_exec:
name: container
command: "mkdir /tmp/overwrite_obj"

- name: Copy file on dir in container with overwrite
containers.podman.podman_copy:
path: '/tmp/overwrite_obj'
container_path: '/tmp/'
container: container
overwrite: true
force: true
into_container: true
register: copy5

- name: Check fifth copy
assert:
that:
- copy5 is success
- copy5 is changed

- name: Stat dir in container
stat:
path: "{{ cntr_info['containers'][0]['GraphDriver']['Data']['MergedDir'] }}/tmp/overwrite_obj"
register: file_check

- name: check file is in container and has root perms
assert:
that:
- file_check.stat.islnk is defined
- file_check.stat.islnk == False
- file_check.stat.isdir == False

- name: Copy from container
containers.podman.podman_copy:
path: '/tmp/podman_copy_from.txt'
container_path: '/podman_copy.txt'
container: container
from_container: true
register: copy6

- name: Stat file in /tmp
stat:
path: "/tmp/podman_copy_from.txt"
register: file_check

- name: Check sixth copy
assert:
that:
- copy6 is success
- copy6 is changed

- name: Check file is in container
assert:
that:
- file_check.stat.islnk is defined
- file_check.stat.islnk == False

- name: Copy from container without force
containers.podman.podman_copy:
path: '/tmp/podman_copy_from.txt'
container_path: '/podman_copy.txt'
container: container
from_container: true
register: copy7

- name: Check seventh copy
assert:
that:
- copy7 is success
- copy7 is not changed

- name: Copy from container (forced)
containers.podman.podman_copy:
path: '/tmp/podman_copy_from.txt'
container_path: '/podman_copy.txt'
container: container
force: true
from_container: true
register: copy8

- name: Check eighth copy
assert:
that:
- copy8 is success
- copy8 is changed

always:
- name: stop container
containers.podman.podman_container:
state: absent
name: container
- name: Clean up test file
file:
path: /tmp/podman_copy.txt
state: absent
- name: Clean up test file
file:
path: /tmp/podman_copy_from.txt
state: absent
- name: Clean up test dir
file:
path: /tmp/overwrite_dir
state: absent

0 comments on commit 04f1404

Please sign in to comment.