diff --git a/plugins/module_utils/podman/podman_container_lib.py b/plugins/module_utils/podman/podman_container_lib.py index d0acfcd..e35649c 100644 --- a/plugins/module_utils/podman/podman_container_lib.py +++ b/plugins/module_utils/podman/podman_container_lib.py @@ -20,6 +20,7 @@ ARGUMENTS_SPEC_CONTAINER = dict( 'absent', 'present', 'stopped', 'started', 'created']), image=dict(type='str'), annotation=dict(type='dict'), + attach=dict(type='list', elements='str', choices=['stdout', 'stderr', 'stdin']), authfile=dict(type='path'), blkio_weight=dict(type='int'), blkio_weight_device=dict(type='dict'), @@ -40,6 +41,9 @@ ARGUMENTS_SPEC_CONTAINER = dict( cpus=dict(type='str'), cpuset_cpus=dict(type='str'), cpuset_mems=dict(type='str'), + delete_depend=dict(type='bool'), + delete_time=dict(type='str'), + delete_volumes=dict(type='bool'), detach=dict(type='bool', default=True), debug=dict(type='bool', default=False), detach_keys=dict(type='str', no_log=False), @@ -60,6 +64,7 @@ ARGUMENTS_SPEC_CONTAINER = dict( 'exposed', 'exposed_ports']), force_restart=dict(type='bool', default=False, aliases=['restart']), + force_delete=dict(type='bool', default=True), generate_systemd=dict(type='dict', default={}), gidmap=dict(type='list', elements='str'), group_add=dict(type='list', elements='str', aliases=['groups']), @@ -116,6 +121,7 @@ ARGUMENTS_SPEC_CONTAINER = dict( recreate=dict(type='bool', default=False), requires=dict(type='list', elements='str'), restart_policy=dict(type='str'), + restart_time=dict(type='str'), rm=dict(type='bool', aliases=['remove', 'auto_remove']), rootfs=dict(type='bool'), secrets=dict(type='list', elements='str', no_log=True), @@ -125,6 +131,7 @@ ARGUMENTS_SPEC_CONTAINER = dict( sig_proxy=dict(type='bool'), stop_signal=dict(type='int'), stop_timeout=dict(type='int'), + stop_time=dict(type='str'), subgidname=dict(type='str'), subuidname=dict(type='str'), sysctl=dict(type='dict'), @@ -231,12 +238,35 @@ class PodmanModuleParams: def start_stop_delete(self): + def complete_params(cmd): + if self.params['attach'] and self.action == 'start': + cmd.append('--attach') + if self.params['detach'] is False and self.action == 'start' and '--attach' not in cmd: + cmd.append('--attach') + if self.params['detach_keys'] and self.action == 'start': + cmd += ['--detach-keys', self.params['detach_keys']] + if self.params['sig_proxy'] and self.action == 'start': + cmd.append('--sig-proxy') + if self.params['stop_time'] and self.action == 'stop': + cmd += ['--time', self.params['stop_time']] + if self.params['restart_time'] and self.action == 'restart': + cmd += ['--time', self.params['restart_time']] + if self.params['delete_depend'] and self.action == 'delete': + cmd.append('--depend') + if self.params['delete_time'] and self.action == 'delete': + cmd += ['--time', self.params['delete_time']] + if self.params['delete_volumes'] and self.action == 'delete': + cmd.append('--volumes') + if self.params['force_delete'] and self.action == 'delete': + cmd.append('--force') + return cmd + if self.action in ['stop', 'start', 'restart']: - cmd = [self.action, self.params['name']] + cmd = complete_params([self.action]) + [self.params['name']] return [to_bytes(i, errors='surrogate_or_strict') for i in cmd] if self.action == 'delete': - cmd = ['rm', '-f', self.params['name']] + cmd = complete_params(['rm']) + [self.params['name']] return [to_bytes(i, errors='surrogate_or_strict') for i in cmd] def check_version(self, param, minv=None, maxv=None): @@ -256,6 +286,11 @@ class PodmanModuleParams: c += ['--annotation', '='.join(annotate)] return c + def addparam_attach(self, c): + for attach in self.params['attach']: + c += ['--attach=%s' % attach] + return c + def addparam_authfile(self, c): return c + ['--authfile', self.params['authfile']] @@ -319,6 +354,9 @@ class PodmanModuleParams: return c + ['--cpuset-mems', self.params['cpuset_mems']] def addparam_detach(self, c): + # Remove detach from create command and don't set if attach is true + if self.action == 'create' or self.params['attach']: + return c return c + ['--detach=%s' % self.params['detach']] def addparam_detach_keys(self, c): @@ -1499,8 +1537,6 @@ class PodmanContainer: self.version, self.module, ).construct_command_from_params() - if action == 'create': - b_command.remove(b'--detach=True') full_cmd = " ".join([self.module_params['executable']] + [to_native(i) for i in b_command]) self.actions.append(full_cmd) @@ -1520,7 +1556,7 @@ class PodmanContainer: self.stderr = err if rc != 0: self.module.fail_json( - msg="Can't %s container %s" % (action, self.name), + msg="Container %s exited with code %s when %sed" % (self.name, rc, action), stdout=out, stderr=err) def run(self): diff --git a/plugins/modules/podman_container.py b/plugins/modules/podman_container.py index 0fc62e6..4d23fe3 100644 --- a/plugins/modules/podman_container.py +++ b/plugins/modules/podman_container.py @@ -76,6 +76,15 @@ options: - Add an annotation to the container. The format is key value, multiple times. type: dict + attach: + description: + - Attach to STDIN, STDOUT or STDERR. The default in Podman is false. + type: list + elements: str + choices: + - stdin + - stdout + - stderr authfile: description: - Path of the authentication file. Default is @@ -184,6 +193,22 @@ options: - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. type: str + delete_depend: + description: + - Remove selected container and recursively remove all containers that depend on it. + Applies to "delete" command. + type: bool + delete_time: + description: + - Seconds to wait before forcibly stopping the container. Use -1 for infinite wait. + Applies to "delete" command. + type: str + delete_volumes: + description: + - Remove anonymous volumes associated with the container. + This does not include named volumes created with podman volume create, + or the --volume option of podman run and podman create. + type: bool detach: description: - Run container in detach mode @@ -300,6 +325,11 @@ options: default: False aliases: - restart + force_delete: + description: + - Force deletion of container when it's being deleted. + type: bool + default: True generate_systemd: description: - Generate systemd unit file for container. @@ -722,6 +752,11 @@ options: * always - Restart containers when they exit, regardless of status, retrying indefinitely type: str + restart_time: + description: + - Seconds to wait before forcibly stopping the container when restarting. Use -1 for infinite wait. + Applies to "restarted" status. + type: str rm: description: - Automatically remove the container when it exits. The default is false. @@ -769,6 +804,11 @@ options: description: - Signal to stop a container. Default is SIGTERM. type: int + stop_time: + description: + - Seconds to wait before forcibly stopping the container. Use -1 for infinite wait. + Applies to "stopped" status. + type: str stop_timeout: description: - Timeout (in seconds) to stop a container. Default is 10. diff --git a/tests/integration/targets/podman_container/tasks/main.yml b/tests/integration/targets/podman_container/tasks/main.yml index b211590..0f7888e 100644 --- a/tests/integration/targets/podman_container/tasks/main.yml +++ b/tests/integration/targets/podman_container/tasks/main.yml @@ -610,7 +610,7 @@ - name: Check podman_actions assert: that: - - "'podman rm -f testidem' in remove.podman_actions" + - "'podman rm --force testidem' in remove.podman_actions" # - name: Create a pod # shell: podman pod create --name testidempod @@ -901,6 +901,115 @@ fail_msg: Rootfs container test failed! success_msg: Rootfs container test passed! + - name: Run started container with attaching + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + image: alpine:3.7 + state: started + command: ls /nonexists + attach: + - stdout + - stderr + register: attach + ignore_errors: true + + - name: Check output is correct for started container with attaching + assert: + that: + - attach is failed + - "'No such file or directory' in attach.stderr" + + - name: Delete container with attaching + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + state: absent + + - name: Create container with attaching in created state + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + image: alpine:3.7 + state: created + command: ls /nonexists + attach: + - stdout + - stderr + + - name: Start container with attaching from created state + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + state: started + attach: + - stdout + - stderr + register: attach2 + ignore_errors: true + + - name: Check output is correct for started container with attaching from created state + assert: + that: + - attach2 is failed + - "'No such file or directory' in attach2.stderr" + + - name: Delete container with attaching from created state + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + state: absent + + - name: Create container without attaching in created state + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + image: alpine:3.7 + state: created + command: ls /nonexists + + - name: Start container without attaching from created state + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + state: started + register: attach21 + + - name: Check output is correct for container without attaching from created state + assert: + that: + - attach21 is success + + - name: Delete container without attaching from created state + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + state: absent + + - name: Create container with detach False + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + image: alpine:3.7 + state: created + command: ls /nonexists + detach: false + + - name: Start container with detach False + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: container1 + state: started + detach: false + register: attach3 + ignore_errors: true + + - name: Check output is correct for started container with detach False + assert: + that: + - attach3 is failed + - "'No such file or directory' in attach3.stderr" + always: - name: Remove container diff --git a/tests/integration/targets/podman_containers/tasks/main.yml b/tests/integration/targets/podman_containers/tasks/main.yml index 69c94b3..9eabd50 100644 --- a/tests/integration/targets/podman_containers/tasks/main.yml +++ b/tests/integration/targets/podman_containers/tasks/main.yml @@ -612,7 +612,7 @@ - name: Check podman_actions assert: that: - - "'podman rm -f testidem' in remove.podman_actions" + - "'podman rm --force testidem' in remove.podman_actions" - name: Create a pod containers.podman.podman_pod: