Compare commits

..

1 Commits

Author SHA1 Message Date
1eba5ba959 add services-runit 2023-12-26 02:45:08 +01:00
3 changed files with 45 additions and 31 deletions

View File

@@ -4,7 +4,7 @@
# === This file is part of Calamares - <https://github.com/calamares> === # === This file is part of Calamares - <https://github.com/calamares> ===
# #
# Copyright 2018-2019, Adriaan de Groot <groot@kde.org> # Copyright 2018-2019, Adriaan de Groot <groot@kde.org>
# Copyright 2021, Artoo <artoo@artixlinux.org> # Copyright 2019, Artoo <artoo@artixlinux.org>
# #
# Calamares is free software: you can redistribute it and/or modify # Calamares is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@@ -33,12 +33,12 @@ _ = gettext.translation("calamares-python",
def pretty_name(): def pretty_name():
return _("Configure Dinit services") return _("Configure Runit services")
class DinitController: class RunitController:
""" """
This is the dinit service controller. This is the runit service controller.
All of its state comes from global storage and the job All of its state comes from global storage and the job
configuration at initialization time. configuration at initialization time.
""" """
@@ -51,43 +51,45 @@ class DinitController:
self.services["enable"] = libcalamares.job.configuration.get('services', []) self.services["enable"] = libcalamares.job.configuration.get('services', [])
self.services["disable"] = libcalamares.job.configuration.get('disable', []) self.services["disable"] = libcalamares.job.configuration.get('disable', [])
self.initdDir = libcalamares.job.configuration['initdDir'] self.svDir = libcalamares.job.configuration['svDir']
self.runsvDir = libcalamares.job.configuration['runsvDir'] self.runsvDir = libcalamares.job.configuration['runsvDir']
def make_failure_description(self, state, name): def make_failure_description(self, state, name, runlevel):
""" """
Returns a generic "could not <foo>" failure message, specialized Returns a generic "could not <foo>" failure message, specialized
for the action @p state and the specific service @p name. for the action @p state and the specific service @p name in @p runlevel.
""" """
if state == "enable": if state == "enable":
description = _("Cannot enable service {name!s}.") description = _("Cannot enable service {name!s} to run-level {level!s}.")
elif state == "disable": elif state == "disable":
description = _("Cannot disable service {name!s}.") description = _("Cannot disable service {name!s} from run-level {level!s}.")
else: else:
description = _("Unknown service-action <code>{arg!s}</code> for service {name!s}.") description = _("Unknown service-action <code>{arg!s}</code> for service {name!s} in run-level {level!s}.")
return description.format(arg=state, name=name) return description.format(arg=state, name=name, level=runlevel)
def update(self, state): def update(self, state):
""" """
Process each service listed Call sv-helper for each service listed
in services for the given @p state. in services for the given @p state.
""" """
for svc in self.services.get(state, []): for svc in self.services.get(state, []):
if isinstance(svc, str): if isinstance(svc, str):
name = svc name = svc
runlevel = "default"
mandatory = False mandatory = False
else: else:
name = svc["name"] name = svc["name"]
runlevel = svc.get("runlevel", "default")
mandatory = svc.get("mandatory", False) mandatory = svc.get("mandatory", False)
service_path = self.root + self.initdDir + "/" + name service_path = self.root + self.svDir + "/" + name
runlevel_path = self.root + self.runsvDir runlevel_path = self.root + self.runsvDir + "/" + runlevel
src = self.initdDir + "/" + name src = self.svDir + "/" + name
dest = self.runsvDir + "/" dest = self.runsvDir + "/" + runlevel + "/"
if state == 'enable': if state == 'enable':
cmd = ["ln", "-sv", src, dest] cmd = ["ln", "-sv", src, dest]
@@ -98,21 +100,30 @@ class DinitController:
if exists(runlevel_path): if exists(runlevel_path):
ec = target_env_call(cmd) ec = target_env_call(cmd)
if ec != 0: if ec != 0:
warning("Cannot {} service {}".format(state, name)) warning("Cannot {} service {} to {}".format(state, name, runlevel))
warning("{} returned error code {!s}".format(cmd, ec)) warning("{} returned error code {!s}".format(cmd, ec))
if mandatory: if mandatory:
title = _("Cannot modify service") title = _("Cannot modify service")
diagnostic = _("<code>cmd {arg!s}</code> call in chroot returned error code {num!s}.").format(arg=state, num=ec) diagnostic = _("<code>cmd {arg!s}</code> call in chroot returned error code {num!s}.").format(arg=state, num=ec)
return (title, return (title,
self.make_failure_description(state, name) + " " + diagnostic self.make_failure_description(state, name, runlevel) + " " + diagnostic
) )
else:
warning("Target runlevel {} does not exist for {}.".format(runlevel, name))
if mandatory:
title = _("Target runlevel does not exist")
diagnostic = _("The path for runlevel {level!s} is <code>{path!s}</code>, which does not exist.").format(level=runlevel, path=runlevel_path)
return (title,
self.make_failure_description(state, name, runlevel) + " " + diagnostic
)
else: else:
warning("Target service {} does not exist in {}.".format(name, self.initdDir)) warning("Target service {} does not exist in {}.".format(name, self.svDir))
if mandatory: if mandatory:
title = _("Target service does not exist") title = _("Target service does not exist")
diagnostic = _("The path for service {name!s} is <code>{path!s}</code>, which does not exist.").format(name=name, path=service_path) diagnostic = _("The path for service {name!s} is <code>{path!s}</code>, which does not exist.").format(name=name, path=service_path)
return (title, return (title,
self.make_failure_description(state, name) + " " + diagnostic self.make_failure_description(state, name, runlevel) + " " + diagnostic
) )
@@ -130,4 +141,4 @@ def run():
Setup services Setup services
""" """
return DinitController().run() return RunitController().run()

View File

@@ -1,5 +1,5 @@
--- ---
type: "job" type: "job"
name: "services-dinit" name: "services-runit"
interface: "python" interface: "python"
script: "main.py" script: "main.py"

View File

@@ -4,36 +4,39 @@
# Handle disable with care and only use it if absolutely necessary. # Handle disable with care and only use it if absolutely necessary.
# #
# if a service is listed in the conf but is not present/detected on the target system, # if a service is listed in the conf but is not present/detected on the target system,
# it will be ignored and skipped; a warning is logged. # or a runlevel does not exist, it will be ignored and skipped; a warning is logged.
# #
--- ---
# initdDir: holds the runit service directory location # svDir: holds the runit service directory location
initdDir: /etc/dinit.d svDir: /etc/runit/sv
# runsvDir: holds the runlevels directory location # runsvDir: holds the runlevels directory location
runsvDir: /etc/dinit.d/boot.d runsvDir: /etc/runit/runsvdir
# services: a list of entries to **enable** # services: a list of entries to **enable**
# disable: a list of entries to **disable** # disable: a list of entries to **disable**
# #
# Each entry has three fields: # Each entry has three fields:
# - name: the service name # - name: the service name
# - (optional) runlevel: can hold any runlevel present on the target
# system; if no runlevel is provided, "default" is assumed.
# - (optional) mandatory: if set to true, a failure to modify # - (optional) mandatory: if set to true, a failure to modify
# the service will result in installation failure, rather than just # the service will result in installation failure, rather than just
# a warning. The default is false. # a warning. The default is false.
# #
# an entry may also be a single string, which is interpreted # an entry may also be a single string, which is interpreted
# as the name field. # as the name field (runlevel "default" is assumed then, and not-mandatory).
# #
# # Example services and disable settings: # # Example services and disable settings:
# # - add foo1, but it must succeed # # - add foo1 to default, but it must succeed
# # - add foo2 # # - add foo2 to nonetwork
# # - remove foo3 # # - remove foo3 from default
# # - remove foo4 # # - remove foo4 from default
# services: # services:
# - name: foo1 # - name: foo1
# mandatory: true # mandatory: true
# - name: foo2 # - name: foo2
# runlevel: nonetwork
# disable: # disable:
# - name: foo3 # - name: foo3
# - foo4 # - foo4