Merge pull request #297726 from r-vdp/systemd-unit-names

systemd: add a name option to all systemd units

Changed files
+124 -63
nixos
+55 -20
nixos/lib/systemd-lib.nix
···
-
{ config, lib, pkgs }:
+
{ config, lib, pkgs, utils }:
let
inherit (lib)
···
};
};
-
serviceConfig = { config, ... }: {
-
config.environment.PATH = mkIf (config.path != []) "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
+
serviceConfig = { name, config, ... }: {
+
config = {
+
name = "${name}.service";
+
environment.PATH = mkIf (config.path != []) "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
+
};
+
};
+
+
pathConfig = { name, config, ... }: {
+
config = {
+
name = "${name}.path";
+
};
+
};
+
+
socketConfig = { name, config, ... }: {
+
config = {
+
name = "${name}.socket";
+
};
+
};
+
+
sliceConfig = { name, config, ... }: {
+
config = {
+
name = "${name}.slice";
+
};
+
};
+
+
targetConfig = { name, config, ... }: {
+
config = {
+
name = "${name}.target";
+
};
+
};
+
+
timerConfig = { name, config, ... }: {
+
config = {
+
name = "${name}.timer";
+
};
};
stage2ServiceConfig = {
···
mountConfig = { config, ... }: {
config = {
+
name = "${utils.escapeSystemdPath config.where}.mount";
mountConfig =
{ What = config.what;
Where = config.where;
···
automountConfig = { config, ... }: {
config = {
+
name = "${utils.escapeSystemdPath config.where}.automount";
automountConfig =
{ Where = config.where;
};
···
WantedBy=${concatStringsSep " " def.wantedBy}
'';
-
targetToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
targetToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text =
''
[Unit]
···
'';
};
-
serviceToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
serviceToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def (''
[Service]
'' + (let env = cfg.globalEnvironment // def.environment;
···
"Environment=${toJSON "${n}=${env.${n}}"}\n";
# systemd max line length is now 1MiB
# https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af
-
in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env))
+
in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${def.name}.service’ is too long." else s) (attrNames env))
+ (if def ? reloadIfChanged && def.reloadIfChanged then ''
X-ReloadIfChanged=true
'' else if (def ? restartIfChanged && !def.restartIfChanged) then ''
···
'' + attrsToSection def.serviceConfig);
};
-
socketToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
socketToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def ''
[Socket]
${attrsToSection def.socketConfig}
···
'';
};
-
timerToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
timerToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def ''
[Timer]
${attrsToSection def.timerConfig}
'';
};
-
pathToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
pathToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def ''
[Path]
${attrsToSection def.pathConfig}
'';
};
-
mountToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
mountToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def ''
[Mount]
${attrsToSection def.mountConfig}
'';
};
-
automountToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
automountToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def ''
[Automount]
${attrsToSection def.automountConfig}
'';
};
-
sliceToUnit = name: def:
-
{ inherit (def) aliases wantedBy requiredBy upheldBy enable overrideStrategy;
+
sliceToUnit = def:
+
{ inherit (def) name aliases wantedBy requiredBy upheldBy enable overrideStrategy;
text = commonUnitText def ''
[Slice]
${attrsToSection def.sliceConfig}
+20 -12
nixos/lib/systemd-types.nix
···
automountConfig
makeUnit
mountConfig
+
pathConfig
+
sliceConfig
+
socketConfig
stage1ServiceConfig
stage2ServiceConfig
+
targetConfig
+
timerConfig
unitConfig
;
···
;
in
-
rec {
+
{
units = attrsOf (submodule ({ name, config, ... }: {
options = concreteUnitOptions;
-
config = { unit = mkDefault (makeUnit name config); };
+
config = {
+
name = mkDefault name;
+
unit = mkDefault (makeUnit name config);
+
};
}));
services = attrsOf (submodule [ stage2ServiceOptions unitConfig stage2ServiceConfig ]);
initrdServices = attrsOf (submodule [ stage1ServiceOptions unitConfig stage1ServiceConfig ]);
-
targets = attrsOf (submodule [ stage2CommonUnitOptions unitConfig ]);
-
initrdTargets = attrsOf (submodule [ stage1CommonUnitOptions unitConfig ]);
+
targets = attrsOf (submodule [ stage2CommonUnitOptions unitConfig targetConfig ]);
+
initrdTargets = attrsOf (submodule [ stage1CommonUnitOptions unitConfig targetConfig ]);
-
sockets = attrsOf (submodule [ stage2SocketOptions unitConfig ]);
-
initrdSockets = attrsOf (submodule [ stage1SocketOptions unitConfig ]);
+
sockets = attrsOf (submodule [ stage2SocketOptions unitConfig socketConfig]);
+
initrdSockets = attrsOf (submodule [ stage1SocketOptions unitConfig socketConfig ]);
-
timers = attrsOf (submodule [ stage2TimerOptions unitConfig ]);
-
initrdTimers = attrsOf (submodule [ stage1TimerOptions unitConfig ]);
+
timers = attrsOf (submodule [ stage2TimerOptions unitConfig timerConfig ]);
+
initrdTimers = attrsOf (submodule [ stage1TimerOptions unitConfig timerConfig ]);
-
paths = attrsOf (submodule [ stage2PathOptions unitConfig ]);
-
initrdPaths = attrsOf (submodule [ stage1PathOptions unitConfig ]);
+
paths = attrsOf (submodule [ stage2PathOptions unitConfig pathConfig ]);
+
initrdPaths = attrsOf (submodule [ stage1PathOptions unitConfig pathConfig ]);
-
slices = attrsOf (submodule [ stage2SliceOptions unitConfig ]);
-
initrdSlices = attrsOf (submodule [ stage1SliceOptions unitConfig ]);
+
slices = attrsOf (submodule [ stage2SliceOptions unitConfig sliceConfig ]);
+
initrdSlices = attrsOf (submodule [ stage1SliceOptions unitConfig sliceConfig ]);
mounts = listOf (submodule [ stage2MountOptions unitConfig mountConfig ]);
initrdMounts = listOf (submodule [ stage1MountOptions unitConfig mountConfig ]);
+8
nixos/lib/systemd-unit-options.nix
···
'';
};
+
name = lib.mkOption {
+
type = lib.types.str;
+
description = ''
+
The name of this systemd unit, including its extension.
+
This can be used to refer to this unit from other systemd units.
+
'';
+
};
+
overrideStrategy = mkOption {
default = "asDropinIfExists";
type = types.enum [ "asDropinIfExists" "asDropin" ];
+5 -3
nixos/lib/utils.nix
···
inherit (lib.strings) toJSON normalizePath escapeC;
in
-
rec {
+
let
+
utils = rec {
# Copy configuration files to avoid having the entire sources in the system closure
copyFile = filePath: pkgs.runCommand (builtins.unsafeDiscardStringContext (baseNameOf filePath)) {} ''
···
filter (x: !(elem (getName x) namesToRemove)) packages;
systemdUtils = {
-
lib = import ./systemd-lib.nix { inherit lib config pkgs; };
+
lib = import ./systemd-lib.nix { inherit lib config pkgs utils; };
unitOptions = import ./systemd-unit-options.nix { inherit lib systemdUtils; };
types = import ./systemd-types.nix { inherit lib systemdUtils pkgs; };
network = {
units = import ./systemd-network-units.nix { inherit lib systemdUtils; };
};
};
-
}
+
};
+
in utils
+11 -12
nixos/modules/system/boot/systemd.nix
···
};
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);
+
let
+
withName = cfgToUnit: cfg: lib.nameValuePair cfg.name (cfgToUnit cfg);
+
in
+
mapAttrs' (_: withName pathToUnit) cfg.paths
+
// mapAttrs' (_: withName serviceToUnit) cfg.services
+
// mapAttrs' (_: withName sliceToUnit) cfg.slices
+
// mapAttrs' (_: withName socketToUnit) cfg.sockets
+
// mapAttrs' (_: withName targetToUnit) cfg.targets
+
// mapAttrs' (_: withName timerToUnit) cfg.timers
+
// listToAttrs (map (withName mountToUnit) cfg.mounts)
+
// listToAttrs (map (withName automountToUnit) cfg.automounts);
# Environment of PID 1
systemd.managerEnvironment = {
+8 -8
nixos/modules/system/boot/systemd/initrd.nix
···
targets.initrd.aliases = ["default.target"];
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
+
mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit v)) cfg.paths
+
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit v)) cfg.services
+
// mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices
+
// mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets
+
// mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit v)) cfg.targets
+
// mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers
// listToAttrs (map
(v: let n = escapeSystemdPath v.where;
-
in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts)
+
in nameValuePair "${n}.mount" (mountToUnit v)) cfg.mounts)
// listToAttrs (map
(v: let n = escapeSystemdPath v.where;
-
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
+
in nameValuePair "${n}.automount" (automountToUnit v)) cfg.automounts);
# make sure all the /dev nodes are set up
services.systemd-tmpfiles-setup-dev.wantedBy = ["sysinit.target"];
+6 -6
nixos/modules/system/boot/systemd/user.nix
···
};
systemd.user.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;
+
mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit v)) cfg.paths
+
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit v)) cfg.services
+
// mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices
+
// mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets
+
// mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit v)) cfg.targets
+
// mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers;
# Generate timer units for all services that have a ‘startAt’ value.
systemd.user.timers =
+11 -2
nixos/tests/systemd.nix
···
import ./make-test-python.nix ({ pkgs, ... }: {
name = "systemd";
-
nodes.machine = { lib, ... }: {
+
nodes.machine = { config, lib, ... }: {
imports = [ common/user-account.nix common/x11.nix ];
virtualisation.emptyDiskImages = [ 512 512 ];
···
script = "true";
};
+
systemd.services.testDependency1 = {
+
description = "Test Dependency 1";
+
wantedBy = [ config.systemd.services."testservice1".name ];
+
serviceConfig.Type = "oneshot";
+
script = ''
+
true
+
'';
+
};
+
systemd.services.testservice1 = {
description = "Test Service 1";
-
wantedBy = [ "multi-user.target" ];
+
wantedBy = [ config.systemd.targets.multi-user.name ];
serviceConfig.Type = "oneshot";
script = ''
if [ "$XXX_SYSTEM" = foo ]; then