Skip to content

Commit

Permalink
switch-to-configuration: Better handling of socket-activated units (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ElvishJerricco authored Jan 4, 2025
2 parents b25a2b5 + bc1cfec commit 15be453
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 9 deletions.
15 changes: 10 additions & 5 deletions nixos/doc/manual/development/unit-handling.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,16 @@ checks:
before the activation script is run. This behavior is different when the
service is socket-activated, as outlined in the following steps.

- The last thing that is taken into account is whether the unit is a service
and socket-activated. If `X-StopIfChanged` is **not** set, the service
is **restart**ed with the others. If it is set, both the service and the
socket are **stop**ped and the socket is **start**ed, leaving socket
activation to start the service when it's needed.
- The last thing that is taken into account is whether the unit is a
service and socket-activated. A correspondence between a
`.service` and its `.socket` unit is detected automatically, but
services can **opt out** of that detection by setting
`X-NotSocketActivated` to `yes` in their `[Service]`
section. Otherwise, if `X-StopIfChanged` is **not** set, the
service is **restart**ed with the others. If it is set, both the
service and the socket are **stop**ped and the socket is
**start**ed, leaving socket activation to start the service when
it's needed.

## Sysinit reactivation {#sec-sysinit-reactivation}

Expand Down
3 changes: 3 additions & 0 deletions nixos/lib/systemd-lib.nix
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@ in rec {
'' else "")
+ optionalString (def ? stopIfChanged && !def.stopIfChanged) ''
X-StopIfChanged=false
''
+ optionalString (def ? notSocketActivated && def.notSocketActivated) ''
X-NotSocketActivated=true
'' + attrsToSection def.serviceConfig);
};

Expand Down
12 changes: 12 additions & 0 deletions nixos/lib/systemd-unit-options.nix
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,18 @@ in rec {
'';
};

notSocketActivated = mkOption {
type = types.bool;
default = false;
description = ''
If set, a changed unit is never assumed to be
socket-activated on configuration switch, even if
it might have associated socket units. Instead, the unit
will be restarted (or stopped/started) as if it had no
associated sockets.
'';
};

startAt = mkOption {
type = with types; either str (listOf str);
default = [];
Expand Down
8 changes: 4 additions & 4 deletions nixos/modules/services/hardware/udev.nix
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,10 @@ in
fi
'';

systemd.services.systemd-udevd =
{ restartTriggers = [ config.environment.etc."udev/rules.d".source ];
};

systemd.services.systemd-udevd = {
restartTriggers = [ config.environment.etc."udev/rules.d".source ];
notSocketActivated = true;
};
};

imports = [
Expand Down
7 changes: 7 additions & 0 deletions nixos/modules/system/activation/switch-to-configuration.pl
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,13 @@ sub handle_modified_unit { ## no critic(Subroutines::ProhibitManyArgs, Subroutin
}
}

if (parse_systemd_bool(\%new_unit_info, "Service", "X-NotSocketActivated", 0)) {
# If the unit explicitly opts out of socket
# activation, restart it as if it weren't (but do
# restart its sockets, that's fine):
$socket_activated = 0;
}

# If the unit is not socket-activated, record
# that this unit needs to be started below.
# We write this to a file to ensure that the
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/system/boot/networkd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2901,6 +2901,7 @@ let
config.environment.etc."systemd/networkd.conf".source
];
aliases = [ "dbus-org.freedesktop.network1.service" ];
notSocketActivated = true;
};

networking.iproute2 = mkIf (cfg.config.addRouteTablesToIPRoute2 && cfg.config.routeTables != { }) {
Expand Down
10 changes: 10 additions & 0 deletions pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ const RELOAD_LIST_FILE: &str = "/run/nixos/reload-list";
// `stopIfChanged = true` is ignored, switch-to-configuration will handle `restartIfChanged =
// false` and `reloadIfChanged = true`. This is the same as specifying a restart trigger in the
// NixOS module.
// In addition, switch-to-configuration will handle notSocketActivated=true to disable treatment
// of units as "socket-activated" even though they might have any associated sockets.
//
// The reload file asks this program to reload a unit. This is the same as specifying a reload
// trigger in the NixOS module and can be ignored if the unit is restarted in this activation.
Expand Down Expand Up @@ -613,6 +615,8 @@ fn handle_modified_unit(
} else {
// If this unit is socket-activated, then stop the socket unit(s) as well, and
// restart the socket(s) instead of the service.
// We count as "socket-activated" any unit that doesn't declare itself not so
// via X-NotSocketActivated, that has any associated .socket units.
let mut socket_activated = false;
if unit.ends_with(".service") {
let mut sockets = if let Some(Some(Some(sockets))) = new_unit_info.map(|info| {
Expand Down Expand Up @@ -663,6 +667,12 @@ fn handle_modified_unit(
}
}
}
if parse_systemd_bool(new_unit_info, "Service", "X-NotSocketActivated", false) {
// If the unit explicitly opts out of socket
// activation, restart it as if it weren't (but do
// restart its sockets, that's fine):
socket_activated = false;
}

// If the unit is not socket-activated, record that this unit needs to be started
// below. We write this to a file to ensure that the service gets restarted if
Expand Down

0 comments on commit 15be453

Please sign in to comment.