mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-14 13:39:15 +03:00
Add an option ‘boot.systemd.services’
This option makes it more convenient to define services because it automates stuff like setting $PATH, having a pre-start script, and so on.
This commit is contained in:
parent
673bf12b1d
commit
352510c208
2 changed files with 256 additions and 94 deletions
|
@ -39,6 +39,7 @@ let
|
||||||
);
|
);
|
||||||
|
|
||||||
userOptions = {
|
userOptions = {
|
||||||
|
|
||||||
openssh.authorizedKeys = {
|
openssh.authorizedKeys = {
|
||||||
|
|
||||||
preserveExistingKeys = mkOption {
|
preserveExistingKeys = mkOption {
|
||||||
|
@ -77,6 +78,7 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mkAuthkeyScript =
|
mkAuthkeyScript =
|
||||||
|
@ -127,19 +129,6 @@ let
|
||||||
${userLoop}
|
${userLoop}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
preStart = pkgs.writeScript "openssh-pre-start"
|
|
||||||
''
|
|
||||||
#! ${pkgs.stdenv.shell}
|
|
||||||
|
|
||||||
${mkAuthkeyScript}
|
|
||||||
|
|
||||||
mkdir -m 0755 -p /etc/ssh
|
|
||||||
|
|
||||||
if ! test -f ${cfg.hostKeyPath}; then
|
|
||||||
ssh-keygen -t ${hktn} -b ${toString hktb} -f ${cfg.hostKeyPath} -N ""
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -317,27 +306,52 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.systemd.units."sshd.service".text =
|
boot.systemd.services."set-ssh-keys.service" =
|
||||||
''
|
{ description = "Update authorized SSH keys";
|
||||||
[Unit]
|
|
||||||
Description=SSH daemon
|
|
||||||
|
|
||||||
[Service]
|
wantedBy = [ "multi-user.target" ];
|
||||||
Environment=PATH=${pkgs.coreutils}/bin:${pkgs.openssh}/bin
|
|
||||||
Environment=LD_LIBRARY_PATH=${nssModulesPath}
|
|
||||||
Environment=LOCALE_ARCHIVE=/var/run/current-system/sw/lib/locale/locale-archive
|
|
||||||
ExecStartPre=${preStart}
|
|
||||||
ExecStart=\
|
|
||||||
${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} \
|
|
||||||
-f ${pkgs.writeText "sshd_config" cfg.extraConfig}
|
|
||||||
Restart=always
|
|
||||||
Type=forking
|
|
||||||
KillMode=process
|
|
||||||
PIDFile=/run/sshd.pid
|
|
||||||
'';
|
|
||||||
|
|
||||||
boot.systemd.units."sshd.service".wantedBy = [ "multi-user.target" ];
|
script = mkAuthkeyScript;
|
||||||
|
|
||||||
|
serviceConfig =
|
||||||
|
''
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=true
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.systemd.services."sshd.service" =
|
||||||
|
{ description = "SSH daemon";
|
||||||
|
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "set-ssh-keys.service" ];
|
||||||
|
|
||||||
|
path = [ pkgs.openssh ];
|
||||||
|
|
||||||
|
environment.LD_LIBRARY_PATH = nssModulesPath;
|
||||||
|
environment.LOCALE_ARCHIVE = "/var/run/current-system/sw/lib/locale/locale-archive";
|
||||||
|
|
||||||
|
preStart =
|
||||||
|
''
|
||||||
|
mkdir -m 0755 -p /etc/ssh
|
||||||
|
|
||||||
|
if ! test -f ${cfg.hostKeyPath}; then
|
||||||
|
ssh-keygen -t ${hktn} -b ${toString hktb} -f ${cfg.hostKeyPath} -N ""
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig =
|
||||||
|
''
|
||||||
|
ExecStart=\
|
||||||
|
${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} \
|
||||||
|
-f ${pkgs.writeText "sshd_config" cfg.extraConfig}
|
||||||
|
Restart=always
|
||||||
|
Type=forking
|
||||||
|
KillMode=process
|
||||||
|
PIDFile=/run/sshd.pid
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = cfg.ports;
|
networking.firewall.allowedTCPPorts = cfg.ports;
|
||||||
|
|
||||||
services.openssh.extraConfig =
|
services.openssh.extraConfig =
|
||||||
|
|
|
@ -4,6 +4,102 @@ with pkgs.lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
|
servicesOptions = {
|
||||||
|
|
||||||
|
description = mkOption {
|
||||||
|
default = "";
|
||||||
|
types = types.uniq types.string;
|
||||||
|
description = "Description of this unit used in systemd messages and progress indicators.";
|
||||||
|
};
|
||||||
|
|
||||||
|
after = mkOption {
|
||||||
|
default = [];
|
||||||
|
types = types.listOf types.string;
|
||||||
|
description = ''
|
||||||
|
If the specified units are started at the same time as
|
||||||
|
this unit, delay this unit until they have started.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
before = mkOption {
|
||||||
|
default = [];
|
||||||
|
types = types.listOf types.string;
|
||||||
|
description = ''
|
||||||
|
If the specified units are started at the same time as
|
||||||
|
this unit, delay them until this unit has started.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
wantedBy = mkOption {
|
||||||
|
default = [];
|
||||||
|
types = types.listOf types.string;
|
||||||
|
description = "Units that want (i.e. depend on) this unit.";
|
||||||
|
};
|
||||||
|
|
||||||
|
environment = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrs;
|
||||||
|
example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
|
||||||
|
description = "Environment variables passed to the services's processes.";
|
||||||
|
};
|
||||||
|
|
||||||
|
path = mkOption {
|
||||||
|
default = [];
|
||||||
|
apply = ps: "${makeSearchPath "bin" ps}:${makeSearchPath "sbin" ps}";
|
||||||
|
description = ''
|
||||||
|
Packages added to the service's <envar>PATH</envar>
|
||||||
|
environment variable. Both the <filename>bin</filename>
|
||||||
|
and <filename>sbin</filename> subdirectories of each
|
||||||
|
package are added.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceConfig = mkOption {
|
||||||
|
default = "";
|
||||||
|
type = types.string;
|
||||||
|
description = ''
|
||||||
|
Contents of the <literal>[Service]</literal> section of the unit.
|
||||||
|
See <citerefentry><refentrytitle>systemd.unit</refentrytitle>
|
||||||
|
<manvolnum>5</manvolnum></citerefentry> for details.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
script = mkOption {
|
||||||
|
type = types.uniq types.string;
|
||||||
|
default = "";
|
||||||
|
description = "Shell commands executed as the service's main process.";
|
||||||
|
};
|
||||||
|
|
||||||
|
preStart = mkOption {
|
||||||
|
type = types.string;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Shell commands executed before the service's main process
|
||||||
|
is started.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
servicesConfig = { name, config, ... }: {
|
||||||
|
|
||||||
|
config = {
|
||||||
|
|
||||||
|
# Default path for systemd services. Should be quite minimal.
|
||||||
|
path =
|
||||||
|
[ pkgs.coreutils
|
||||||
|
pkgs.findutils
|
||||||
|
pkgs.gnugrep
|
||||||
|
pkgs.gnused
|
||||||
|
systemd
|
||||||
|
];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
cfg = config.boot.systemd;
|
cfg = config.boot.systemd;
|
||||||
|
|
||||||
systemd = pkgs.systemd;
|
systemd = pkgs.systemd;
|
||||||
|
@ -111,6 +207,103 @@ let
|
||||||
"shutdown.target.wants"
|
"shutdown.target.wants"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
rescueService =
|
||||||
|
''
|
||||||
|
[Unit]
|
||||||
|
Description=Rescue Shell
|
||||||
|
DefaultDependencies=no
|
||||||
|
Conflicts=shutdown.target
|
||||||
|
After=sysinit.target
|
||||||
|
Before=shutdown.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=HOME=/root
|
||||||
|
WorkingDirectory=/root
|
||||||
|
ExecStartPre=-${pkgs.coreutils}/bin/echo 'Welcome to rescue mode. Use "systemctl default" or ^D to enter default mode.'
|
||||||
|
#ExecStart=-/sbin/sulogin
|
||||||
|
ExecStart=-${pkgs.bashInteractive}/bin/bash --login
|
||||||
|
ExecStopPost=-${systemd}/bin/systemctl --fail --no-block default
|
||||||
|
Type=idle
|
||||||
|
StandardInput=tty-force
|
||||||
|
StandardOutput=inherit
|
||||||
|
StandardError=inherit
|
||||||
|
KillMode=process
|
||||||
|
|
||||||
|
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
|
||||||
|
# terminates cleanly.
|
||||||
|
KillSignal=SIGHUP
|
||||||
|
'';
|
||||||
|
|
||||||
|
gettyService =
|
||||||
|
''
|
||||||
|
[Unit]
|
||||||
|
Description=Getty on %I
|
||||||
|
Documentation=man:agetty(8)
|
||||||
|
After=systemd-user-sessions.service plymouth-quit-wait.service
|
||||||
|
|
||||||
|
# If additional gettys are spawned during boot then we should make
|
||||||
|
# sure that this is synchronized before getty.target, even though
|
||||||
|
# getty.target didn't actually pull it in.
|
||||||
|
Before=getty.target
|
||||||
|
IgnoreOnIsolate=yes
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=TERM=linux
|
||||||
|
ExecStart=-${pkgs.utillinux}/sbin/agetty --noclear --login-program ${pkgs.shadow}/bin/login %I 38400
|
||||||
|
Type=idle
|
||||||
|
Restart=always
|
||||||
|
RestartSec=0
|
||||||
|
UtmpIdentifier=%I
|
||||||
|
TTYPath=/dev/%I
|
||||||
|
TTYReset=yes
|
||||||
|
TTYVHangup=yes
|
||||||
|
TTYVTDisallocate=yes
|
||||||
|
KillMode=process
|
||||||
|
IgnoreSIGPIPE=no
|
||||||
|
|
||||||
|
# Unset locale for the console getty since the console has problems
|
||||||
|
# displaying some internationalized messages.
|
||||||
|
Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=
|
||||||
|
|
||||||
|
# Some login implementations ignore SIGTERM, so we send SIGHUP
|
||||||
|
# instead, to ensure that login terminates cleanly.
|
||||||
|
KillSignal=SIGHUP
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceToUnit = name: def:
|
||||||
|
{ inherit (def) wantedBy;
|
||||||
|
|
||||||
|
text =
|
||||||
|
''
|
||||||
|
[Unit]
|
||||||
|
${optionalString (def.description != "") ''
|
||||||
|
Description=${def.description}
|
||||||
|
''}
|
||||||
|
Before=${concatStringsSep " " def.before}
|
||||||
|
After=${concatStringsSep " " def.after}
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PATH=${def.path}
|
||||||
|
${concatMapStrings (n: "Environment=${n}=\"${getAttr n def.environment}\"\n") (attrNames def.environment)}
|
||||||
|
|
||||||
|
${optionalString (def.preStart != "") ''
|
||||||
|
ExecStartPre=${pkgs.writeScript "${name}-prestart.sh" ''
|
||||||
|
#! ${pkgs.stdenv.shell} -e
|
||||||
|
${def.preStart}
|
||||||
|
''}
|
||||||
|
''}
|
||||||
|
|
||||||
|
${optionalString (def.script != "") ''
|
||||||
|
ExecStart=${pkgs.writeScript "${name}.sh" ''
|
||||||
|
#! ${pkgs.stdenv.shell} -e
|
||||||
|
${def.script}
|
||||||
|
''}
|
||||||
|
''}
|
||||||
|
|
||||||
|
${def.serviceConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
nixosUnits = mapAttrsToList makeUnit cfg.units;
|
nixosUnits = mapAttrsToList makeUnit cfg.units;
|
||||||
|
|
||||||
units = pkgs.runCommand "units" { preferLocalBuild = true; }
|
units = pkgs.runCommand "units" { preferLocalBuild = true; }
|
||||||
|
@ -160,20 +353,32 @@ in
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
boot.systemd.units = mkOption {
|
boot.systemd.units = mkOption {
|
||||||
|
description = "Definition of systemd units.";
|
||||||
default = {};
|
default = {};
|
||||||
type = types.attrsOf types.optionSet;
|
type = types.attrsOf types.optionSet;
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
text = mkOption {
|
text = mkOption {
|
||||||
types = types.uniq types.string;
|
types = types.uniq types.string;
|
||||||
description = "Text of this systemd unit.";
|
description = "Text of this systemd unit.";
|
||||||
};
|
};
|
||||||
|
|
||||||
wantedBy = mkOption {
|
wantedBy = mkOption {
|
||||||
default = [];
|
default = [];
|
||||||
types = types.listOf types.string;
|
types = types.listOf types.string;
|
||||||
description = "Units that want (i.e. depend on) this unit.";
|
description = "Units that want (i.e. depend on) this unit.";
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
description = "Definition of systemd units.";
|
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.systemd.services = mkOption {
|
||||||
|
description = "Definition of systemd services.";
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf types.optionSet;
|
||||||
|
options = [ servicesOptions servicesConfig ];
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.systemd.defaultUnit = mkOption {
|
boot.systemd.defaultUnit = mkOption {
|
||||||
|
@ -201,68 +406,11 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.systemd.units."getty@.service".text =
|
boot.systemd.units =
|
||||||
''
|
{ "rescue.service".text = rescueService;
|
||||||
[Unit]
|
"getty@.service".text = gettyService;
|
||||||
Description=Getty on %I
|
}
|
||||||
Documentation=man:agetty(8)
|
// mapAttrs serviceToUnit cfg.services;
|
||||||
After=systemd-user-sessions.service plymouth-quit-wait.service
|
|
||||||
|
|
||||||
# If additional gettys are spawned during boot then we should make
|
|
||||||
# sure that this is synchronized before getty.target, even though
|
|
||||||
# getty.target didn't actually pull it in.
|
|
||||||
Before=getty.target
|
|
||||||
IgnoreOnIsolate=yes
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Environment=TERM=linux
|
|
||||||
ExecStart=-${pkgs.utillinux}/sbin/agetty --noclear --login-program ${pkgs.shadow}/bin/login %I 38400
|
|
||||||
Type=idle
|
|
||||||
Restart=always
|
|
||||||
RestartSec=0
|
|
||||||
UtmpIdentifier=%I
|
|
||||||
TTYPath=/dev/%I
|
|
||||||
TTYReset=yes
|
|
||||||
TTYVHangup=yes
|
|
||||||
TTYVTDisallocate=yes
|
|
||||||
KillMode=process
|
|
||||||
IgnoreSIGPIPE=no
|
|
||||||
|
|
||||||
# Unset locale for the console getty since the console has problems
|
|
||||||
# displaying some internationalized messages.
|
|
||||||
Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=
|
|
||||||
|
|
||||||
# Some login implementations ignore SIGTERM, so we send SIGHUP
|
|
||||||
# instead, to ensure that login terminates cleanly.
|
|
||||||
KillSignal=SIGHUP
|
|
||||||
'';
|
|
||||||
|
|
||||||
boot.systemd.units."rescue.service".text =
|
|
||||||
''
|
|
||||||
[Unit]
|
|
||||||
Description=Rescue Shell
|
|
||||||
DefaultDependencies=no
|
|
||||||
Conflicts=shutdown.target
|
|
||||||
After=sysinit.target
|
|
||||||
Before=shutdown.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Environment=HOME=/root
|
|
||||||
WorkingDirectory=/root
|
|
||||||
ExecStartPre=-${pkgs.coreutils}/bin/echo 'Welcome to rescue mode. Use "systemctl default" or ^D to enter default mode.'
|
|
||||||
#ExecStart=-/sbin/sulogin
|
|
||||||
ExecStart=-${pkgs.bashInteractive}/bin/bash --login
|
|
||||||
ExecStopPost=-${systemd}/bin/systemctl --fail --no-block default
|
|
||||||
Type=idle
|
|
||||||
StandardInput=tty-force
|
|
||||||
StandardOutput=inherit
|
|
||||||
StandardError=inherit
|
|
||||||
KillMode=process
|
|
||||||
|
|
||||||
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
|
|
||||||
# terminates cleanly.
|
|
||||||
KillSignal=SIGHUP
|
|
||||||
'';
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue