mirror of
https://github.com/containers/ansible-podman-collections.git
synced 2026-04-18 23:31:27 +00:00
Redesign idempotency for Podman Pod module (#759)
Signed-off-by: Sagi Shnaidman <sshnaidm@redhat.com>
This commit is contained in:
parent
b3dc57c1cf
commit
47fc4cc119
7 changed files with 563 additions and 239 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
283
tests/integration/targets/podman_pod/tasks/idempotency.yml
Normal file
283
tests/integration/targets/podman_pod/tasks/idempotency.yml
Normal file
|
|
@ -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"
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue