Merge pull request #164317 from bobvanderlinden/pr-move-systemd-fns-lib
nixos: systemd: split off helper functions into systemd-lib
This commit is contained in:
commit
e98ae78636
|
@ -5,6 +5,7 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.systemd;
|
cfg = config.systemd;
|
||||||
lndir = "${pkgs.buildPackages.xorg.lndir}/bin/lndir";
|
lndir = "${pkgs.buildPackages.xorg.lndir}/bin/lndir";
|
||||||
|
systemd = cfg.package;
|
||||||
in rec {
|
in rec {
|
||||||
|
|
||||||
shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s);
|
shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s);
|
||||||
|
@ -235,4 +236,205 @@ in rec {
|
||||||
''}
|
''}
|
||||||
''; # */
|
''; # */
|
||||||
|
|
||||||
|
makeJobScript = name: text:
|
||||||
|
let
|
||||||
|
scriptName = replaceChars [ "\\" "@" ] [ "-" "_" ] (shellEscape name);
|
||||||
|
out = (pkgs.writeShellScriptBin scriptName ''
|
||||||
|
set -e
|
||||||
|
${text}
|
||||||
|
'').overrideAttrs (_: {
|
||||||
|
# The derivation name is different from the script file name
|
||||||
|
# to keep the script file name short to avoid cluttering logs.
|
||||||
|
name = "unit-script-${scriptName}";
|
||||||
|
});
|
||||||
|
in "${out}/bin/${scriptName}";
|
||||||
|
|
||||||
|
unitConfig = { config, options, ... }: {
|
||||||
|
config = {
|
||||||
|
unitConfig =
|
||||||
|
optionalAttrs (config.requires != [])
|
||||||
|
{ Requires = toString config.requires; }
|
||||||
|
// optionalAttrs (config.wants != [])
|
||||||
|
{ Wants = toString config.wants; }
|
||||||
|
// optionalAttrs (config.after != [])
|
||||||
|
{ After = toString config.after; }
|
||||||
|
// optionalAttrs (config.before != [])
|
||||||
|
{ Before = toString config.before; }
|
||||||
|
// optionalAttrs (config.bindsTo != [])
|
||||||
|
{ BindsTo = toString config.bindsTo; }
|
||||||
|
// optionalAttrs (config.partOf != [])
|
||||||
|
{ PartOf = toString config.partOf; }
|
||||||
|
// optionalAttrs (config.conflicts != [])
|
||||||
|
{ Conflicts = toString config.conflicts; }
|
||||||
|
// optionalAttrs (config.requisite != [])
|
||||||
|
{ Requisite = toString config.requisite; }
|
||||||
|
// optionalAttrs (config.restartTriggers != [])
|
||||||
|
{ X-Restart-Triggers = toString config.restartTriggers; }
|
||||||
|
// optionalAttrs (config.reloadTriggers != [])
|
||||||
|
{ X-Reload-Triggers = toString config.reloadTriggers; }
|
||||||
|
// optionalAttrs (config.description != "") {
|
||||||
|
Description = config.description; }
|
||||||
|
// optionalAttrs (config.documentation != []) {
|
||||||
|
Documentation = toString config.documentation; }
|
||||||
|
// optionalAttrs (config.onFailure != []) {
|
||||||
|
OnFailure = toString config.onFailure; }
|
||||||
|
// optionalAttrs (options.startLimitIntervalSec.isDefined) {
|
||||||
|
StartLimitIntervalSec = toString config.startLimitIntervalSec;
|
||||||
|
} // optionalAttrs (options.startLimitBurst.isDefined) {
|
||||||
|
StartLimitBurst = toString config.startLimitBurst;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceConfig = { name, config, ... }: {
|
||||||
|
config = mkMerge
|
||||||
|
[ { # Default path for systemd services. Should be quite minimal.
|
||||||
|
path = mkAfter
|
||||||
|
[ pkgs.coreutils
|
||||||
|
pkgs.findutils
|
||||||
|
pkgs.gnugrep
|
||||||
|
pkgs.gnused
|
||||||
|
systemd
|
||||||
|
];
|
||||||
|
environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
|
||||||
|
}
|
||||||
|
(mkIf (config.preStart != "")
|
||||||
|
{ serviceConfig.ExecStartPre =
|
||||||
|
[ (makeJobScript "${name}-pre-start" config.preStart) ];
|
||||||
|
})
|
||||||
|
(mkIf (config.script != "")
|
||||||
|
{ serviceConfig.ExecStart =
|
||||||
|
makeJobScript "${name}-start" config.script + " " + config.scriptArgs;
|
||||||
|
})
|
||||||
|
(mkIf (config.postStart != "")
|
||||||
|
{ serviceConfig.ExecStartPost =
|
||||||
|
[ (makeJobScript "${name}-post-start" config.postStart) ];
|
||||||
|
})
|
||||||
|
(mkIf (config.reload != "")
|
||||||
|
{ serviceConfig.ExecReload =
|
||||||
|
makeJobScript "${name}-reload" config.reload;
|
||||||
|
})
|
||||||
|
(mkIf (config.preStop != "")
|
||||||
|
{ serviceConfig.ExecStop =
|
||||||
|
makeJobScript "${name}-pre-stop" config.preStop;
|
||||||
|
})
|
||||||
|
(mkIf (config.postStop != "")
|
||||||
|
{ serviceConfig.ExecStopPost =
|
||||||
|
makeJobScript "${name}-post-stop" config.postStop;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
mountConfig = { config, ... }: {
|
||||||
|
config = {
|
||||||
|
mountConfig =
|
||||||
|
{ What = config.what;
|
||||||
|
Where = config.where;
|
||||||
|
} // optionalAttrs (config.type != "") {
|
||||||
|
Type = config.type;
|
||||||
|
} // optionalAttrs (config.options != "") {
|
||||||
|
Options = config.options;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
automountConfig = { config, ... }: {
|
||||||
|
config = {
|
||||||
|
automountConfig =
|
||||||
|
{ Where = config.where;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
commonUnitText = def: ''
|
||||||
|
[Unit]
|
||||||
|
${attrsToSection def.unitConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
targetToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text =
|
||||||
|
''
|
||||||
|
[Unit]
|
||||||
|
${attrsToSection def.unitConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Service]
|
||||||
|
${let env = cfg.globalEnvironment // def.environment;
|
||||||
|
in concatMapStrings (n:
|
||||||
|
let s = optionalString (env.${n} != null)
|
||||||
|
"Environment=${builtins.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)}
|
||||||
|
${if def.reloadIfChanged then ''
|
||||||
|
X-ReloadIfChanged=true
|
||||||
|
'' else if !def.restartIfChanged then ''
|
||||||
|
X-RestartIfChanged=false
|
||||||
|
'' else ""}
|
||||||
|
${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
|
||||||
|
${attrsToSection def.serviceConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
socketToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Socket]
|
||||||
|
${attrsToSection def.socketConfig}
|
||||||
|
${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)}
|
||||||
|
${concatStringsSep "\n" (map (s: "ListenDatagram=${s}") def.listenDatagrams)}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
timerToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Timer]
|
||||||
|
${attrsToSection def.timerConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
pathToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Path]
|
||||||
|
${attrsToSection def.pathConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
mountToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Mount]
|
||||||
|
${attrsToSection def.mountConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
automountToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Automount]
|
||||||
|
${attrsToSection def.automountConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sliceToUnit = name: def:
|
||||||
|
{ inherit (def) aliases wantedBy requiredBy enable;
|
||||||
|
text = commonUnitText def +
|
||||||
|
''
|
||||||
|
[Slice]
|
||||||
|
${attrsToSection def.sliceConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,22 @@ let
|
||||||
|
|
||||||
systemd = cfg.package;
|
systemd = cfg.package;
|
||||||
|
|
||||||
|
inherit (systemdUtils.lib)
|
||||||
|
makeJobScript
|
||||||
|
unitConfig
|
||||||
|
serviceConfig
|
||||||
|
mountConfig
|
||||||
|
automountConfig
|
||||||
|
commonUnitText
|
||||||
|
targetToUnit
|
||||||
|
serviceToUnit
|
||||||
|
socketToUnit
|
||||||
|
timerToUnit
|
||||||
|
pathToUnit
|
||||||
|
mountToUnit
|
||||||
|
automountToUnit
|
||||||
|
sliceToUnit;
|
||||||
|
|
||||||
upstreamSystemUnits =
|
upstreamSystemUnits =
|
||||||
[ # Targets.
|
[ # Targets.
|
||||||
"basic.target"
|
"basic.target"
|
||||||
|
@ -209,207 +225,6 @@ let
|
||||||
"xdg-desktop-autostart.target"
|
"xdg-desktop-autostart.target"
|
||||||
];
|
];
|
||||||
|
|
||||||
makeJobScript = name: text:
|
|
||||||
let
|
|
||||||
scriptName = replaceChars [ "\\" "@" ] [ "-" "_" ] (shellEscape name);
|
|
||||||
out = (pkgs.writeShellScriptBin scriptName ''
|
|
||||||
set -e
|
|
||||||
${text}
|
|
||||||
'').overrideAttrs (_: {
|
|
||||||
# The derivation name is different from the script file name
|
|
||||||
# to keep the script file name short to avoid cluttering logs.
|
|
||||||
name = "unit-script-${scriptName}";
|
|
||||||
});
|
|
||||||
in "${out}/bin/${scriptName}";
|
|
||||||
|
|
||||||
unitConfig = { config, options, ... }: {
|
|
||||||
config = {
|
|
||||||
unitConfig =
|
|
||||||
optionalAttrs (config.requires != [])
|
|
||||||
{ Requires = toString config.requires; }
|
|
||||||
// optionalAttrs (config.wants != [])
|
|
||||||
{ Wants = toString config.wants; }
|
|
||||||
// optionalAttrs (config.after != [])
|
|
||||||
{ After = toString config.after; }
|
|
||||||
// optionalAttrs (config.before != [])
|
|
||||||
{ Before = toString config.before; }
|
|
||||||
// optionalAttrs (config.bindsTo != [])
|
|
||||||
{ BindsTo = toString config.bindsTo; }
|
|
||||||
// optionalAttrs (config.partOf != [])
|
|
||||||
{ PartOf = toString config.partOf; }
|
|
||||||
// optionalAttrs (config.conflicts != [])
|
|
||||||
{ Conflicts = toString config.conflicts; }
|
|
||||||
// optionalAttrs (config.requisite != [])
|
|
||||||
{ Requisite = toString config.requisite; }
|
|
||||||
// optionalAttrs (config.restartTriggers != [])
|
|
||||||
{ X-Restart-Triggers = toString config.restartTriggers; }
|
|
||||||
// optionalAttrs (config.reloadTriggers != [])
|
|
||||||
{ X-Reload-Triggers = toString config.reloadTriggers; }
|
|
||||||
// optionalAttrs (config.description != "") {
|
|
||||||
Description = config.description; }
|
|
||||||
// optionalAttrs (config.documentation != []) {
|
|
||||||
Documentation = toString config.documentation; }
|
|
||||||
// optionalAttrs (config.onFailure != []) {
|
|
||||||
OnFailure = toString config.onFailure; }
|
|
||||||
// optionalAttrs (options.startLimitIntervalSec.isDefined) {
|
|
||||||
StartLimitIntervalSec = toString config.startLimitIntervalSec;
|
|
||||||
} // optionalAttrs (options.startLimitBurst.isDefined) {
|
|
||||||
StartLimitBurst = toString config.startLimitBurst;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceConfig = { name, config, ... }: {
|
|
||||||
config = mkMerge
|
|
||||||
[ { # Default path for systemd services. Should be quite minimal.
|
|
||||||
path = mkAfter
|
|
||||||
[ pkgs.coreutils
|
|
||||||
pkgs.findutils
|
|
||||||
pkgs.gnugrep
|
|
||||||
pkgs.gnused
|
|
||||||
systemd
|
|
||||||
];
|
|
||||||
environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
|
|
||||||
}
|
|
||||||
(mkIf (config.preStart != "")
|
|
||||||
{ serviceConfig.ExecStartPre =
|
|
||||||
[ (makeJobScript "${name}-pre-start" config.preStart) ];
|
|
||||||
})
|
|
||||||
(mkIf (config.script != "")
|
|
||||||
{ serviceConfig.ExecStart =
|
|
||||||
makeJobScript "${name}-start" config.script + " " + config.scriptArgs;
|
|
||||||
})
|
|
||||||
(mkIf (config.postStart != "")
|
|
||||||
{ serviceConfig.ExecStartPost =
|
|
||||||
[ (makeJobScript "${name}-post-start" config.postStart) ];
|
|
||||||
})
|
|
||||||
(mkIf (config.reload != "")
|
|
||||||
{ serviceConfig.ExecReload =
|
|
||||||
makeJobScript "${name}-reload" config.reload;
|
|
||||||
})
|
|
||||||
(mkIf (config.preStop != "")
|
|
||||||
{ serviceConfig.ExecStop =
|
|
||||||
makeJobScript "${name}-pre-stop" config.preStop;
|
|
||||||
})
|
|
||||||
(mkIf (config.postStop != "")
|
|
||||||
{ serviceConfig.ExecStopPost =
|
|
||||||
makeJobScript "${name}-post-stop" config.postStop;
|
|
||||||
})
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
mountConfig = { config, ... }: {
|
|
||||||
config = {
|
|
||||||
mountConfig =
|
|
||||||
{ What = config.what;
|
|
||||||
Where = config.where;
|
|
||||||
} // optionalAttrs (config.type != "") {
|
|
||||||
Type = config.type;
|
|
||||||
} // optionalAttrs (config.options != "") {
|
|
||||||
Options = config.options;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
automountConfig = { config, ... }: {
|
|
||||||
config = {
|
|
||||||
automountConfig =
|
|
||||||
{ Where = config.where;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
commonUnitText = def: ''
|
|
||||||
[Unit]
|
|
||||||
${attrsToSection def.unitConfig}
|
|
||||||
'';
|
|
||||||
|
|
||||||
targetToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text =
|
|
||||||
''
|
|
||||||
[Unit]
|
|
||||||
${attrsToSection def.unitConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Service]
|
|
||||||
${let env = cfg.globalEnvironment // def.environment;
|
|
||||||
in concatMapStrings (n:
|
|
||||||
let s = optionalString (env.${n} != null)
|
|
||||||
"Environment=${builtins.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)}
|
|
||||||
${if def.reloadIfChanged then ''
|
|
||||||
X-ReloadIfChanged=true
|
|
||||||
'' else if !def.restartIfChanged then ''
|
|
||||||
X-RestartIfChanged=false
|
|
||||||
'' else ""}
|
|
||||||
${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
|
|
||||||
${attrsToSection def.serviceConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
socketToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Socket]
|
|
||||||
${attrsToSection def.socketConfig}
|
|
||||||
${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)}
|
|
||||||
${concatStringsSep "\n" (map (s: "ListenDatagram=${s}") def.listenDatagrams)}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
timerToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Timer]
|
|
||||||
${attrsToSection def.timerConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
pathToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Path]
|
|
||||||
${attrsToSection def.pathConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
mountToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Mount]
|
|
||||||
${attrsToSection def.mountConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
automountToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Automount]
|
|
||||||
${attrsToSection def.automountConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
sliceToUnit = name: def:
|
|
||||||
{ inherit (def) aliases wantedBy requiredBy enable;
|
|
||||||
text = commonUnitText def +
|
|
||||||
''
|
|
||||||
[Slice]
|
|
||||||
${attrsToSection def.sliceConfig}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
logindHandlerType = types.enum [
|
logindHandlerType = types.enum [
|
||||||
"ignore" "poweroff" "reboot" "halt" "kexec" "suspend"
|
"ignore" "poweroff" "reboot" "halt" "kexec" "suspend"
|
||||||
|
|
Loading…
Reference in a new issue