1
0
Fork 0
mirror of https://github.com/containers/ansible-podman-collections.git synced 2026-02-04 07:11:49 +00:00
ansible-podman-collections/plugins/module_utils/podman/common.py
Oliver Walsh a0377fbd24
Fix signal diff for truncated and RT signal names (#326)
* Fix signal diff for truncated and RT signal names

This refactors the signal mapping logic to closely resemble the logic in
podman.

Podman tolerates images with truncated STOPSIGNAL names e.g RTMIN+3
is used in the freeipa-container Dockerfiles.

Also avoids hardcoding real-time signals as they vary per
platform or glibc implementation (see man 7 signal).

* Cleanup lint

* More lint cleanup
2021-10-19 17:18:22 +03:00

159 lines
5.2 KiB
Python

# Copyright (c) 2020 Red Hat
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
import os
import shutil
import signal
def run_podman_command(module, executable='podman', args=None, expected_rc=0, ignore_errors=False):
if not isinstance(executable, list):
command = [executable]
if args is not None:
command.extend(args)
rc, out, err = module.run_command(command)
if not ignore_errors and rc != expected_rc:
module.fail_json(
msg='Failed to run {command} {args}: {err}'.format(
command=command, args=args, err=err))
return rc, out, err
def generate_systemd(module, module_params, name):
"""Generate systemd unit file."""
command = [module_params['executable'], 'generate', 'systemd',
name, '--format', 'json']
sysconf = module_params['generate_systemd']
empty = {}
if sysconf.get('restart_policy'):
if sysconf.get('restart_policy') not in [
"no", "on-success", "on-failure", "on-abnormal", "on-watchdog",
"on-abort", "always"]:
module.fail_json(
'Restart policy for systemd unit file is "%s" and must be one of: '
'"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", or "always"' %
sysconf.get('restart_policy'))
command.extend([
'--restart-policy',
sysconf['restart_policy']])
if sysconf.get('time'):
command.extend(['--time', str(sysconf['time'])])
if sysconf.get('no_header'):
command.extend(['--no-header'])
if sysconf.get('names', True):
command.extend(['--name'])
if sysconf.get('container_prefix') is not None:
command.extend(['--container-prefix=%s' % sysconf['container_prefix']])
if sysconf.get('pod_prefix') is not None:
command.extend(['--pod-prefix=%s' % sysconf['pod_prefix']])
if sysconf.get('separator') is not None:
command.extend(['--separator=%s' % sysconf['separator']])
if module.params['debug'] or module_params['debug']:
module.log("PODMAN-CONTAINER-DEBUG: systemd command: %s" %
" ".join(command))
rc, systemd, err = module.run_command(command)
if rc != 0:
module.log(
"PODMAN-CONTAINER-DEBUG: Error generating systemd: %s" % err)
return empty
else:
try:
data = json.loads(systemd)
if sysconf.get('path'):
if not os.path.exists(sysconf['path']):
os.makedirs(sysconf['path'])
if not os.path.isdir(sysconf['path']):
module.fail_json("Path %s is not a directory! "
"Can not save systemd unit files there!"
% sysconf['path'])
for file_name, file_content in data.items():
file_name += ".service"
with open(os.path.join(sysconf['path'], file_name), 'w') as f:
f.write(file_content)
return data
except Exception as e:
module.log(
"PODMAN-CONTAINER-DEBUG: Error writing systemd: %s" % e)
return empty
def lower_keys(x):
if isinstance(x, list):
return [lower_keys(v) for v in x]
elif isinstance(x, dict):
return dict((k.lower(), lower_keys(v)) for k, v in x.items())
else:
return x
def remove_file_or_dir(path):
if os.path.isfile(path):
os.unlink(path)
elif os.path.isdir(path):
shutil.rmtree(path)
else:
raise ValueError("file %s is not a file or dir." % path)
# Generated from https://github.com/containers/podman/blob/main/pkg/signal/signal_linux.go
# and https://github.com/containers/podman/blob/main/pkg/signal/signal_linux_mipsx.go
_signal_map = {
"ABRT": 6,
"ALRM": 14,
"BUS": 7,
"CHLD": 17,
"CLD": 17,
"CONT": 18,
"EMT": 7,
"FPE": 8,
"HUP": 1,
"ILL": 4,
"INT": 2,
"IO": 29,
"IOT": 6,
"KILL": 9,
"PIPE": 13,
"POLL": 29,
"PROF": 27,
"PWR": 30,
"QUIT": 3,
"RTMAX": int(signal.SIGRTMAX),
"RTMIN": int(signal.SIGRTMIN),
"SEGV": 11,
"STKFLT": 16,
"STOP": 19,
"SYS": 31,
"TERM": 15,
"TRAP": 5,
"TSTP": 20,
"TTIN": 21,
"TTOU": 22,
"URG": 23,
"USR1": 10,
"USR2": 12,
"VTALRM": 26,
"WINCH": 28,
"XCPU": 24,
"XFSZ": 25
}
for i in range(1, _signal_map['RTMAX'] - _signal_map['RTMIN'] + 1):
_signal_map['RTMIN+{0}'.format(i)] = _signal_map['RTMIN'] + i
_signal_map['RTMAX-{0}'.format(i)] = _signal_map['RTMAX'] - i
def normalize_signal(signal_name_or_number):
signal_name_or_number = str(signal_name_or_number)
if signal_name_or_number.isdigit():
return signal_name_or_number
else:
signal_name = signal_name_or_number.upper()
if signal_name.startswith('SIG'):
signal_name = signal_name[3:]
if signal_name not in _signal_map:
raise RuntimeError("Unknown signal '{0}'".format(signal_name_or_number))
return str(_signal_map[signal_name])