[services-systemd] Ungroup systemd units

This commit is contained in:
Adriaan de Groot 2022-07-10 12:52:40 +02:00 committed by GitHub
commit 0e6d70c395
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 135 deletions

View File

@ -7,10 +7,10 @@
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org> # SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org> # SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
# SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org> # SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org>
# SPDX-FileCopyrightText: 2022 shivanandvp <shivanandvp@rebornos.org>
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# Calamares is Free Software: see the License-Identifier above. # Calamares is Free Software: see the License-Identifier above.
#
import libcalamares import libcalamares
@ -23,96 +23,64 @@ _ = gettext.translation("calamares-python",
def pretty_name(): def pretty_name():
return _("Configure systemd services") return _("Configure systemd units")
def systemctl(targets, command, suffix): def systemctl(units):
""" """
For each entry in @p targets, run "systemctl <command> <thing>", For each entry in @p units, run "systemctl <action> <name>",
where <thing> is the entry's name plus the given @p suffix. where each unit is a mapping of unit name, action, and a flag.
(No dot is added between name and suffix; suffix may be empty)
Returns a failure message, or None if this was successful. Returns a failure message, or None if this was successful.
Services that are not mandatory have their failures suppressed Units that are not mandatory have their failures suppressed
silently. silently.
""" """
for svc in targets:
if isinstance(svc, str): for unit in units:
name = svc if isinstance(unit, str):
name = unit
action = "enable"
mandatory = False mandatory = False
else: else:
name = svc["name"] if not unit.has_key("name"):
mandatory = svc.get("mandatory", False) libcalamares.utils.error("The key 'name' is missing from the mapping {_unit!s}. Continuing to the next unit.".format(_unit=str(unit)))
continue
name = unit["name"]
action = unit.get("action", "enable")
mandatory = unit.get("mandatory", False)
ec = libcalamares.utils.target_env_call( exit_code = libcalamares.utils.target_env_call(
['systemctl', command, "{}{}".format(name, suffix)] ['systemctl', action, name]
) )
if ec != 0: if exit_code != 0:
libcalamares.utils.warning( libcalamares.utils.warning(
"Cannot {} systemd {} {}".format(command, suffix, name) "Cannot {} systemd unit {}".format(action, name)
) )
libcalamares.utils.warning( libcalamares.utils.warning(
"systemctl {} call in chroot returned error code {}".format(command, ec) "systemctl {} call in chroot returned error code {}".format(action, exit_code)
) )
if mandatory: if mandatory:
title = _("Cannot modify service") title = _("Cannot modify unit")
diagnostic = _("<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}.").format(arg=command, num=ec) diagnostic = _("<code>systemctl {_action!s}</code> call in chroot returned error code {_exit_code!s}.").format(_action=action, _exit_code=exit_code)
description = _("Cannot {_action!s} systemd unit <code>{_name!s}</code>.").format(_action=action, _name=name)
if command == "enable" and suffix == ".service": return (
description = _("Cannot enable systemd service <code>{name!s}</code>.") title,
elif command == "enable" and suffix == ".target": description + " " + diagnostic
description = _("Cannot enable systemd target <code>{name!s}</code>.")
elif command == "enable" and suffix == ".timer":
description = _("Cannot enable systemd timer <code>{name!s}</code>.")
elif command == "disable" and suffix == ".service":
description = _("Cannot enable systemd service <code>{name!s}</code>.")
elif command == "disable" and suffix == ".target":
description = _("Cannot disable systemd target <code>{name!s}</code>.")
elif command == "mask":
description = _("Cannot mask systemd unit <code>{name!s}</code>.")
else:
description = _("Unknown systemd commands <code>{command!s}</code> and <code>{suffix!s}</code> for unit {name!s}.")
return (title,
description.format(name=name, command=command, suffix=suffix) + " " + diagnostic
) )
return None return None
def run(): def run():
""" """
Setup systemd services Setup systemd units
""" """
cfg = libcalamares.job.configuration cfg = libcalamares.job.configuration
# note that the "systemctl enable" and "systemctl disable" commands used return_value = systemctl(
# here will work in a chroot; in fact, they are the only systemctl commands cfg.get("units", [])
# that support that, see: )
# http://0pointer.de/blog/projects/changing-roots.html if return_value is not None:
return return_value
r = systemctl(cfg.get("services", []), "enable", ".service")
if r is not None:
return r
r = systemctl(cfg.get("targets", []), "enable", ".target")
if r is not None:
return r
r = systemctl(cfg.get("timers", []), "enable", ".timer")
if r is not None:
return r
r = systemctl(cfg.get("disable", []), "disable", ".service")
if r is not None:
return r
r = systemctl(cfg.get("disable-targets", []), "disable", ".target")
if r is not None:
return r
r = systemctl(cfg.get("mask", []), "mask", "")
if r is not None:
return r
return None return None

View File

@ -1,79 +1,53 @@
# SPDX-FileCopyrightText: no # SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
# #
# Systemd services manipulation. # Systemd units manipulation.
# #
# This module can enable services, timers and targets for systemd # This module can perform actions using systemd units,
# (if packaging doesn't already do that). It can also # (for example, enabling, disabling, or masking services, sockets, paths, etc.)
# disable services and targets as well as mask units.
#
# The order of operations is fixed. Enable services, enable targets,
# enable timers, disable services, disable targets and finally apply masks.
--- ---
# There are several configuration keys for this module: # There is one key for this module: *units*. Its value is a list of entries.
# *services*, *targets*, *timers*, *disable*, *disable-targets* and *mask*. # Each entry has three keys:
# The value of each key is a list of entries. Each entry has two keys: # - *name* is the (string) name of the systemd unit that is being changed.
# - *name* is the (string) name of the service or target that is being # Use quotes. You can use any valid systemd unit here (for example,
# changed. Use quotes. Don't include unit suffix in the name. For # "NetworkManager.service", "cups.socket", "lightdm", "gdm", etc.)
# example, it should be "NetworkManager", not "NetworkManager.service" # - *action* is the (string) action that you want to perform over the unit
# (for example, "enable", "disable", "mask", "unmask", etc.). Please
# ensure that the action can actually run under chroot (otherwise it is
# pointless)
# - *mandatory* is a boolean option, which states whether the change # - *mandatory* is a boolean option, which states whether the change
# must be done successfully. If systemd reports an error while changing # must be done successfully. If systemd reports an error while changing
# a mandatory entry, the installation will fail. When mandatory is false, # a mandatory entry, the installation will fail. When mandatory is false,
# errors for that systemd unit are ignored. If mandatory # errors for that systemd unit are ignored. If mandatory
# is not specified, the default is false. # is not specified, the default is false.
# #
# An entry may also be given as a single string, which is then # The order of operations is the same as the order in which entries
# interpreted as the name of the service. In this case, mandatory # appear in the list
# is also set to the default of false.
#
# Use [] to express an empty list.
# # This example enables NetworkManager (and fails if it can't), # # This example enables NetworkManager.service (and fails if it can't),
# # disables cups (and ignores failure). Then it enables the # # disables cups.socket (and ignores failure). Then it enables the
# # graphical target (e.g. so that SDDM runs for login), and # # graphical target (e.g. so that SDDM runs for login), and
# # finally disables pacman-init (an ArchLinux-only service). # # finally masks pacman-init (an ArchLinux-only service).
# # # #
# # Enables <name>.service # units:
# services:
# - name: "NetworkManager" # - name: "NetworkManager"
# action: "enable"
# mandatory: true # mandatory: true
# - name: "cups" #
# - name: "cups.socket"
# action: "disable"
# mandatory: false # mandatory: false
# #
# # Enables <name>.target
# targets:
# - name: "graphical" # - name: "graphical"
# mandatory: true # action: "enable"
# # The property "mandatory" is taken to be false by default here
# # because it is not specified
# #
# # Enables <name>.timer
# timers:
# - name: "fstrim"
# mandatory: false
#
# # Disables <name>.service
# disable:
# - name: "pacman-init" # - name: "pacman-init"
# mandatory: false # action: "mask"
# # # The property "mandatory" is taken to be false by default here
# # Disables <name>.target # # because it is not specified
# # .. this shows how to use just the name
# disable-targets:
# - graphical
#
# # Masks (stronger version of disable). This section
# # is unusual because you **must** include the suffix
# # (e.g. ".service") as part of the name, so, e.g. to mask
# # NetworkManager (rather than just disable it) you must
# # specify "NetworkManager.service" as name.
# mask:
# - name: "NetworkManager.service"
# - mandatory: true
# By default, no changes are made. # By default, no changes are made.
services: [] units: []
targets: []
timers: []
disable: []
disable-targets: []
mask: []

View File

@ -4,22 +4,18 @@
$schema: https://json-schema.org/schema# $schema: https://json-schema.org/schema#
$id: https://calamares.io/schemas/services-systemd $id: https://calamares.io/schemas/services-systemd
definitions: definitions:
service: unit:
$id: 'definitions/service' $id: 'definitions/unit'
type: object type: object
description: a name and a flag for services, targets, and others description: a map containing a unit name, an action, and whether it is mandatory
additionalProperties: false additionalProperties: false
properties: properties:
name: { type: string } name: { type: string }
action: { type: string, default: "enable" }
mandatory: { type: boolean, default: false } mandatory: { type: boolean, default: false }
required: [ name ] required: [ name ]
additionalProperties: false additionalProperties: false
type: object type: object
properties: properties:
services: { type: array, items: { $ref: 'definitions/service' } } units: { type: array, items: { $ref: 'definitions/unit' } }
targets: { type: array, items: { $ref: 'definitions/service' } }
timers: { type: array, items: { $ref: 'definitions/service' } }
disable: { type: array, items: { $ref: 'definitions/service' } }
disable-targets: { type: array, items: { $ref: 'definitions/service' } }
mask: { type: array, items: { $ref: 'definitions/service' } }