1
0
Fork 0
ansible-systemd/plugins/modules/system_service.py

451 Zeilen
16 KiB
Python

#!/usr/bin/python3
import pathlib
from typing import List, Union
try:
from ansible_module.module_utils.generic import SYSTEMD_SERVICE_CONFIG, Types # type: ignore[reportMissingImports]
from ansible_module.module_utils.module import SystemdReloadMixin, SystemdUnitModule, installable # type: ignore[reportMissingImports]
except ImportError:
from ansible_collections.sebastian.base.plugins.module_utils.generic import SYSTEMD_SERVICE_CONFIG, Types
from ansible_collections.sebastian.base.plugins.module_utils.module import SystemdReloadMixin, SystemdUnitModule, installable
@installable
class Module(SystemdUnitModule, SystemdReloadMixin): # type: ignore[misc]
"""Creates System Services units"""
name = "system_service"
module_spec = dict(
argument_spec=dict(
name=Types.str(required=True, help="Name of the service"),
serviceuser=Types.str(help="Username of under which the commands run at.", default="root"),
servicegroup=Types.str(help="Group of under which the commands run at.", default="root"),
type=Types.str(
choices=("simple", "exec", "forking", "oneshot", "dbus", "notify", "notify-reload", "idle"),
default="simple",
help="Type of the systemd service.\n"
"simple and exec start long running services that run in the same process over the whole time, exec is waiting until the process was started completly.\n"
"forking does some things in the foreground, starts an background process and then exits to leave the work to the background process.\n"
"oneshot processes are started by systemd, do their work and then exit, similar to cronjobs.\n"
"dbus services will be considered started up once they aquire the specified dbus bus"
"notify and notify-reload notify systemd about the start up via sd_notify. notify-reload needs also inform systemd on reloads and when it is ready again after an reload.\n"
"idle is similar to simple, but it can delay the start up by a few seconds.",
),
pre=Types.list(elements=str, help="command or list of commands that are started before the main command"),
start=Types.list(
elements=str,
required=True,
help="command or list of commands that are started as main programm. Multiple commands are only allowed in a oneshot command",
),
stop=Types.str(help="command that is started to stop the main program."),
remain=Types.bool(help="should the service remain as started after the command exited"),
post=Types.list(str, help="Command or list of commands that are started after the main command(s) stopped without problems."),
environmentfile=Types.list(
elements=str,
help="List of file that are containing environment variables. They are evaluated before each pre/start/post command",
),
environment=Types.list(
elements=Types.dict(
help="An Environment Variable",
name=Types.str(help="name of the Environment variable", required=True),
value=Types.str(help="value of the Environment variable", required=True),
),
help="List of environment variables that are set to each command before they run",
),
workingdirectory=Types.str(
help="The Directory that is used for the processes as current working directory",
),
rwpath=Types.list(
elements=Types.path(help="An Read and writable Path"),
help="Path(s) that are readable and writable (if permission allow)",
),
ropath=Types.list(
elements=Types.path(help="An Read and writable Path"),
help="Path(s) that are read only",
),
notreadablepath=Types.list(
elements=Types.path(help="An Read and writable Path"),
help="Path(s) that are not accessible by the applications",
),
execpath=Types.list(
elements=Types.path(help="An Read and writable Path"),
help="Path(s) where executable files are",
),
noexecpath=Types.list(
elements=Types.path(help="An Read and writable Path"),
help="Path(s) which are never executable (uploaded files, user accessible paths)",
),
protecthome=Types.str(
help="if true makes user specific directories (/home, /root, /run/user) inaccessible. read-only makes them read only and tmpfs is useful to create binds in it",
choices=("true", "false", "read-only", "tmpfs"),
),
protectsystem=Types.str(
help="makes the system read only. if true /usr, /boot and /efi are read only, if full additionally /etc and if strict all except /proc, /sys and /dev",
choices=("true", "false", "full", "strict"),
),
nonewprivileges=Types.bool(
help="disables the ability to get new capabilities for processes than already granted ones",
),
statedirectory=Types.str(
help="creates an unit specific state directory in /var/lib and sets the env var STATE_DIRECTORY with the path to it. Its cleaned up after the unit is stopped"
),
runtimedirectory=Types.str(
help="creates an unit specific runtime directory in /run and sets the env var RUNTIME_DIRECTORY with the path to it. Its cleaned up after the unit is stopped"
),
restart=Types.str(
help=[
"Controls when the service is automatically restarted",
"no means never",
"on-success when it exits with an exitcode of 0 or one of the SuccessExitStatus(not implemented) values",
"on-failure is the reverse of the on-success value",
"on-abnormal is when an service has to be killed or doesn't react to notifications from systemd, if its of the notify type",
"on-abort means if it has to be killed, because it didn't react to signals",
"on-watchdog when services missed the regular ping or other important messages",
"always means what it is: restart it whenever it is stopped",
"This setting is invalid for oneshot services",
],
choices=("no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"),
),
restartsec=Types.str(
help="this is the time it is waited between the stop of an service and its restart. this can be an time in seconds or an timespan like '5m 20s'"
),
),
)
def prepare(self):
self.unitfile = (SYSTEMD_SERVICE_CONFIG / self.get("name")).with_suffix(".service")
self.__unit = None
if self.get("type", "simple") != "oneshot" and len(self.get("start")) > 1:
self.fail("only oneshot services are allowed to have multiple start commands")
def service(self) -> str:
params = []
if self.get("environment", False):
for env in self.get("environment"):
params.append(f"Environment={env['name']}={env['value']}\n")
params.extend(
self.map_param(
type="Type",
pre="ExecStartPre",
start="ExecStart",
stop="ExecStop",
post="ExecStartPost",
serviceuser="User",
servicegroup="Group",
workingdirectory="WorkingDirectory",
environmentfile="EnvironmentFile",
protecthome="ProtectHome",
protectsystem="ProtectSystem",
rwpath="ReadWritePaths",
ropath="ReadOnlyPaths",
notreadablepath="InaccessiblePaths",
execpath="ExecPaths",
noexecpath="NoExecPaths",
statedirectory="StateDirectory",
runtimedirectory="RuntimeDirectory",
nonewprivileges="NoNewPriviledges",
remain="RemainAfterExit",
restart="Restart",
restartsec="RestartSec",
)
)
return "[Service]\n" + "".join(params)
def unit(self) -> str:
if self.__unit is None:
self.__unit = self._unit(
self.header(),
self.service(),
self.install(), # type: ignore[call-arg,misc]
)
return self.__unit
DOCUMENTATION = r"""---
description:
- Creates System Services units
extends_documentation_fragment:
- ansible.builtin.files
module: system_service
options:
after:
default: []
description:
- list of units that this unit wants to be started after this unit
elements: str
required: false
type: list
before:
default: []
description:
- list of units that this unit needs to be started before this unit.
elements: str
required: false
type: list
description:
description:
- An description for programs that access systemd
required: false
type: str
documentation:
default: []
description:
- Paths where documentation can be found
elements: str
required: false
type: list
environment:
default: []
description:
- List of environment variables that are set to each command before they run
elements: dict
options:
name:
description:
- name of the Environment variable
required: true
type: str
value:
description:
- value of the Environment variable
required: true
type: str
required: false
type: list
environmentfile:
default: []
description:
- List of file that are containing environment variables. They are evaluated before
each pre/start/post command
elements: str
required: false
type: list
execpath:
default: []
description:
- Path(s) where executable files are
elements: path
required: false
type: list
name:
description:
- Name of the service
required: true
type: str
noexecpath:
default: []
description:
- Path(s) which are never executable (uploaded files, user accessible paths)
elements: path
required: false
type: list
nonewprivileges:
description:
- disables the ability to get new capabilities for processes than already granted
ones
required: false
type: bool
notreadablepath:
default: []
description:
- Path(s) that are not accessible by the applications
elements: path
required: false
type: list
partof:
default: []
description:
- list of units that this unit is part of.
- If the restart this unit does it too, but if this restarts it does not affect
the other units.
elements: str
required: false
type: list
post:
default: []
description:
- Command or list of commands that are started after the main command(s) stopped
without problems.
elements: str
required: false
type: list
pre:
default: []
description:
- command or list of commands that are started before the main command
elements: str
required: false
type: list
protecthome:
choices:
- 'true'
- 'false'
- read-only
- tmpfs
description:
- if true makes user specific directories (/home, /root, /run/user) inaccessible.
read-only makes them read only and tmpfs is useful to create binds in it
required: false
type: str
protectsystem:
choices:
- 'true'
- 'false'
- full
- strict
description:
- makes the system read only. if true /usr, /boot and /efi are read only, if full
additionally /etc and if strict all except /proc, /sys and /dev
required: false
type: str
remain:
description:
- should the service remain as started after the command exited
required: false
type: bool
required_by:
default: []
description:
- systemd units that require this mount
elements: str
required: false
type: list
requires:
default: []
description:
- list of units that this unit requires. If it fails or can't be started this
unit fails. without before/after this is started at the same time
elements: str
required: false
type: list
restart:
choices:
- 'no'
- on-success
- on-failure
- on-abnormal
- on-watchdog
- on-abort
- always
description:
- Controls when the service is automatically restarted
- no means never
- on-success when it exits with an exitcode of 0 or one of the SuccessExitStatus(not
implemented) values
- on-failure is the reverse of the on-success value
- on-abnormal is when an service has to be killed or doesn't react to notifications
from systemd, if its of the notify type
- on-abort means if it has to be killed, because it didn't react to signals
- on-watchdog when services missed the regular ping or other important messages
- 'always means what it is: restart it whenever it is stopped'
- This setting is invalid for oneshot services
required: false
type: str
restartsec:
description:
- this is the time it is waited between the stop of an service and its restart.
this can be an time in seconds or an timespan like '5m 20s'
required: false
type: str
ropath:
default: []
description:
- Path(s) that are read only
elements: path
required: false
type: list
runtimedirectory:
description:
- creates an unit specific runtime directory in /run and sets the env var RUNTIME_DIRECTORY
with the path to it. Its cleaned up after the unit is stopped
required: false
type: str
rwpath:
default: []
description:
- Path(s) that are readable and writable (if permission allow)
elements: path
required: false
type: list
servicegroup:
default: root
description:
- Group of under which the commands run at.
required: false
type: str
serviceuser:
default: root
description:
- Username of under which the commands run at.
required: false
type: str
start:
description:
- command or list of commands that are started as main programm. Multiple commands
are only allowed in a oneshot command
elements: str
required: true
type: list
statedirectory:
description:
- creates an unit specific state directory in /var/lib and sets the env var STATE_DIRECTORY
with the path to it. Its cleaned up after the unit is stopped
required: false
type: str
stop:
description:
- command that is started to stop the main program.
required: false
type: str
type:
choices:
- simple
- exec
- forking
- oneshot
- dbus
- notify
- notify-reload
- idle
default: simple
description:
- Type of the systemd service.
- simple and exec start long running services that run in the same process over
the whole time, exec is waiting until the process was started completly.
- forking does some things in the foreground, starts an background process and
then exits to leave the work to the background process.
- oneshot processes are started by systemd, do their work and then exit, similar
to cronjobs.
- dbus services will be considered started up once they aquire the specified dbus
busnotify and notify-reload notify systemd about the start up via sd_notify.
notify-reload needs also inform systemd on reloads and when it is ready again
after an reload.
- idle is similar to simple, but it can delay the start up by a few seconds.
required: false
type: str
wanted_by:
default: []
description:
- systemd units that want the mount, but not explicitly require it. Commonly used
for target if not service explicitly require it.
elements: str
required: false
type: list
wants:
default: []
description:
- list of units that this unit wants. If it fails or can't be started it does
not affect this unit
elements: str
required: false
type: list
workingdirectory:
description:
- The Directory that is used for the processes as current working directory
required: false
type: str
short_description: Creates System Services units
"""
if __name__ == "__main__":
Module()()