lib/services: add some generalization options (#535695)

This commit is contained in:
Aaron Andersen
2026-07-11 12:26:04 +00:00
committed by GitHub
2 changed files with 94 additions and 1 deletions

View File

@@ -6,6 +6,7 @@
# The module
{
lib,
config,
...
}:
let
@@ -49,6 +50,53 @@ in
a shell script or `importas` from `pkgs.execline`.
'';
};
reloadSignal = mkOption {
type = types.nullOr types.str;
default = null;
example = "HUP";
description = ''
Configures the reload signal to send to the service manager.
'';
};
reloadCommand = mkOption {
type = types.nullOr types.str;
default = null;
example = lib.literalExpression ''"''${pkgs.coreutils}/bin/kill -HUP $MAINPID"'';
description = ''
Command used for reloading in the underlying service manager to reload.
'';
};
};
notificationProtocol = mkOption {
type = types.listOf (
types.enum [
"systemd"
"s6"
]
);
default = [ ];
apply = v: lib.unique v;
description = ''
Notification protocol that this service supports with the underlying service manager.
'';
};
};
config = {
assertions = [
{
assertion = config.process.reloadSignal != null && config.process.reloadCommand != null;
message = "reloadSignal conflicts with reloadCommand. Please either use reloadSignal or reloadCommand.";
}
];
process.reloadCommand = (lib.mkIf config.process.reloadSignal != null) (
lib.mkForce "${pkgs.coreutils}/bin/kill -${config.process.reloadSignal} $MAINPID"
);
};
}

View File

@@ -113,6 +113,48 @@ in
defaultText = lib.literalExpression "config.systemd.lib.escapeSystemdExecArgs config.process.argv";
};
systemd.mainExecReload = mkOption {
description = ''
Main command line for systemd's ExecReload with systemd's specifier and
environment variable substitution enabled.
This option sets the primary ExecRestart entry. Additional ExecReload entries
can be added via `systemd.service.serviceConfig.ExecReload` with `lib.mkBefore`
or `lib.mkAfter`.
This option allows you to use systemd specifiers like `%n` (unit name),
`%i` (instance), `%t` (runtime directory), and environment variables using
`''${VAR}` syntax in your command line.
By default, it is either set to null or this is set to the escaped version of {option}`process.reloadCommand`
when specified to prevent systemd substitution. Set this option explicitly to enable
systemd's substitution features.
To extend {option}`process.reloadCommand` with systemd specifiers, you can append
to the escaped arguments:
```nix
systemd.mainExecReload =
config.systemd.lib.escapeSystemdExecArgs config.process.reload + " --systemd-unit %n";
```
This pattern allows you to pass the unit name (or other systemd specifiers)
as additional arguments while keeping the base command from {option}`process.argv`
properly escaped.
See {manpage}`systemd.service(5)` (section "COMMAND LINES") for details on
variable substitution and {manpage}`systemd.unit(5)` (section "SPECIFIERS")
for available specifiers like `%n`, `%i`, `%t`.
'';
type = types.nullOr types.str;
default =
if config.process.reloadCommand then
config.systemd.lib.escapeSystemdExecArgs config.process.reloadCommand
else
"";
defaultText = lib.literalExpression "config.systemd.lib.escapeSystemdExecArgs config.process.reloadCommand";
};
systemd.services = mkOption {
description = ''
This module configures systemd services, with the notable difference that their unit names will be prefixed with the abstract service name.
@@ -170,7 +212,10 @@ in
# TODO description;
wantedBy = lib.mkDefault [ "multi-user.target" ];
serviceConfig = {
Type = lib.mkDefault "simple";
ExecReload = config.systemd.mainExecReload;
Type = lib.mkDefault (
if (config.serviceManager.notificationProtocol == "systemd") then "notify" else "simple"
);
Restart = lib.mkDefault "always";
RestartSec = lib.mkDefault "5";
ExecStart = [