mirror of
https://github.com/containers/ansible-podman-collections.git
synced 2026-02-04 07:11:49 +00:00
Add podman_container_exec module (#627)
* Add podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> * Update podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> * Add tests for podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> * Update examples for podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> * Fix CI errors Signed-off-by: nishipy <goodisonev4@gmail.com> * Fix CI errors Signed-off-by: nishipy <goodisonev4@gmail.com> * Fix typo Signed-off-by: nishipy <goodisonev4@gmail.com> * Add workflow for podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> * Fix python version in the workflow for podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> * Fix python version in the workflow for podman_container_exec Signed-off-by: nishipy <goodisonev4@gmail.com> --------- Signed-off-by: nishipy <goodisonev4@gmail.com>
This commit is contained in:
parent
c6ae4b97e7
commit
bc3670f8dc
4 changed files with 418 additions and 0 deletions
99
.github/workflows/podman_container_exec.yml
vendored
Normal file
99
.github/workflows/podman_container_exec.yml
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
name: Podman container exec
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/podman_container_exec.yml'
|
||||
- 'ci/*.yml'
|
||||
- 'ci/run_containers_tests.sh'
|
||||
- 'ci/playbooks/containers/podman_container_exec.yml'
|
||||
- 'plugins/modules/podman_container_exec.py'
|
||||
- 'tests/integration/targets/podman_container_exec/**'
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/podman_container_exec.yml'
|
||||
- 'ci/*.yml'
|
||||
- 'ci/run_containers_tests.sh'
|
||||
- 'ci/playbooks/containers/podman_container_exec.yml'
|
||||
- 'plugins/modules/podman_container_exec.py'
|
||||
- 'tests/integration/targets/podman_container_exec/**'
|
||||
schedule:
|
||||
- cron: 4 0 * * * # Run daily at 0:03 UTC
|
||||
|
||||
jobs:
|
||||
|
||||
test_podman_container_exec:
|
||||
name: Podman container exec ${{ matrix.ansible-version }}-${{ matrix.os || 'ubuntu-22.04' }}
|
||||
runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ansible-version:
|
||||
- ansible<2.10
|
||||
# - git+https://github.com/ansible/ansible.git@stable-2.11
|
||||
- git+https://github.com/ansible/ansible.git@devel
|
||||
os:
|
||||
- ubuntu-22.04
|
||||
python-version:
|
||||
- "3.10"
|
||||
|
||||
steps:
|
||||
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Upgrade pip and display Python and PIP versions
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y python*-wheel python*-yaml
|
||||
python -m pip install --upgrade pip
|
||||
python -V
|
||||
pip --version
|
||||
- name: Set up pip cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ github.ref }}-units-VMs
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
${{ runner.os }}-
|
||||
- name: Install Ansible ${{ matrix.ansible-version }}
|
||||
run: python3 -m pip install --user --force-reinstall --upgrade '${{ matrix.ansible-version }}'
|
||||
|
||||
- name: Build and install the collection tarball
|
||||
run: |
|
||||
rm -rf /tmp/just_new_collection
|
||||
~/.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: Run collection tests for Podman container exec
|
||||
run: |
|
||||
export PATH=~/.local/bin:$PATH
|
||||
echo "Run ansible version"
|
||||
command -v ansible
|
||||
ansible --version
|
||||
export ANSIBLE_CONFIG=$(pwd)/ci/ansible-dev.cfg
|
||||
if [[ '${{ matrix.ansible-version }}' == 'ansible<2.10' ]]; then
|
||||
export ANSIBLE_CONFIG=$(pwd)/ci/ansible-2.9.cfg
|
||||
fi
|
||||
echo $ANSIBLE_CONFIG
|
||||
command -v ansible-playbook
|
||||
pip --version
|
||||
python --version
|
||||
ansible-playbook --version
|
||||
ansible-playbook -vv ci/playbooks/pre.yml \
|
||||
-e host=localhost \
|
||||
-i localhost, \
|
||||
-e ansible_connection=local \
|
||||
-e setup_python=false
|
||||
TEST2RUN=podman_container_exec ./ci/run_containers_tests.sh
|
||||
shell: bash
|
||||
8
ci/playbooks/containers/podman_container_exec.yml
Normal file
8
ci/playbooks/containers/podman_container_exec.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- hosts: all
|
||||
gather_facts: true
|
||||
tasks:
|
||||
- include_role:
|
||||
name: podman_container_exec
|
||||
vars:
|
||||
ansible_python_interpreter: "{{ _ansible_python_interpreter }}"
|
||||
244
plugins/modules/podman_container_exec.py
Normal file
244
plugins/modules/podman_container_exec.py
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
#!/usr/bin/python
|
||||
# coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Takuya Nishimura <@nishipy>
|
||||
# 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_container_exec
|
||||
author:
|
||||
- Takuya Nishimura (@nishipy)
|
||||
short_description: Executes a command in a running container.
|
||||
description:
|
||||
- Executes a command in a running container.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the container where the command is executed.
|
||||
type: str
|
||||
required: true
|
||||
command:
|
||||
description:
|
||||
- The command to run in the container.
|
||||
- One of the I(command) or I(args) is required.
|
||||
type: str
|
||||
argv:
|
||||
description:
|
||||
- Passes the command as a list rather than a string.
|
||||
- One of the I(command) or I(args) is required.
|
||||
type: list
|
||||
elements: str
|
||||
detach:
|
||||
description:
|
||||
- If true, the command runs in the background.
|
||||
- The exec session is automatically removed when it completes.
|
||||
type: bool
|
||||
default: false
|
||||
env:
|
||||
description:
|
||||
- Set environment variables.
|
||||
type: dict
|
||||
privileged:
|
||||
description:
|
||||
- Give extended privileges to the container.
|
||||
type: bool
|
||||
default: false
|
||||
tty:
|
||||
description:
|
||||
- Allocate a pseudo-TTY.
|
||||
type: bool
|
||||
default: false
|
||||
user:
|
||||
description:
|
||||
- The username or UID used and, optionally, the groupname or GID for the specified command.
|
||||
- Both user and group may be symbolic or numeric.
|
||||
type: str
|
||||
workdir:
|
||||
description:
|
||||
- Working directory inside the container.
|
||||
type: str
|
||||
requirements:
|
||||
- podman
|
||||
notes:
|
||||
- See L(the Podman documentation,https://docs.podman.io/en/latest/markdown/podman-exec.1.html) for details of podman-exec(1).
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Execute a command with workdir
|
||||
containers.podman.podman_container_exec:
|
||||
name: ubi8
|
||||
command: "cat redhat-release"
|
||||
workdir: /etc
|
||||
|
||||
- name: Execute a command with a list of args and enviroment variables
|
||||
containers.podman.podman_container_exec:
|
||||
name: test_container
|
||||
argv:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- echo $HELLO $BYE
|
||||
env:
|
||||
HELLO: hello world
|
||||
BYE: goodbye world
|
||||
|
||||
- name: Execute command in background by using detach
|
||||
containers.podman.podman_container_exec:
|
||||
name: detach_container
|
||||
command: "cat redhat-release"
|
||||
detach: true
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
stdout:
|
||||
type: str
|
||||
returned: success
|
||||
description:
|
||||
- The standard output of the command executed in the container.
|
||||
stderr:
|
||||
type: str
|
||||
returned: success
|
||||
description:
|
||||
- The standard output of the command executed in the container.
|
||||
rc:
|
||||
type: int
|
||||
returned: success
|
||||
sample: 0
|
||||
description:
|
||||
- The exit code of the command executed in the container.
|
||||
exec_id:
|
||||
type: str
|
||||
returned: success and I(detach=true)
|
||||
sample: f99002e34c1087fd1aa08d5027e455bf7c2d6b74f019069acf6462a96ddf2a47
|
||||
description:
|
||||
- The ID of the exec session.
|
||||
'''
|
||||
|
||||
|
||||
import shlex
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.containers.podman.plugins.module_utils.podman.common import run_podman_command
|
||||
|
||||
|
||||
def run_container_exec(module: AnsibleModule) -> dict:
|
||||
'''
|
||||
Execute podman-container-exec for the given options
|
||||
'''
|
||||
exec_with_args = ['container', 'exec']
|
||||
# podman_container_exec always returns changed=true
|
||||
changed = True
|
||||
exec_options = []
|
||||
|
||||
name = module.params['name']
|
||||
argv = module.params['argv']
|
||||
command = module.params['command']
|
||||
detach = module.params['detach']
|
||||
env = module.params['env']
|
||||
privileged = module.params['privileged']
|
||||
tty = module.params['tty']
|
||||
user = module.params['user']
|
||||
workdir = module.params['workdir']
|
||||
|
||||
if command is not None:
|
||||
argv = shlex.split(command)
|
||||
|
||||
if detach:
|
||||
exec_options.append('--detach')
|
||||
|
||||
if env is not None:
|
||||
for key, value in env.items():
|
||||
if not isinstance(value, string_types):
|
||||
module.fail_json(
|
||||
msg="Specify string value %s on the env field" % (value))
|
||||
|
||||
to_text(value, errors='surrogate_or_strict')
|
||||
exec_options += ['--env',
|
||||
'%s="%s"' % (key, value)]
|
||||
|
||||
if privileged:
|
||||
exec_options.append('--privileged')
|
||||
|
||||
if tty:
|
||||
exec_options.append('--tty')
|
||||
|
||||
if user is not None:
|
||||
exec_options += ['--user',
|
||||
to_text(user, errors='surrogate_or_strict')]
|
||||
|
||||
if workdir is not None:
|
||||
exec_options += ['--workdir',
|
||||
to_text(workdir, errors='surrogate_or_strict')]
|
||||
|
||||
exec_options.append(name)
|
||||
exec_options.extend(argv)
|
||||
|
||||
exec_with_args.extend(exec_options)
|
||||
|
||||
rc, stdout, stderr = run_podman_command(
|
||||
module=module, executable='podman', args=exec_with_args)
|
||||
|
||||
result = {
|
||||
'changed': changed,
|
||||
'podman_command': exec_options,
|
||||
'rc': rc,
|
||||
'stdout': stdout,
|
||||
'stderr': stderr,
|
||||
}
|
||||
|
||||
if detach:
|
||||
result['exec_id'] = stdout.replace('\n', '')
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = {
|
||||
'name': {
|
||||
'type': 'str',
|
||||
'required': True,
|
||||
},
|
||||
'command': {
|
||||
'type': 'str',
|
||||
},
|
||||
'argv': {
|
||||
'type': 'list',
|
||||
'elements': 'str',
|
||||
},
|
||||
'detach': {
|
||||
'type': 'bool',
|
||||
'default': False,
|
||||
},
|
||||
'env': {
|
||||
'type': 'dict',
|
||||
},
|
||||
'privileged': {
|
||||
'type': 'bool',
|
||||
'default': False,
|
||||
},
|
||||
'tty': {
|
||||
'type': 'bool',
|
||||
'default': False,
|
||||
},
|
||||
'user': {
|
||||
'type': 'str',
|
||||
},
|
||||
'workdir': {
|
||||
'type': 'str',
|
||||
},
|
||||
}
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=[('argv', 'command')],
|
||||
)
|
||||
|
||||
result = run_container_exec(module)
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
- name: Test podman_container_exec
|
||||
block:
|
||||
- name: Generate random value for container name
|
||||
set_fact:
|
||||
container_name: "{{ 'ansible-test-podman-%0x' % ((2**32) | random) }}"
|
||||
|
||||
- name: Make sure container doesn't exist
|
||||
containers.podman.podman_container:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ container_name }}"
|
||||
state: absent
|
||||
|
||||
- name: Test exec when the container doesn't exist
|
||||
containers.podman.podman_container_exec:
|
||||
name: "{{ container_name }}"
|
||||
command: "cat /etc/redhat-release"
|
||||
ignore_errors: true
|
||||
register: no_container
|
||||
|
||||
- name: Create and start a container for testing
|
||||
containers.podman.podman_container:
|
||||
name: "{{ container_name }}"
|
||||
image: registry.access.redhat.com/ubi8
|
||||
command: sleep 1d
|
||||
state: started
|
||||
|
||||
- name: Test exec with command and workdir options
|
||||
containers.podman.podman_container_exec:
|
||||
name: "{{ container_name }}"
|
||||
command: "cat redhat-release"
|
||||
workdir: /etc
|
||||
register: exec1
|
||||
|
||||
- name: Test exec with argv and env options
|
||||
containers.podman.podman_container_exec:
|
||||
name: "{{ container_name }}"
|
||||
argv:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- echo $HELLO $BYE
|
||||
env:
|
||||
HELLO: hello world
|
||||
BYE: goodbye world
|
||||
register: exec2
|
||||
|
||||
- name: Test exec with detach option
|
||||
containers.podman.podman_container_exec:
|
||||
name: "{{ container_name }}"
|
||||
command: "cat redhat-release"
|
||||
detach: true
|
||||
register: exec3
|
||||
|
||||
- name: Check if the result is as expected
|
||||
assert:
|
||||
that:
|
||||
- no_container is failed
|
||||
- "'Red Hat Enterprise Linux' in exec1.stdout"
|
||||
- "'hello world' in exec2.stdout"
|
||||
- "'goodbye world' in exec2.stdout"
|
||||
- exec3.exec_id is defined
|
||||
|
||||
always:
|
||||
- name: Cleanup
|
||||
containers.podman.podman_container:
|
||||
executable: "{{ test_executable | default('podman') }}"
|
||||
name: "{{ container_name }}"
|
||||
state: absent
|
||||
Loading…
Add table
Add a link
Reference in a new issue