Skip to content

Commit

Permalink
nixos: systemd: make common options reusable
Browse files Browse the repository at this point in the history
  • Loading branch information
bobvanderlinden committed Mar 13, 2022
1 parent ede620c commit e5ad5b3
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 107 deletions.
193 changes: 193 additions & 0 deletions nixos/lib/systemd-submodules.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
{
config,
lib,
pkgs,
utils,
}: let
mountModule' = name: module: {config, ...} @ args: let
moduleInstance = module (args // {config = config.${name};});
in {
options.${name} = moduleInstance.options;
config.${name} = moduleInstance.config;
};

mountModule = names: module: lib.foldr mountModule' module names;

inherit (utils.systemdUtils.lib) generateUnits makeUnit unitConfig mountConfig automountConfig;
inherit (utils.systemdUtils.unitOptions) concreteUnitOptions mountOptions automountOptions;
in
with lib; rec {
mkUnitTypeModule = {
name,
extension,
subOptions,
extraConfigs ? [],
toUnit,
description,
}: {config, ...}: {
options = {
"${name}" = mkOption {
default = {};
type = with types; attrsOf (submodule ([{options = subOptions;} unitConfig] ++ extraConfigs));
description = description;
};
};

config = {
units =
mapAttrs' (n: v: nameValuePair "${n}${extension}" (toUnit n v)) config.${name};
};
};

mkModules = {
title,
type,
upstreamUnits ? [],
upstreamWants ? [],
suppressedUnits ? [],
mount ? [],
}:
mapAttrs (name: module: mountModule mount module) {
units = {config, ...}: {
options = {
units = mkOption {
description = "Definition of ${title} units.";
default = {};
type = with types;
attrsOf (submodule (
{
name,
config,
...
}: {
options = concreteUnitOptions;
config = {
unit = mkDefault (makeUnit name config);
};
}
));
};

unitsSource = mkOption {
internal = true;
visible = false;
type = types.path;
};

upstreamUnits = mkOption {
type = with types; listOf str;
default = upstreamUnits;
};

upstreamWants = mkOption {
type = with types; listOf str;
default = upstreamWants;
};
};

config = {
unitsSource = let
enabledUpstreamUnits = filter (n: !elem n suppressedUnits) config.upstreamUnits;
enabledUnits = filterAttrs (n: v: !elem n suppressedUnits) config.units;
in
generateUnits type enabledUnits enabledUpstreamUnits config.upstreamWants;
};
};

targets = mkUnitTypeModule {
name = "targets";
extension = ".target";
subOptions = utils.systemdUtils.unitOptions.targetOptions;
toUnit = utils.systemdUtils.lib.targetToUnit;
description = "Definition of ${title} target units.";
};

services = mkUnitTypeModule {
name = "services";
extension = ".service";
subOptions = utils.systemdUtils.unitOptions.serviceOptions;
extraConfigs = [utils.systemdUtils.lib.serviceConfig];
toUnit = utils.systemdUtils.lib.serviceToUnit;
description = "Definition of ${title} service units.";
};

sockets = mkUnitTypeModule {
name = "sockets";
extension = ".socket";
subOptions = utils.systemdUtils.unitOptions.socketOptions;
toUnit = utils.systemdUtils.lib.socketToUnit;
description = "Definition of ${title} socket units.";
};

timers = mkUnitTypeModule {
name = "timers";
extension = ".timer";
subOptions = utils.systemdUtils.unitOptions.timerOptions;
toUnit = utils.systemdUtils.lib.timerToUnit;
description = "Definition of ${title} timer units.";
};

paths = mkUnitTypeModule {
name = "paths";
extension = ".path";
subOptions = utils.systemdUtils.unitOptions.pathOptions;
toUnit = utils.systemdUtils.lib.pathToUnit;
description = "Definition of ${title} path units.";
};

slices = mkUnitTypeModule {
name = "slices";
extension = ".slice";
subOptions = utils.systemdUtils.unitOptions.sliceOptions;
extraConfigs = [utils.systemdUtils.lib.sliceConfig];
toUnit = utils.systemdUtils.lib.sliceToUnit;
description = "Definition of ${title} slice configurations.";
};

mounts = {config, ...}: {
options = {
mounts = mkOption {
default = [];
type = with types; listOf (submodule [{options = mountOptions;} unitConfig mountConfig]);
description = ''
Definition of ${title} mount units.
This is a list instead of an attrSet, because systemd mandates the names to be derived from
the 'where' attribute.
'';
};
};

config = {
units = listToAttrs (map
(v: let
n = escapeSystemdPath v.where;
in
nameValuePair "${n}.mount" (mountToUnit n v))
config.mounts);
};
};

automounts = {config, ...}: {
options = {
automounts = mkOption {
default = [];
type = with types; listOf (submodule [{options = automountOptions;} unitConfig automountConfig]);
description = ''
Definition of ${title} automount units.
This is a list instead of an attrSet, because systemd mandates the names to be derived from
the 'where' attribute.
'';
};
};

config = {
units = listToAttrs (map
(v: let
n = escapeSystemdPath v.where;
in
nameValuePair "${n}.automount" (automountToUnit n v))
config.automounts);
};
};
};
}
126 changes: 19 additions & 107 deletions nixos/modules/system/boot/systemd.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{ config, lib, pkgs, utils, ... }:

with utils;
with systemdUtils.unitOptions;
with lib;

let
Expand All @@ -10,24 +8,6 @@ let

systemd = cfg.package;

inherit (systemdUtils.lib)
makeUnit
generateUnits
makeJobScript
unitConfig
serviceConfig
mountConfig
automountConfig
commonUnitText
targetToUnit
serviceToUnit
socketToUnit
timerToUnit
pathToUnit
mountToUnit
automountToUnit
sliceToUnit;

upstreamSystemUnits =
[ # Targets.
"basic.target"
Expand Down Expand Up @@ -182,81 +162,13 @@ in
description = "The systemd package.";
};

systemd.units = mkOption {
description = "Definition of systemd units.";
default = {};
type = with types; attrsOf (submodule (
{ name, config, ... }:
{ options = concreteUnitOptions;
config = {
unit = mkDefault (makeUnit name config);
};
}));
};

systemd.packages = mkOption {
default = [];
type = types.listOf types.package;
example = literalExpression "[ pkgs.systemd-cryptsetup-generator ]";
description = "Packages providing systemd units and hooks.";
};

systemd.targets = mkOption {
default = {};
type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] );
description = "Definition of systemd target units.";
};

systemd.services = mkOption {
default = {};
type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ]);
description = "Definition of systemd service units.";
};

systemd.sockets = mkOption {
default = {};
type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ]);
description = "Definition of systemd socket units.";
};

systemd.timers = mkOption {
default = {};
type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ]);
description = "Definition of systemd timer units.";
};

systemd.paths = mkOption {
default = {};
type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]);
description = "Definition of systemd path units.";
};

systemd.mounts = mkOption {
default = [];
type = with types; listOf (submodule [ { options = mountOptions; } unitConfig mountConfig ]);
description = ''
Definition of systemd mount units.
This is a list instead of an attrSet, because systemd mandates the names to be derived from
the 'where' attribute.
'';
};

systemd.automounts = mkOption {
default = [];
type = with types; listOf (submodule [ { options = automountOptions; } unitConfig automountConfig ]);
description = ''
Definition of systemd automount units.
This is a list instead of an attrSet, because systemd mandates the names to be derived from
the 'where' attribute.
'';
};

systemd.slices = mkOption {
default = {};
type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig] );
description = "Definition of slice configurations.";
};

systemd.generators = mkOption {
type = types.attrsOf types.path;
default = {};
Expand Down Expand Up @@ -467,11 +379,8 @@ in
done
${concatStrings (mapAttrsToList (exec: target: "ln -s ${target} $out/${exec};\n") links)}
'';

enabledUpstreamSystemUnits = filter (n: ! elem n cfg.suppressedSystemUnits) upstreamSystemUnits;
enabledUnits = filterAttrs (n: v: ! elem n cfg.suppressedSystemUnits) cfg.units;
in ({
"systemd/system".source = generateUnits "system" enabledUnits enabledUpstreamSystemUnits upstreamSystemWants;
"systemd/system".source = cfg.unitsSource;

"systemd/system.conf".text = ''
[Manager]
Expand Down Expand Up @@ -528,20 +437,6 @@ in
unitConfig.X-StopOnReconfiguration = true;
};

systemd.units =
mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
// mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices
// mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets
// mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
// mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers
// listToAttrs (map
(v: let n = escapeSystemdPath v.where;
in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts)
// listToAttrs (map
(v: let n = escapeSystemdPath v.where;
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);

system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled
[ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET"
"SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC"
Expand Down Expand Up @@ -611,7 +506,24 @@ in

# FIXME: Remove these eventually.
imports =
[ (mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ])
(with (import ./../../../lib/systemd-submodules.nix { inherit config lib pkgs utils; }).mkModules {
title = "systemd";
type = "system";
upstreamUnits = upstreamSystemUnits;
upstreamWants = upstreamSystemWants;
mount = [ "systemd" ];
}; [
units
targets
services
sockets
timers
mounts
automounts
paths
slices
]) ++ [
(mkRenamedOptionModule [ "boot" "systemd" "sockets" ] [ "systemd" "sockets" ])
(mkRenamedOptionModule [ "boot" "systemd" "targets" ] [ "systemd" "targets" ])
(mkRenamedOptionModule [ "boot" "systemd" "services" ] [ "systemd" "services" ])
(mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ])
Expand Down

0 comments on commit e5ad5b3

Please sign in to comment.