summaryrefslogtreecommitdiffstats
path: root/ansible_collections/containers/podman/plugins/module_utils
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-18 05:52:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-18 05:52:22 +0000
commit38b7c80217c4e72b1d8988eb1e60bb6e77334114 (patch)
tree356e9fd3762877d07cde52d21e77070aeff7e789 /ansible_collections/containers/podman/plugins/module_utils
parentAdding upstream version 7.7.0+dfsg. (diff)
downloadansible-38b7c80217c4e72b1d8988eb1e60bb6e77334114.tar.xz
ansible-38b7c80217c4e72b1d8988eb1e60bb6e77334114.zip
Adding upstream version 9.4.0+dfsg.upstream/9.4.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/containers/podman/plugins/module_utils')
-rw-r--r--ansible_collections/containers/podman/plugins/module_utils/podman/common.py119
-rw-r--r--ansible_collections/containers/podman/plugins/module_utils/podman/podman_container_lib.py204
-rw-r--r--ansible_collections/containers/podman/plugins/module_utils/podman/podman_pod_lib.py66
3 files changed, 331 insertions, 58 deletions
diff --git a/ansible_collections/containers/podman/plugins/module_utils/podman/common.py b/ansible_collections/containers/podman/plugins/module_utils/podman/common.py
index dba3aff65..cbb6b080e 100644
--- a/ansible_collections/containers/podman/plugins/module_utils/podman/common.py
+++ b/ansible_collections/containers/podman/plugins/module_utils/podman/common.py
@@ -19,6 +19,25 @@ except ImportError:
' < 2.11, you need to use Python < 3.12 with '
'distutils.version present'), exc)
+ARGUMENTS_OPTS_DICT = {
+ '--attach': ['--attach', '-a'],
+ '--cpu-shares': ['--cpu-shares', '-c'],
+ '--detach': ['--detach', '-d'],
+ '--env': ['--env', '-e'],
+ '--hostname': ['--hostname', '-h'],
+ '--interactive': ['--interactive', '-i'],
+ '--label': ['--label', '-l'],
+ '--memory': ['--memory', '-m'],
+ '--network': ['--network', '--net'],
+ '--publish': ['--publish', '-p'],
+ '--publish-all': ['--publish-all', '-P'],
+ '--quiet': ['--quiet', '-q'],
+ '--tty': ['--tty', '-t'],
+ '--user': ['--user', '-u'],
+ '--volume': ['--volume', '-v'],
+ '--workdir': ['--workdir', '-w'],
+}
+
def run_podman_command(module, executable='podman', args=None, expected_rc=0, ignore_errors=False):
if not isinstance(executable, list):
@@ -50,8 +69,15 @@ def run_generate_systemd_command(module, module_params, name, version):
command.extend([
'--restart-policy',
sysconf['restart_policy']])
- if sysconf.get('time'):
- command.extend(['--time', str(sysconf['time'])])
+ if sysconf.get('restart_sec') is not None:
+ command.extend(['--restart-sec=%s' % sysconf['restart_sec']])
+ if (sysconf.get('stop_timeout') is not None) or (sysconf.get('time') is not None):
+ # Select correct parameter name based on version
+ arg_name = 'stop-timeout' if gt4ver else 'time'
+ arg_value = sysconf.get('stop_timeout') if sysconf.get('stop_timeout') is not None else sysconf.get('time')
+ command.extend(['--%s=%s' % (arg_name, arg_value)])
+ if sysconf.get('start_timeout') is not None:
+ command.extend(['--start-timeout=%s' % sysconf['start_timeout']])
if sysconf.get('no_header'):
command.extend(['--no-header'])
if sysconf.get('names', True):
@@ -96,34 +122,103 @@ def run_generate_systemd_command(module, module_params, name, version):
return rc, systemd, err
+def compare_systemd_file_content(file_path, file_content):
+ if not os.path.exists(file_path):
+ # File does not exist, so all lines in file_content are different
+ return '', file_content
+ # Read the file
+ with open(file_path, 'r') as unit_file:
+ current_unit_file_content = unit_file.read()
+
+ # Function to remove comments from file content
+ def remove_comments(content):
+ return "\n".join([line for line in content.splitlines() if not line.startswith('#')])
+
+ # Remove comments from both file contents before comparison
+ current_unit_file_content_nocmnt = remove_comments(current_unit_file_content)
+ unit_content_nocmnt = remove_comments(file_content)
+ if current_unit_file_content_nocmnt == unit_content_nocmnt:
+ return None
+
+ # Get the different lines between the two contents
+ diff_in_file = [line
+ for line in unit_content_nocmnt.splitlines()
+ if line not in current_unit_file_content_nocmnt.splitlines()]
+ diff_in_string = [line
+ for line in current_unit_file_content_nocmnt.splitlines()
+ if line not in unit_content_nocmnt.splitlines()]
+
+ return diff_in_string, diff_in_file
+
+
def generate_systemd(module, module_params, name, version):
- empty = {}
+ result = {
+ 'changed': False,
+ 'systemd': {},
+ 'diff': {},
+ }
sysconf = module_params['generate_systemd']
rc, systemd, err = run_generate_systemd_command(module, module_params, name, version)
if rc != 0:
module.log(
"PODMAN-CONTAINER-DEBUG: Error generating systemd: %s" % err)
- return empty
+ if sysconf:
+ module.fail_json(msg="Error generating systemd: %s" % err)
+ return result
else:
try:
data = json.loads(systemd)
+ result['systemd'] = data
if sysconf.get('path'):
full_path = os.path.expanduser(sysconf['path'])
if not os.path.exists(full_path):
os.makedirs(full_path)
+ result['changed'] = True
if not os.path.isdir(full_path):
module.fail_json("Path %s is not a directory! "
"Can not save systemd unit files there!"
% full_path)
for file_name, file_content in data.items():
file_name += ".service"
+ if not os.path.exists(os.path.join(full_path, file_name)):
+ result['changed'] = True
+ if result['diff'].get('before') is None:
+ result['diff'] = {'before': {}, 'after': {}}
+ result['diff']['before'].update(
+ {'systemd_{file_name}.service'.format(file_name=file_name): ''})
+ result['diff']['after'].update(
+ {'systemd_{file_name}.service'.format(file_name=file_name): file_content})
+
+ else:
+ diff_ = compare_systemd_file_content(os.path.join(full_path, file_name), file_content)
+ if diff_:
+ result['changed'] = True
+ if result['diff'].get('before') is None:
+ result['diff'] = {'before': {}, 'after': {}}
+ result['diff']['before'].update(
+ {'systemd_{file_name}.service'.format(file_name=file_name): "\n".join(diff_[0])})
+ result['diff']['after'].update(
+ {'systemd_{file_name}.service'.format(file_name=file_name): "\n".join(diff_[1])})
with open(os.path.join(full_path, file_name), 'w') as f:
f.write(file_content)
- return data
+ diff_before = "\n".join(
+ ["{j} - {k}".format(j=j, k=k)
+ for j, k in result['diff'].get('before', {}).items() if 'PIDFile' not in k]).strip()
+ diff_after = "\n".join(
+ ["{j} - {k}".format(j=j, k=k)
+ for j, k in result['diff'].get('after', {}).items() if 'PIDFile' not in k]).strip()
+ if diff_before or diff_after:
+ result['diff']['before'] = diff_before + "\n"
+ result['diff']['after'] = diff_after + "\n"
+ else:
+ result['diff'] = {}
+ return result
except Exception as e:
module.log(
"PODMAN-CONTAINER-DEBUG: Error writing systemd: %s" % e)
- return empty
+ if sysconf:
+ module.fail_json(msg="Error writing systemd: %s" % e)
+ return result
def delete_systemd(module, module_params, name, version):
@@ -230,3 +325,15 @@ def normalize_signal(signal_name_or_number):
if signal_name not in _signal_map:
raise RuntimeError("Unknown signal '{0}'".format(signal_name_or_number))
return str(_signal_map[signal_name])
+
+
+def get_podman_version(module, fail=True):
+ executable = module.params['executable'] if module.params['executable'] else 'podman'
+ rc, out, err = module.run_command(
+ [executable, b'--version'])
+ if rc != 0 or not out or "version" not in out:
+ if fail:
+ module.fail_json(msg="'%s --version' run failed! Error: %s" %
+ (executable, err))
+ return None
+ return out.split("version")[1].strip()
diff --git a/ansible_collections/containers/podman/plugins/module_utils/podman/podman_container_lib.py b/ansible_collections/containers/podman/plugins/module_utils/podman/podman_container_lib.py
index 1ba28f4c8..ff4c18629 100644
--- a/ansible_collections/containers/podman/plugins/module_utils/podman/podman_container_lib.py
+++ b/ansible_collections/containers/podman/plugins/module_utils/podman/podman_container_lib.py
@@ -9,6 +9,7 @@ from ansible_collections.containers.podman.plugins.module_utils.podman.common im
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 normalize_signal
+from ansible_collections.containers.podman.plugins.module_utils.podman.common import ARGUMENTS_OPTS_DICT
__metaclass__ = type
@@ -19,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'),
@@ -32,12 +34,16 @@ ARGUMENTS_SPEC_CONTAINER = dict(
conmon_pidfile=dict(type='path'),
command=dict(type='raw'),
cpu_period=dict(type='int'),
+ cpu_quota=dict(type='int'),
cpu_rt_period=dict(type='int'),
cpu_rt_runtime=dict(type='int'),
cpu_shares=dict(type='int'),
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),
@@ -51,13 +57,14 @@ ARGUMENTS_SPEC_CONTAINER = dict(
dns_search=dict(type='str', aliases=['dns_search_domains']),
entrypoint=dict(type='str'),
env=dict(type='dict'),
- env_file=dict(type='path'),
+ env_file=dict(type='list', elements='path', aliases=['env_files']),
env_host=dict(type='bool'),
etc_hosts=dict(type='dict', aliases=['add_hosts']),
expose=dict(type='list', elements='str', aliases=[
'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']),
@@ -66,6 +73,8 @@ ARGUMENTS_SPEC_CONTAINER = dict(
healthcheck_retries=dict(type='int'),
healthcheck_start_period=dict(type='str'),
healthcheck_timeout=dict(type='str'),
+ healthcheck_failure_action=dict(type='str', choices=[
+ 'none', 'kill', 'restart', 'stop']),
hooks_dir=dict(type='list', elements='str'),
hostname=dict(type='str'),
http_proxy=dict(type='bool'),
@@ -112,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),
@@ -121,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'),
@@ -227,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):
@@ -252,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']]
@@ -293,6 +332,9 @@ class PodmanModuleParams:
def addparam_cpu_period(self, c):
return c + ['--cpu-period', self.params['cpu_period']]
+ def addparam_cpu_quota(self, c):
+ return c + ['--cpu-quota', self.params['cpu_quota']]
+
def addparam_cpu_rt_period(self, c):
return c + ['--cpu-rt-period', self.params['cpu_rt_period']]
@@ -312,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):
@@ -362,7 +407,9 @@ class PodmanModuleParams:
return c
def addparam_env_file(self, c):
- return c + ['--env-file', self.params['env_file']]
+ for env_file in self.params['env_file']:
+ c += ['--env-file', env_file]
+ return c
def addparam_env_host(self, c):
self.check_version('--env-host', minv='1.5.0')
@@ -407,6 +454,10 @@ class PodmanModuleParams:
return c + ['--healthcheck-timeout',
self.params['healthcheck_timeout']]
+ def addparam_healthcheck_failure_action(self, c):
+ return c + ['--health-on-failure',
+ self.params['healthcheck_failure_action']]
+
def addparam_hooks_dir(self, c):
for hook_dir in self.params['hooks_dir']:
c += ['--hooks-dir=%s' % hook_dir]
@@ -722,6 +773,35 @@ class PodmanContainerDiff:
params_with_defaults[p] = self.module_params[p]
return params_with_defaults
+ def _createcommand(self, argument):
+ """Returns list of values for given argument from CreateCommand
+ from Podman container inspect output.
+
+ Args:
+ argument (str): argument name
+
+ 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:
+ # This is a key=value argument
+ if not cr_com[ind + 1].startswith("-"):
+ all_values.append(cr_com[ind + 1])
+ else:
+ # This is 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})
@@ -737,7 +817,7 @@ class PodmanContainerDiff:
return self._diff_update_and_compare('annotation', before, after)
def diffparam_env_host(self):
- # It's impossible to get from inspest, recreate it if not default
+ # It's impossible to get from inspect, recreate it if not default
before = False
after = self.params['env_host']
return self._diff_update_and_compare('env_host', before, after)
@@ -826,9 +906,16 @@ class PodmanContainerDiff:
def diffparam_cpu_period(self):
before = self.info['hostconfig']['cpuperiod']
- after = self.params['cpu_period']
+ # if cpu_period left to default keep settings
+ after = self.params['cpu_period'] or before
return self._diff_update_and_compare('cpu_period', before, after)
+ def diffparam_cpu_quota(self):
+ before = self.info['hostconfig']['cpuquota']
+ # if cpu_quota left to default keep settings
+ after = self.params['cpu_quota'] or before
+ return self._diff_update_and_compare('cpu_quota', before, after)
+
def diffparam_cpu_rt_period(self):
before = self.info['hostconfig']['cpurealtimeperiod']
after = self.params['cpu_rt_period']
@@ -845,8 +932,9 @@ class PodmanContainerDiff:
return self._diff_update_and_compare('cpu_shares', before, after)
def diffparam_cpus(self):
- before = int(self.info['hostconfig']['nanocpus']) / 1000000000
- after = self.params['cpus']
+ before = self.info['hostconfig']['nanocpus'] / 1000000000
+ # if cpus left to default keep settings
+ after = float(self.params['cpus'] or before)
return self._diff_update_and_compare('cpus', before, after)
def diffparam_cpuset_cpus(self):
@@ -863,16 +951,13 @@ class PodmanContainerDiff:
before = [":".join([i['pathonhost'], i['pathincontainer']])
for i in self.info['hostconfig']['devices']]
if not before and 'createcommand' in self.info['config']:
- cr_com = self.info['config']['createcommand']
- if '--device' in cr_com:
- before = [cr_com[k + 1].lower()
- for k, i in enumerate(cr_com) if i == '--device']
+ before = [i.lower() for i in self._createcommand('--device')]
before = [":".join((i, i))
if len(i.split(":")) == 1 else i for i in before]
after = [":".join(i.split(":")[:2]) for i in self.params['device']]
after = [":".join((i, i))
if len(i.split(":")) == 1 else i for i in after]
- after = [i.lower() for i in after]
+ before, after = [i.lower() for i in before], [i.lower() for i in after]
before, after = sorted(list(set(before))), sorted(list(set(after)))
return self._diff_update_and_compare('devices', before, after)
@@ -931,15 +1016,23 @@ class PodmanContainerDiff:
# Healthcheck is only defined in container config if a healthcheck
# was configured; otherwise the config key isn't part of the config.
def diffparam_healthcheck(self):
+ before = ''
if 'healthcheck' in self.info['config']:
# the "test" key is a list of 2 items where the first one is
# "CMD-SHELL" and the second one is the actual healthcheck command.
- before = self.info['config']['healthcheck']['test'][1]
- else:
- before = ''
+ if len(self.info['config']['healthcheck']['test']) > 1:
+ before = self.info['config']['healthcheck']['test'][1]
after = self.params['healthcheck'] or before
return self._diff_update_and_compare('healthcheck', before, after)
+ def diffparam_healthcheck_failure_action(self):
+ if 'healthcheckonfailureaction' in self.info['config']:
+ before = self.info['config']['healthcheckonfailureaction']
+ else:
+ before = ''
+ after = self.params['healthcheck_failure_action'] or before
+ return self._diff_update_and_compare('healthcheckonfailureaction', before, after)
+
# Because of hostname is random generated, this parameter has partial idempotency only.
def diffparam_hostname(self):
before = self.info['config']['hostname']
@@ -1066,9 +1159,8 @@ class PodmanContainerDiff:
if macs:
before = macs[0]
if not before and 'createcommand' in self.info['config']:
- cr_com = self.info['config']['createcommand']
- if '--mac-address' in cr_com:
- before = cr_com[cr_com.index('--mac-address') + 1].lower()
+ before = [i.lower() for i in self._createcommand('--mac-address')]
+ before = before[0] if before else ''
if self.module_params['mac_address'] is not None:
after = self.params['mac_address']
else:
@@ -1084,11 +1176,10 @@ class PodmanContainerDiff:
before = []
# Special case for options for slirp4netns rootless networking from v2
if net_mode_before == 'slirp4netns' and 'createcommand' in self.info['config']:
- cr_com = self.info['config']['createcommand']
- if '--network' in cr_com:
- cr_net = cr_com[cr_com.index('--network') + 1].lower()
- if 'slirp4netns:' in cr_net:
- before = [cr_net]
+ cr_net = [i.lower() for i in self._createcommand('--network')]
+ for cr_net_opt in cr_net:
+ if 'slirp4netns:' in cr_net_opt:
+ before = [cr_net_opt]
after = self.params['network'] or []
# If container is in pod and no networks are provided
if not self.module_params['network'] and self.params['pod']:
@@ -1124,8 +1215,19 @@ class PodmanContainerDiff:
return self._diff_update_and_compare('privileged', before, after)
def diffparam_pid(self):
+ def get_container_id_by_name(name):
+ rc, podman_inspect_info, err = self.module.run_command(
+ [self.module.params["executable"], "inspect", name, "-f", "{{.Id}}"])
+ if rc != 0:
+ return None
+ return podman_inspect_info.strip()
+
before = self.info['hostconfig']['pidmode']
after = self.params['pid']
+ if after is not None and "container:" in after and "container:" in before:
+ if after.split(":")[1] == before.split(":")[1]:
+ return self._diff_update_and_compare('pid', before, after)
+ after = "container:" + get_container_id_by_name(after.split(":")[1])
return self._diff_update_and_compare('pid', before, after)
# TODO(sshnaidm) Need to add port ranges support
@@ -1150,7 +1252,7 @@ class PodmanContainerDiff:
if image_ports:
after += list(image_ports.keys())
after = [
- i.replace("/tcp", "").replace("[", "").replace("]", "")
+ i.replace("/tcp", "").replace("[", "").replace("]", "").replace("0.0.0.0:", "")
for i in after]
# No support for port ranges yet
for ports in after:
@@ -1166,7 +1268,15 @@ class PodmanContainerDiff:
def diffparam_restart_policy(self):
before = self.info['hostconfig']['restartpolicy']['name']
+ before_max_count = int(self.info['hostconfig']['restartpolicy'].get('maximumretrycount', 0))
after = self.params['restart_policy'] or ""
+ if ':' in after:
+ after, after_max_count = after.rsplit(':', 1)
+ after_max_count = int(after_max_count)
+ else:
+ after_max_count = 0
+ before = "%s:%i" % (before, before_max_count)
+ after = "%s:%i" % (after, after_max_count)
return self._diff_update_and_compare('restart_policy', before, after)
def diffparam_rm(self):
@@ -1175,11 +1285,16 @@ class PodmanContainerDiff:
return self._diff_update_and_compare('rm', before, after)
def diffparam_security_opt(self):
- before = self.info['hostconfig']['securityopt']
- # In rootful containers with apparmor there is a default security opt
- before = [o for o in before if 'apparmor=containers-default' not in o]
- after = self.params['security_opt']
- before, after = sorted(list(set(before))), sorted(list(set(after)))
+ unsorted_before = self.info['hostconfig']['securityopt']
+ unsorted_after = self.params['security_opt']
+ # In rootful containers with apparmor there is a profile, "container-default",
+ # which is already added by default
+ # Since SElinux labels are basically annotations, they are merged in a single list
+ # element by podman so we need to split them in a (sorted) list if we want to compare it
+ # to the list we provide to the module
+ before = sorted(item for element in unsorted_before for item in element.split(',')
+ if 'apparmor=container-default' not in item)
+ after = sorted(list(set(unsorted_after)))
return self._diff_update_and_compare('security_opt', before, after)
def diffparam_stop_signal(self):
@@ -1206,11 +1321,7 @@ class PodmanContainerDiff:
after = self.params['ulimit'] or []
# In case of latest podman
if 'createcommand' in self.info['config']:
- ulimits = []
- for k, c in enumerate(self.info['config']['createcommand']):
- if c == '--ulimit':
- ulimits.append(self.info['config']['createcommand'][k + 1])
- before = ulimits
+ before = self._createcommand('--ulimit')
before, after = sorted(before), sorted(after)
return self._diff_update_and_compare('ulimit', before, after)
if after:
@@ -1428,8 +1539,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)
@@ -1449,7 +1558,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):
@@ -1547,11 +1656,19 @@ class PodmanManager:
self.results.update({'diff': self.container.diff})
if self.module.params['debug'] or self.module_params['debug']:
self.results.update({'podman_version': self.container.version})
+ sysd = generate_systemd(self.module,
+ self.module_params,
+ self.name,
+ self.container.version)
+ self.results['changed'] = changed or sysd['changed']
self.results.update(
- {'podman_systemd': generate_systemd(self.module,
- self.module_params,
- self.name,
- self.container.version)})
+ {'podman_systemd': sysd['systemd']})
+ if sysd['diff']:
+ if 'diff' not in self.results:
+ self.results.update({'diff': sysd['diff']})
+ else:
+ self.results['diff']['before'] += sysd['diff']['before']
+ self.results['diff']['after'] += sysd['diff']['after']
def make_started(self):
"""Run actions if desired state is 'started'."""
@@ -1601,7 +1718,8 @@ class PodmanManager:
self.results['actions'].append('started %s' % self.container.name)
self.update_container_result()
return
- elif self.container.stopped and self.container.different:
+ elif self.container.stopped and \
+ (self.container.different or self.recreate):
self.container.recreate_run()
self.results['actions'].append('recreated %s' %
self.container.name)
diff --git a/ansible_collections/containers/podman/plugins/module_utils/podman/podman_pod_lib.py b/ansible_collections/containers/podman/plugins/module_utils/podman/podman_pod_lib.py
index 0b4afc0bc..4106136e2 100644
--- a/ansible_collections/containers/podman/plugins/module_utils/podman/podman_pod_lib.py
+++ b/ansible_collections/containers/podman/plugins/module_utils/podman/podman_pod_lib.py
@@ -27,10 +27,15 @@ 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),
cpus=dict(type='str', required=False),
cpuset_cpus=dict(type='str', required=False),
+ cpuset_mems=dict(type='str', required=False),
+ cpu_shares=dict(type='str', required=False),
device=dict(type='list', elements='str', required=False),
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_search=dict(type='list', elements='str', required=False),
@@ -46,6 +51,8 @@ ARGUMENTS_SPEC_POD = dict(
label=dict(type='dict', required=False),
label_file=dict(type='str', required=False),
mac_address=dict(type='str', required=False),
+ memory=dict(type='str', required=False),
+ memory_swap=dict(type='str', required=False),
name=dict(type='str', required=True),
network=dict(type='list', elements='str', required=False),
network_alias=dict(type='list', elements='str', required=False,
@@ -135,25 +142,52 @@ class PodmanPodModuleParams:
c += ['--add-host', g]
return c
+ def addparam_blkio_weight(self, c):
+ self.check_version('--blkio-weight', minv='4.3.0')
+ return c + ['--blkio-weight', self.params['blkio_weight']]
+
+ def addparam_blkio_weight_device(self, c):
+ self.check_version('--blkio-weight-device', minv='4.3.0')
+ for dev in self.params['blkio_weight_device']:
+ c += ['--blkio-weight-device', dev]
+ return c
+
def addparam_cgroup_parent(self, c):
return c + ['--cgroup-parent', self.params['cgroup_parent']]
def addparam_cpus(self, c):
+ self.check_version('--cpus', minv='4.2.0')
return c + ['--cpus', self.params['cpus']]
def addparam_cpuset_cpus(self, c):
+ self.check_version('--cpus', minv='4.2.0')
return c + ['--cpuset-cpus', self.params['cpuset_cpus']]
+ def addparam_cpuset_mems(self, c):
+ self.check_version('--cpuset-mems', minv='4.3.0')
+ return c + ['--cpuset-mems', self.params['cpuset_mems']]
+
+ def addparam_cpu_shares(self, c):
+ self.check_version('--cpu-shares', minv='4.3.0')
+ return c + ['--cpu-shares', self.params['cpu_shares']]
+
def addparam_device(self, c):
for dev in self.params['device']:
c += ['--device', dev]
return c
def addparam_device_read_bps(self, c):
+ self.check_version('--device-read-bps', minv='4.3.0')
for dev in self.params['device_read_bps']:
c += ['--device-read-bps', dev]
return c
+ def addparam_device_write_bps(self, c):
+ self.check_version('--device-write-bps', minv='4.3.0')
+ for dev in self.params['device_write_bps']:
+ c += ['--device-write-bps', dev]
+ return c
+
def addparam_dns(self, c):
for g in self.params['dns']:
c += ['--dns', g]
@@ -209,6 +243,14 @@ class PodmanPodModuleParams:
def addparam_mac_address(self, c):
return c + ['--mac-address', self.params['mac_address']]
+ def addparam_memory(self, c):
+ self.check_version('--memory', minv='4.2.0')
+ return c + ['--memory', self.params['memory']]
+
+ def addparam_memory_swap(self, c):
+ self.check_version('--memory-swap', minv='4.3.0')
+ return c + ['--memory-swap', self.params['memory_swap']]
+
def addparam_name(self, c):
return c + ['--name', self.params['name']]
@@ -323,10 +365,8 @@ class PodmanPodDiff:
return self._diff_update_and_compare('add_host', before, after)
def diffparam_cgroup_parent(self):
- if 'cgroupparent' in self.info:
- before = self.info['cgroupparent']
- elif 'config' in self.info and self.info['config'].get('cgroupparent'):
- before = self.info['config']['cgroupparent']
+ 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)
@@ -511,7 +551,7 @@ class PodmanPodDiff:
# 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"]:
+ if self.params["uidmap"] or self.params["gidmap"] or self.params["userns"]:
after.append('user')
before, after = sorted(list(set(before))), sorted(list(set(after)))
@@ -759,11 +799,19 @@ class PodmanPodManager:
self.results.update({'diff': self.pod.diff})
if self.module.params['debug'] or self.module_params['debug']:
self.results.update({'podman_version': self.pod.version})
+ sysd = generate_systemd(self.module,
+ self.module_params,
+ self.name,
+ self.pod.version)
+ self.results['changed'] = changed or sysd['changed']
self.results.update(
- {'podman_systemd': generate_systemd(self.module,
- self.module_params,
- self.name,
- self.pod.version)})
+ {'podman_systemd': sysd['systemd']})
+ if sysd['diff']:
+ if 'diff' not in self.results:
+ self.results.update({'diff': sysd['diff']})
+ else:
+ self.results['diff']['before'] += sysd['diff']['before']
+ self.results['diff']['after'] += sysd['diff']['after']
def execute(self):
"""Execute the desired action according to map of actions & states."""