diff --git a/plugins/module_utils/podman/common.py b/plugins/module_utils/podman/common.py index cbb6b08..aac7b60 100644 --- a/plugins/module_utils/podman/common.py +++ b/plugins/module_utils/podman/common.py @@ -337,3 +337,88 @@ def get_podman_version(module, fail=True): (executable, err)) return None return out.split("version")[1].strip() + + +def createcommand(argument, info_config, boolean_type=False): + """Returns list of values for given argument from CreateCommand + from Podman container inspect output. + + Args: + argument (str): argument name + info_config (dict): dictionary with container info + boolean_type (bool): if True, then argument is boolean type + + Returns: + + all_values: list of values for given argument from createcommand + """ + if "createcommand" not in info_config: + return [] + cr_com = info_config["createcommand"] + argument_values = ARGUMENTS_OPTS_DICT.get(argument, [argument]) + all_values = [] + for arg in argument_values: + for ind, cr_opt in enumerate(cr_com): + if arg == cr_opt: + if boolean_type: + # This is a boolean argument and doesn't have value + return [True] + if not cr_com[ind + 1].startswith("-"): + # This is a key=value argument + all_values.append(cr_com[ind + 1]) + else: + # This is also a false/true switching argument + return [True] + if cr_opt.startswith("%s=" % arg): + all_values.append(cr_opt.split("=", 1)[1]) + return all_values + + +def diff_generic(params, info_config, module_arg, cmd_arg, boolean_type=False): + """ + Generic diff function for module arguments from CreateCommand + in Podman inspection output. + + Args: + params (dict): module parameters + info_config (dict): dictionary with container info + module_arg (str): module argument name + cmd_arg (str): command line argument name + boolean_type (bool): if True, then argument is boolean type + + Returns: + bool: True if there is a difference, False otherwise + + """ + before = createcommand(cmd_arg, info_config, boolean_type=boolean_type) + if before == []: + before = None + after = params[module_arg] + if boolean_type and (before, after) in [(None, False), (False, None)]: + before, after = False, False + return before, after + if before is None and after is None: + return before, after + if after is not None: + if isinstance(after, list): + after = ",".join(sorted([str(i).lower() for i in after])) + if before: + before = ",".join(sorted([str(i).lower() for i in before])) + elif isinstance(after, dict): + after = ",".join(sorted( + [str(k).lower() + "=" + str(v).lower() for k, v in after.items() if v is not None])) + if before: + before = ",".join(sorted([j.lower() for j in before])) + elif isinstance(after, bool): + after = str(after).capitalize() + if before is not None: + before = str(before[0]).capitalize() + elif isinstance(after, int): + after = str(after) + if before is not None: + before = str(before[0]) + else: + before = before[0] if before else None + else: + before = ",".join(sorted(before)) if len(before) > 1 else before[0] + return before, after diff --git a/plugins/module_utils/podman/podman_container_lib.py b/plugins/module_utils/podman/podman_container_lib.py index 5c7bb9b..82baaa5 100644 --- a/plugins/module_utils/podman/podman_container_lib.py +++ b/plugins/module_utils/podman/podman_container_lib.py @@ -8,7 +8,8 @@ from ansible_collections.containers.podman.plugins.module_utils.podman.common im from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys from ansible_collections.containers.podman.plugins.module_utils.podman.common import generate_systemd from ansible_collections.containers.podman.plugins.module_utils.podman.common import delete_systemd -from ansible_collections.containers.podman.plugins.module_utils.podman.common import ARGUMENTS_OPTS_DICT +from ansible_collections.containers.podman.plugins.module_utils.podman.common import diff_generic +from ansible_collections.containers.podman.plugins.module_utils.podman.common import createcommand from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import create_quadlet_state from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import ContainerQuadlet @@ -913,39 +914,6 @@ class PodmanContainerDiff: params_with_defaults[p] = self.module_params[p] return params_with_defaults - def _createcommand(self, argument, boolean_type=False): - """Returns list of values for given argument from CreateCommand - from Podman container inspect output. - - Args: - argument (str): argument name - boolean_type (bool): if True, then argument is boolean type - - Returns: - - all_values: list of values for given argument from createcommand - """ - if "createcommand" not in self.info["config"]: - return [] - cr_com = self.info["config"]["createcommand"] - argument_values = ARGUMENTS_OPTS_DICT.get(argument, [argument]) - all_values = [] - for arg in argument_values: - for ind, cr_opt in enumerate(cr_com): - if arg == cr_opt: - if boolean_type: - # This is a boolean argument and doesn't have value - return [True] - if not cr_com[ind + 1].startswith("-"): - # This is a key=value argument - all_values.append(cr_com[ind + 1]) - else: - # This is also a false/true switching argument - return [True] - if cr_opt.startswith("%s=" % arg): - all_values.append(cr_opt.split("=", 1)[1]) - return all_values - def _diff_update_and_compare(self, param_name, before, after): if before != after: self.diff['before'].update({param_name: before}) @@ -967,37 +935,8 @@ class PodmanContainerDiff: bool: True if there is a difference, False otherwise """ - before = self._createcommand(cmd_arg, boolean_type=boolean_type) - if before == []: - before = None - after = self.params[module_arg] - if boolean_type and (before, after) in [(None, False), (False, None)]: - before, after = False, False - return self._diff_update_and_compare(module_arg, before, after) - if before is None and after is None: - return self._diff_update_and_compare(module_arg, before, after) - if after is not None: - if isinstance(after, list): - after = ",".join(sorted([str(i).lower() for i in after])) - if before: - before = ",".join(sorted([str(i).lower() for i in before])) - elif isinstance(after, dict): - after = ",".join(sorted( - [str(k).lower() + "=" + str(v).lower() for k, v in after.items() if v is not None])) - if before: - before = ",".join(sorted([j.lower() for j in before])) - elif isinstance(after, bool): - after = str(after).capitalize() - if before is not None: - before = str(before[0]).capitalize() - elif isinstance(after, int): - after = str(after) - if before is not None: - before = str(before[0]) - else: - before = before[0] if before else None - else: - before = ",".join(sorted(before)) if len(before) > 1 else before[0] + info_config = self.info["config"] + before, after = diff_generic(self.params, info_config, module_arg, cmd_arg, boolean_type) return self._diff_update_and_compare(module_arg, before, after) def diffparam_annotation(self): @@ -1489,7 +1428,7 @@ class PodmanContainerDiff: return "/" return x.replace("//", "/").rstrip("/") - before = self._createcommand('--volume') + before = createcommand('--volume', self.info['config']) if before == []: before = None after = self.params['volume'] diff --git a/plugins/module_utils/podman/podman_pod_lib.py b/plugins/module_utils/podman/podman_pod_lib.py index c81321f..013bc0a 100644 --- a/plugins/module_utils/podman/podman_pod_lib.py +++ b/plugins/module_utils/podman/podman_pod_lib.py @@ -6,6 +6,8 @@ from ansible_collections.containers.podman.plugins.module_utils.podman.common im from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys from ansible_collections.containers.podman.plugins.module_utils.podman.common import generate_systemd from ansible_collections.containers.podman.plugins.module_utils.podman.common import delete_systemd +from ansible_collections.containers.podman.plugins.module_utils.podman.common import diff_generic +from ansible_collections.containers.podman.plugins.module_utils.podman.common import createcommand from ansible_collections.containers.podman.plugins.module_utils.podman.quadlet import create_quadlet_state, PodQuadlet @@ -28,9 +30,9 @@ ARGUMENTS_SPEC_POD = dict( ]), recreate=dict(type='bool', default=False), add_host=dict(type='list', required=False, elements='str'), - cgroup_parent=dict(type='str', required=False), blkio_weight=dict(type='str', required=False), blkio_weight_device=dict(type='list', elements='str', required=False), + cgroup_parent=dict(type='str', required=False), cpus=dict(type='str', required=False), cpuset_cpus=dict(type='str', required=False), cpuset_mems=dict(type='str', required=False), @@ -39,8 +41,9 @@ ARGUMENTS_SPEC_POD = dict( device_read_bps=dict(type='list', elements='str', required=False), device_write_bps=dict(type='list', elements='str', required=False), dns=dict(type='list', elements='str', required=False), - dns_opt=dict(type='list', elements='str', required=False), + dns_opt=dict(type='list', elements='str', aliases=['dns_option'], required=False), dns_search=dict(type='list', elements='str', required=False), + exit_policy=dict(type='str', required=False, choices=['continue', 'stop']), generate_systemd=dict(type='dict', default={}), gidmap=dict(type='list', elements='str', required=False), gpus=dict(type='str', required=False), @@ -69,6 +72,7 @@ ARGUMENTS_SPEC_POD = dict( quadlet_dir=dict(type='path'), quadlet_filename=dict(type='str'), quadlet_options=dict(type='list', elements='str'), + restart_policy=dict(type='str', required=False), security_opt=dict(type='list', elements='str', required=False), share=dict(type='str', required=False), share_parent=dict(type='bool', required=False), @@ -209,7 +213,7 @@ class PodmanPodModuleParams: def addparam_dns_opt(self, c): for g in self.params['dns_opt']: - c += ['--dns-opt', g] + c += ['--dns-option', g] return c def addparam_dns_search(self, c): @@ -217,6 +221,9 @@ class PodmanPodModuleParams: c += ['--dns-search', g] return c + def addparam_exit_policy(self, c): + return c + ['--exit-policy=%s' % self.params['exit_policy']] + def addparam_gidmap(self, c): for gidmap in self.params['gidmap']: c += ['--gidmap', gidmap] @@ -300,6 +307,9 @@ class PodmanPodModuleParams: c += ['--publish', g] return c + def addparam_restart_policy(self, c): + return c + ['--restart=%s' % self.params['restart_policy']] + def addparam_security_opt(self, c): for g in self.params['security_opt']: c += ['--security-opt', g] @@ -358,10 +368,6 @@ class PodmanPodDefaults: self.module = module self.version = podman_version self.defaults = { - 'add_host': [], - 'dns': [], - 'dns_opt': [], - 'dns_search': [], 'infra': True, 'label': {}, } @@ -405,50 +411,77 @@ class PodmanPodDiff: return True return False + def _diff_generic(self, module_arg, cmd_arg, boolean_type=False): + """ + Generic diff function for module arguments from CreateCommand + in Podman inspection output. + + Args: + module_arg (str): module argument name + cmd_arg (str): command line argument name + boolean_type (bool): if True, then argument is boolean type + + Returns: + bool: True if there is a difference, False otherwise + + """ + info_config = self.info + before, after = diff_generic(self.params, info_config, module_arg, cmd_arg, boolean_type) + return self._diff_update_and_compare(module_arg, before, after) + def diffparam_add_host(self): - if not self.infra_info: - return self._diff_update_and_compare('add_host', '', '') - before = self.infra_info['hostconfig']['extrahosts'] or [] - after = self.params['add_host'] - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('add_host', before, after) + return self._diff_generic('add_host', '--add-host') + + def diffparam_blkio_weight(self): + return self._diff_generic('blkio_weight', '--blkio-weight') + + def diffparam_blkio_weight_device(self): + return self._diff_generic('blkio_weight_device', '--blkio-weight-device') def diffparam_cgroup_parent(self): - before = (self.info.get('cgroupparent', '') - or self.info.get('hostconfig', {}).get('cgroupparent', '')) - after = self.params['cgroup_parent'] or before - return self._diff_update_and_compare('cgroup_parent', before, after) + return self._diff_generic('cgroup_parent', '--cgroup-parent') + + def diffparam_cpu_shares(self): + return self._diff_generic('cpu_shares', '--cpu-shares') + + def diffparam_cpus(self): + return self._diff_generic('cpus', '--cpus') + + def diffparam_cpuset_cpus(self): + return self._diff_generic('cpuset_cpus', '--cpuset-cpus') + + def diffparam_cpuset_mems(self): + return self._diff_generic('cpuset_mems', '--cpuset-mems') + + def diffparam_device(self): + return self._diff_generic('device', '--device') + + def diffparam_device_read_bps(self): + return self._diff_generic('device_read_bps', '--device-read-bps') + + def diffparam_device_write_bps(self): + return self._diff_generic('device_write_bps', '--device-write-bps') def diffparam_dns(self): - if not self.infra_info: - return self._diff_update_and_compare('dns', '', '') - before = self.infra_info['hostconfig']['dns'] or [] - after = self.params['dns'] - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('dns', before, after) + return self._diff_generic('dns', '--dns') def diffparam_dns_opt(self): - if not self.infra_info: - return self._diff_update_and_compare('dns_opt', '', '') - before = self.infra_info['hostconfig']['dnsoptions'] or [] - after = self.params['dns_opt'] - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('dns_opt', before, after) + return self._diff_generic('dns_opt', '--dns-option') def diffparam_dns_search(self): - if not self.infra_info: - return self._diff_update_and_compare('dns_search', '', '') - before = self.infra_info['hostconfig']['dnssearch'] or [] - after = self.params['dns_search'] - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('dns_search', before, after) + return self._diff_generic('dns_search', '--dns-search') + + def diffparam_exit_policy(self): + return self._diff_generic('exit_policy', '--exit-policy') + + def diffparam_gidmap(self): + return self._diff_generic('gidmap', '--gidmap') + + def diffparam_gpus(self): + return self._diff_generic('gpus', '--gpus') def diffparam_hostname(self): - if not self.infra_info: - return self._diff_update_and_compare('hostname', '', '') - before = self.infra_info['config']['hostname'] - after = self.params['hostname'] or before - return self._diff_update_and_compare('hostname', before, after) + return self._diff_generic('hostname', '--hostname') # TODO(sshnaidm): https://github.com/containers/podman/issues/6968 def diffparam_infra(self): @@ -460,30 +493,23 @@ class PodmanPodDiff: after = self.params['infra'] return self._diff_update_and_compare('infra', before, after) - # TODO(sshnaidm): https://github.com/containers/podman/issues/6969 - # def diffparam_infra_command(self): - # before = str(self.info['hostconfig']['infra_command']) - # after = self.params['infra_command'] - # return self._diff_update_and_compare('infra_command', before, after) + def diffparam_infra_command(self): + return self._diff_generic('infra_command', '--infra-command') + + def diffparam_infra_conmon_pidfile(self): + return self._diff_generic('infra_conmon_pidfile', '--infra-conmon-pidfile') def diffparam_infra_image(self): - if not self.infra_info: - return self._diff_update_and_compare('infra_image', '', '') - before = str(self.infra_info['imagename']) - after = before - if self.module_params['infra_image']: - after = self.params['infra_image'] - before = before.replace(":latest", "") - after = after.replace(":latest", "") - before = before.split("/")[-1] # pylint: disable=W,C,R - after = after.split("/")[-1] # pylint: disable=W,C,R - return self._diff_update_and_compare('infra_image', before, after) + return self._diff_generic('infra_image', '--infra-image') - # TODO(sshnaidm): https://github.com/containers/podman/pull/6956 - # def diffparam_ip(self): - # before = str(self.info['hostconfig']['ip']) - # after = self.params['ip'] - # return self._diff_update_and_compare('ip', before, after) + def diffparam_infra_name(self): + return self._diff_generic('infra_name', '--infra-name') + + def diffparam_ip(self): + return self._diff_generic('ip', '--ip') + + def diffparam_ip6(self): + return self._diff_generic('ip6', '--ip6') def diffparam_label(self): if 'config' in self.info and 'labels' in self.info['config']: @@ -498,129 +524,99 @@ class PodmanPodDiff: before.pop('podman_systemd_unit', None) return self._diff_update_and_compare('label', before, after) - # TODO(sshnaidm): https://github.com/containers/podman/pull/6956 - # def diffparam_mac_address(self): - # before = str(self.info['hostconfig']['mac_address']) - # after = self.params['mac_address'] - # return self._diff_update_and_compare('mac_address', before, after) + def diffparam_label_file(self): + return self._diff_generic('label_file', '--label-file') + + def diffparam_mac_address(self): + return self._diff_generic('mac_address', '--mac-address') + + def diffparam_memory(self): + return self._diff_generic('memory', '--memory') + + def diffparam_memory_swap(self): + return self._diff_generic('memory_swap', '--memory-swap') def diffparam_network(self): - if not self.infra_info: - return self._diff_update_and_compare('network', [], []) - net_mode_before = self.infra_info['hostconfig']['networkmode'] - net_mode_after = '' - before = list(self.infra_info['networksettings'].get('networks', {})) - # Remove default 'podman' network in v3 for comparison - if before == ['podman']: - before = [] - after = self.params['network'] or [] - after = [i.lower() for i in after] - # Special case for options for slirp4netns rootless networking from v2 - if net_mode_before == 'slirp4netns' and 'createcommand' in self.info: - cr_com = self.info['createcommand'] - if '--network' in cr_com: - cr_net = cr_com[cr_com.index('--network') + 1].lower() - if 'slirp4netns:' in cr_net: - before = [cr_net] - if net_mode_before == 'pasta' and 'createcommand' in self.info: - cr_com = self.info['createcommand'] - if '--network' in cr_com: - cr_net = cr_com[cr_com.index('--network') + 1].lower() - if 'pasta:' in cr_net: - before = [cr_net] - # Currently supported only 'host' and 'none' network modes idempotency - if after in [['bridge'], ['host'], ['slirp4netns'], ['pasta']]: - net_mode_after = after[0] + return self._diff_generic('network', '--network') - if net_mode_after and not before: - # Remove differences between v1 and v2 - net_mode_after = net_mode_after.replace('bridge', 'default') - net_mode_after = net_mode_after.replace('slirp4netns', 'default') - net_mode_after = net_mode_after.replace('pasta', 'default') - net_mode_before = net_mode_before.replace('bridge', 'default') - net_mode_before = net_mode_before.replace('slirp4netns', 'default') - net_mode_before = net_mode_before.replace('pasta', 'default') - return self._diff_update_and_compare('network', net_mode_before, net_mode_after) - # For 4.4.0+ podman versions with no network specified - if not net_mode_after and net_mode_before == 'slirp4netns' and not after: - net_mode_after = 'slirp4netns' - if before == ['slirp4netns']: - after = ['slirp4netns'] - if not net_mode_after and net_mode_before == 'bridge' and not after: - net_mode_after = 'bridge' - if before == ['bridge']: - after = ['bridge'] - # For pasta networking for Podman v5 - if not net_mode_after and net_mode_before == 'pasta' and not after: - net_mode_after = 'pasta' - if before == ['pasta']: - after = ['pasta'] - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('network', before, after) + def diffparam_network_alias(self): + return self._diff_generic('network_alias', '--network-alias') - # TODO(sshnaidm) - # def diffparam_no_hosts(self): - # before = str(self.info['hostconfig']['no_hosts']) - # after = self.params['no_hosts'] - # return self._diff_update_and_compare('no_hosts', before, after) + def diffparam_no_hosts(self): + return self._diff_generic('no_hosts', '--no-hosts', boolean_type=True) + + def diffparam_pid(self): + return self._diff_generic('pid', '--pid') + + def diffparam_pod_id_file(self): + return self._diff_generic('pod_id_file', '--pod-id-file') - # TODO(sshnaidm) Need to add port ranges support def diffparam_publish(self): - def compose(p, h): - s = ":".join( - [str(h["hostport"]), p.replace('/tcp', '')] - ).strip(":") - if h['hostip'] == '0.0.0.0' and LooseVersion(self.version) >= LooseVersion('5.0.0'): - return s - if h['hostip']: - return ":".join([h['hostip'], s]) - return s + return self._diff_generic('publish', '--publish') - if not self.infra_info: - return self._diff_update_and_compare('publish', '', '') + def diffparam_restart_policy(self): + return self._diff_generic('restart_policy', '--restart') - ports = self.infra_info['hostconfig']['portbindings'] - before = [] - for port, hosts in ports.items(): - if hosts: - for h in hosts: - before.append(compose(port, h)) - after = self.params['publish'] or [] - after = [ - i.replace("/tcp", "").replace("[", "").replace("]", "").replace("0.0.0.0:", "") - for i in after] - # No support for port ranges yet - for ports in after: - if "-" in ports: - return self._diff_update_and_compare('publish', '', '') - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('publish', before, after) + def diffparam_security_opt(self): + return self._diff_generic('security_opt', '--security-opt') def diffparam_share(self): - if not self.infra_info: - return self._diff_update_and_compare('share', '', '') - if 'sharednamespaces' in self.info: - before = self.info['sharednamespaces'] - elif 'config' in self.info: - before = [ - i.split('shares')[1].lower() - for i in self.info['config'] if 'shares' in i] - # TODO(sshnaidm): to discover why in podman v1 'cgroup' appears - before.remove('cgroup') - else: - before = [] - if self.params['share'] is not None: - after = self.params['share'].split(",") - else: - after = ['uts', 'ipc', 'net'] - # TODO: find out why on Ubuntu the 'net' is not present - if 'net' not in before: - after.remove('net') - if self.params["uidmap"] or self.params["gidmap"] or self.params["userns"]: - after.append('user') + return self._diff_generic('share', '--share') - before, after = sorted(list(set(before))), sorted(list(set(after))) - return self._diff_update_and_compare('share', before, after) + def diffparam_share_parent(self): + return self._diff_generic('share_parent', '--share-parent') + + def diffparam_shm_size(self): + return self._diff_generic('shm_size', '--shm-size') + + def diffparam_shm_size_systemd(self): + return self._diff_generic('shm_size_systemd', '--shm-size-systemd') + + def diffparam_subgidname(self): + return self._diff_generic('subgidname', '--subgidname') + + def diffparam_subuidname(self): + return self._diff_generic('subuidname', '--subuidname') + + def diffparam_sysctl(self): + return self._diff_generic('sysctl', '--sysctl') + + def diffparam_uidmap(self): + return self._diff_generic('uidmap', '--uidmap') + + def diffparam_userns(self): + return self._diff_generic('userns', '--userns') + + def diffparam_uts(self): + return self._diff_generic('uts', '--uts') + + def diffparam_volume(self): + def clean_volume(x): + '''Remove trailing and double slashes from volumes.''' + if not x.rstrip("/"): + return "/" + return x.replace("//", "/").rstrip("/") + + before = createcommand('--volume', self.info) + if before == []: + before = None + after = self.params['volume'] + if after is not None: + after = [":".join( + [clean_volume(i) for i in v.split(":")[:2]]) for v in self.params['volume']] + if before is not None: + before = [":".join([clean_volume(i) for i in v.split(":")[:2]]) for v in before] + self.module.log("PODMAN Before: %s and After: %s" % (before, after)) + if before is None and after is None: + return self._diff_update_and_compare('volume', before, after) + if after is not None: + after = ",".join(sorted([str(i).lower() for i in after])) + if before: + before = ",".join(sorted([str(i).lower() for i in before])) + return self._diff_update_and_compare('volume', before, after) + + def diffparam_volumes_from(self): + return self._diff_generic('volumes_from', '--volumes-from') def is_different(self): diff_func_list = [func for func in dir(self) diff --git a/plugins/module_utils/podman/quadlet.py b/plugins/module_utils/podman/quadlet.py index 7b41ab4..6296c7b 100644 --- a/plugins/module_utils/podman/quadlet.py +++ b/plugins/module_utils/podman/quadlet.py @@ -474,6 +474,8 @@ class PodQuadlet(Quadlet): if params["gidmap"]: for gidmap in params["gidmap"]: params["podman_args"].append(f"--gidmap {gidmap}") + if params["exit_policy"]: + params["podman_args"].append(f"--exit-policy={params['gpus']}") if params["gpus"]: params["podman_args"].append(f"--gpus {params['gpus']}") if params["hostname"]: @@ -509,6 +511,8 @@ class PodQuadlet(Quadlet): params["podman_args"].append(f"--pid {params['pid']}") if params["pod_id_file"]: params["podman_args"].append(f"--pod-id-file {params['pod_id_file']}") + if params["restart_policy"]: + params["podman_args"].append(f"--restart={params['restart_policy']}") if params["security_opt"]: for security_opt in params["security_opt"]: params["podman_args"].append(f"--security-opt {security_opt}") diff --git a/plugins/modules/podman_pod.py b/plugins/modules/podman_pod.py index 2d06d02..5b3b5a1 100644 --- a/plugins/modules/podman_pod.py +++ b/plugins/modules/podman_pod.py @@ -117,6 +117,8 @@ options: all containers in the pod. type: list elements: str + aliases: + - dns_option required: false dns_search: description: @@ -125,6 +127,14 @@ options: type: list elements: str required: false + exit_policy: + description: + - Set the exit policy of the pod when the last container exits. Supported policies are stop and continue + choices: + - stop + - continue + type: str + required: false generate_systemd: description: - Generate systemd unit file for container. @@ -367,6 +377,10 @@ options: options as a list of lines to add. type: list elements: str + restart_policy: + description: + - Restart policy to follow when containers exit. + type: str security_opt: description: - Security options for the pod. diff --git a/tests/integration/targets/podman_pod/tasks/idempotency.yml b/tests/integration/targets/podman_pod/tasks/idempotency.yml new file mode 100644 index 0000000..1908fb2 --- /dev/null +++ b/tests/integration/targets/podman_pod/tasks/idempotency.yml @@ -0,0 +1,283 @@ +- name: Test podman pod idempotency + block: + + - name: Delete all pods leftovers from tests + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: "{{ item }}" + state: absent + loop: + - "podidem1" + - "podidem2" + + - name: Delete all container leftovers from tests + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: "{{ item }}" + state: absent + loop: + - "container1" + - "container2" + + - name: Create pod + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: created + register: podidem1_info + + - name: Check info + assert: + that: + - podidem1_info is changed + - >- + (podidem1_info.pod['State']['status'] is defined and + podidem1_info.pod['State']['status'] == 'Created') or + (podidem1_info.pod['State']['status'] is not defined and + podidem1_info.pod['State'] == 'Created') + + - name: Create pod again + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: created + register: podidem1_info2 + + - name: Check info + assert: + that: + - podidem1_info2 is not changed + + - name: Start pod + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: started + register: podidem1_info3 + + - name: Check info + assert: + that: + - podidem1_info3 is changed + - >- + (podidem1_info3.pod['State']['status'] is defined and + podidem1_info3.pod['State']['status'] == 'Running') or + (podidem1_info3.pod['State']['status'] is not defined and + podidem1_info3.pod['State'] == 'Running') + + - name: Start pod again + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: started + register: podidem1_info4 + + - name: Check info + assert: + that: + - podidem1_info4 is not changed + + - name: Stop pod + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: stopped + register: podidem1_info5 + + - name: Check info + assert: + that: + - podidem1_info5 is changed + + - name: Stop pod again + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: stopped + register: podidem1_info6 + + - name: Check info + assert: + that: + - podidem1_info6 is not changed + + - name: Create stopped pod again + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem1 + state: created + register: podidem1_info7 + + - name: Check info + assert: + that: + - podidem1_info7 is not changed + + - name: Create pod with multiple options and containers + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem2 + state: created + infra: true + network: host + share: net + userns: auto + security_opt: + - seccomp=unconfined + - apparmor=unconfined + hostname: mypod + dns: + - 1.1.1.1 + volumes: + - /tmp:/tmp/:ro + - /var/run/://var/run + label: + key: cval + otherkey: kddkdk + somekey: someval + add_host: + - "google:5.5.5.5" + register: podidem2_info + + - name: Check info + assert: + that: + - podidem2_info is changed + + - name: Create same pod + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem2 + state: created + infra: true + network: host + share: net + userns: auto + security_opt: + - seccomp=unconfined + - apparmor=unconfined + hostname: mypod + dns: + - 1.1.1.1 + volumes: + - /tmp:/tmp/:ro + - /var/run/://var/run + label: + key: cval + otherkey: kddkdk + somekey: someval + add_host: + - "google:5.5.5.5" + register: podidem2_info2 + + - name: Check info + assert: + that: + - podidem2_info2 is not changed + + - name: Change the pod + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem2 + state: created + infra: true + network: host + share: net + userns: auto + security_opt: + - seccomp=unconfined + - apparmor=unconfined + hostname: mypod + dns: + - 1.1.1.2 + volumes: + - /tmp:/tmp/:ro + - /var/run/://var/run + label: + key: cval + otherkey: kddkdk + somekey: someval + add_host: + - "google:5.5.5.5" + register: podidem2_info3 + + - name: Check info + assert: + that: + - podidem2_info3 is changed + + - name: Start the pod + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem2 + state: started + infra: true + network: host + share: net + userns: auto + security_opt: + - seccomp=unconfined + - apparmor=unconfined + hostname: mypod + dns: + - 1.1.1.2 + volumes: + - /tmp:/tmp/:ro + - /var/run/://var/run + label: + key: cval + otherkey: kddkdk + somekey: someval + add_host: + - "google:5.5.5.5" + + - name: Configure and start the pod again + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: podidem2 + state: started + infra: true + network: host + share: net + userns: auto + security_opt: + - seccomp=unconfined + - apparmor=unconfined + hostname: mypod + dns: + - 1.1.1.2 + volumes: + - /tmp:/tmp/:ro + - /var/run/://var/run + label: + key: cval + otherkey: kddkdk + somekey: someval + add_host: + - "google:5.5.5.5" + register: podidem2_info4 + + - name: Check info + assert: + that: + - podidem2_info4 is not changed + + always: + + - name: Delete all pods leftovers from tests + containers.podman.podman_pod: + executable: "{{ test_executable | default('podman') }}" + name: "{{ item }}" + state: absent + loop: + - "podidem1" + - "podidem1" + + - name: Delete all container leftovers from tests + containers.podman.podman_container: + executable: "{{ test_executable | default('podman') }}" + name: "{{ item }}" + state: absent + loop: + - "container1" + - "container2" diff --git a/tests/integration/targets/podman_pod/tasks/main.yml b/tests/integration/targets/podman_pod/tasks/main.yml index 51a0d16..c148f9a 100644 --- a/tests/integration/targets/podman_pod/tasks/main.yml +++ b/tests/integration/targets/podman_pod/tasks/main.yml @@ -1153,6 +1153,9 @@ - "container1" - "container2" +- name: Test idempotency rootless pods + include_tasks: idempotency.yml + - name: Test idempotency for root pods include_tasks: root-pod.yml vars: