summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorMichael Weiss <dev.primeos@gmail.com>2021-11-27 17:14:55 +0100
committerMichael Weiss <dev.primeos@gmail.com>2021-11-27 17:22:22 +0100
commit1cfecb636b14a88174d914cd0522b78ff3bf9f82 (patch)
tree68f3b11a71e557e2c23e452344c929ec63ae01ab /nixos
parent549025bbedac9080a513507a263a6c06326be62c (diff)
downloadnixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.tar
nixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.tar.gz
nixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.tar.bz2
nixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.tar.lz
nixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.tar.xz
nixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.tar.zst
nixpkgs-1cfecb636b14a88174d914cd0522b78ff3bf9f82.zip
Revert "Merge pull request #141192 from helsinki-systems/feat/improved-socket-handling2"
This reverts commit 57961d2b838cc31fa4ce89641b6a8db544a8471a, reversing
changes made to b04f913afce4419f6b777fd64ac52315dbef3aaf.
(I.e. this reverts PR #141192.)

While well-intended, this change does unfortunately introduce very
serious regressions that are especially disruptive/noticeable on desktop
systems (e.g. users of Sway will loose their graphical session when
running "nixos-rebuild switch").

Therefore, this change has to be reverted ASAP instead of trying to fix
it in "production".
Note: An updated version should be extensively discussed, reviewed, and
tested before re-landing this change as an earlier version also had to
be reverted for the exact same issues [0].

Fix: #146727

[0]: https://github.com/NixOS/nixpkgs/pull/73871#issuecomment-559783752
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2111.section.xml9
-rw-r--r--nixos/doc/manual/release-notes/rl-2111.section.md2
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl274
-rw-r--r--nixos/modules/system/activation/top-level.nix7
-rw-r--r--nixos/tests/switch-test.nix386
5 files changed, 87 insertions, 591 deletions
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
index f0e39471ece..eb620a3e3ed 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
@@ -1862,15 +1862,6 @@ Superuser created successfully.
       </listitem>
       <listitem>
         <para>
-          Changing systemd <literal>.socket</literal> units now restarts
-          them and stops the service that is activated by them.
-          Additionally, services with
-          <literal>stopOnChange = false</literal> don’t break anymore
-          when they are socket-activated.
-        </para>
-      </listitem>
-      <listitem>
-        <para>
           The <literal>virtualisation.libvirtd</literal> module has been
           refactored and updated with new options:
         </para>
diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md
index 3bdda82c026..c0151479903 100644
--- a/nixos/doc/manual/release-notes/rl-2111.section.md
+++ b/nixos/doc/manual/release-notes/rl-2111.section.md
@@ -520,8 +520,6 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - `networking.sits` now supports Foo-over-UDP encapsulation.
 
-- Changing systemd `.socket` units now restarts them and stops the service that is activated by them. Additionally, services with `stopOnChange = false` don't break anymore when they are socket-activated.
-
 -  The `virtualisation.libvirtd` module has been refactored and updated with new options:
     - `virtualisation.libvirtd.qemu*` options (e.g.: `virtualisation.libvirtd.qemuRunAsRoot`) were moved to [`virtualisation.libvirtd.qemu`](options.html#opt-virtualisation.libvirtd.qemu) submodule,
     - software TPM1/TPM2 support (e.g.: Windows 11 guests) ([`virtualisation.libvirtd.qemu.swtpm`](options.html#opt-virtualisation.libvirtd.qemu.swtpm)),
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index e105502cf3a..053496441d8 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -11,6 +11,7 @@ use Cwd 'abs_path';
 
 my $out = "@out@";
 
+# FIXME: maybe we should use /proc/1/exe to get the current systemd.
 my $curSystemd = abs_path("/run/current-system/sw/bin");
 
 # To be robust against interruption, record what units need to be started etc.
@@ -18,16 +19,13 @@ my $startListFile = "/run/nixos/start-list";
 my $restartListFile = "/run/nixos/restart-list";
 my $reloadListFile = "/run/nixos/reload-list";
 
-# Parse restart/reload requests by the activation script.
-# Activation scripts may write newline-separated units to this
-# file and switch-to-configuration will handle them. While
-# `stopIfChanged = true` is ignored, switch-to-configuration will
-# handle `restartIfChanged = false` and `reloadIfChanged = true`.
-# This also works for socket-activated units.
+# Parse restart/reload requests by the activation script
 my $restartByActivationFile = "/run/nixos/activation-restart-list";
+my $reloadByActivationFile = "/run/nixos/activation-reload-list";
 my $dryRestartByActivationFile = "/run/nixos/dry-activation-restart-list";
+my $dryReloadByActivationFile = "/run/nixos/dry-activation-reload-list";
 
-make_path("/run/nixos", { mode => oct(755) });
+make_path("/run/nixos", { mode => 0755 });
 
 my $action = shift @ARGV;
 
@@ -149,92 +147,6 @@ sub fingerprintUnit {
     return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
 }
 
-sub handleModifiedUnit {
-    my ($unit, $baseName, $newUnitFile, $activePrev, $unitsToStop, $unitsToStart, $unitsToReload, $unitsToRestart, $unitsToSkip) = @_;
-
-    if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.slice$/ || $unit =~ /\.path$/) {
-        # Do nothing.  These cannot be restarted directly.
-        # Slices and Paths don't have to be restarted since
-        # properties (resource limits and inotify watches)
-        # seem to get applied on daemon-reload.
-    } elsif ($unit =~ /\.mount$/) {
-        # Reload the changed mount unit to force a remount.
-        $unitsToReload->{$unit} = 1;
-        recordUnit($reloadListFile, $unit);
-    } else {
-        my $unitInfo = parseUnit($newUnitFile);
-        if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
-            $unitsToReload->{$unit} = 1;
-            recordUnit($reloadListFile, $unit);
-        }
-        elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
-            $unitsToSkip->{$unit} = 1;
-        } else {
-            # If this unit is socket-activated, then stop it instead
-            # of restarting it to make sure the new version of it is
-            # socket-activated.
-            my $socketActivated = 0;
-            if ($unit =~ /\.service$/) {
-                my @sockets = split / /, ($unitInfo->{Sockets} // "");
-                if (scalar @sockets == 0) {
-                    @sockets = ("$baseName.socket");
-                }
-                foreach my $socket (@sockets) {
-                    if (-e "$out/etc/systemd/system/$socket") {
-                        $socketActivated = 1;
-                        $unitsToStop->{$unit} = 1;
-                        # If the socket was not running previously,
-                        # start it now.
-                        if (not defined $activePrev->{$socket}) {
-                            $unitsToStart->{$socket} = 1;
-                        }
-                    }
-                }
-            }
-
-            # Don't do the rest of this for socket-activated units
-            # because we handled these above where we stop the unit.
-            # Since only services can be socket-activated, the
-            # following condition always evaluates to `true` for
-            # non-service units.
-            if ($socketActivated) {
-                return;
-            }
-
-            # If we are restarting a socket, also stop the corresponding
-            # service. This is required because restarting a socket
-            # when the service is already activated fails.
-            if ($unit =~ /\.socket$/) {
-                my $service = $unitInfo->{Service} // "";
-                if ($service eq "") {
-                    $service = "$baseName.service";
-                }
-                if (defined $activePrev->{$service}) {
-                    $unitsToStop->{$service} = 1;
-                }
-                $unitsToRestart->{$unit} = 1;
-                recordUnit($restartListFile, $unit);
-            } else {
-                # Always restart non-services instead of stopping and starting them
-                # because it doesn't make sense to stop them with a config from
-                # the old evaluation.
-                if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes") || $unit !~ /\.service$/) {
-                    # This unit should be restarted instead of
-                    # stopped and started.
-                    $unitsToRestart->{$unit} = 1;
-                    recordUnit($restartListFile, $unit);
-                } else {
-                    # We write to a file to ensure that the
-                    # service gets restarted if we're interrupted.
-                    $unitsToStart->{$unit} = 1;
-                    recordUnit($startListFile, $unit);
-                    $unitsToStop->{$unit} = 1;
-                }
-            }
-        }
-    }
-}
-
 # Figure out what units need to be stopped, started, restarted or reloaded.
 my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
 
@@ -307,7 +219,65 @@ while (my ($unit, $state) = each %{$activePrev}) {
         }
 
         elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
-            handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToSkip);
+            if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") {
+                # Do nothing.  These cannot be restarted directly.
+            } elsif ($unit =~ /\.mount$/) {
+                # Reload the changed mount unit to force a remount.
+                $unitsToReload{$unit} = 1;
+                recordUnit($reloadListFile, $unit);
+            } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
+                # FIXME: do something?
+            } else {
+                my $unitInfo = parseUnit($newUnitFile);
+                if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
+                    $unitsToReload{$unit} = 1;
+                    recordUnit($reloadListFile, $unit);
+                }
+                elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
+                    $unitsToSkip{$unit} = 1;
+                } else {
+                    if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {
+                        # This unit should be restarted instead of
+                        # stopped and started.
+                        $unitsToRestart{$unit} = 1;
+                        recordUnit($restartListFile, $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.
+                        my $socketActivated = 0;
+                        if ($unit =~ /\.service$/) {
+                            my @sockets = split / /, ($unitInfo->{Sockets} // "");
+                            if (scalar @sockets == 0) {
+                                @sockets = ("$baseName.socket");
+                            }
+                            foreach my $socket (@sockets) {
+                                if (defined $activePrev->{$socket}) {
+                                    $unitsToStop{$socket} = 1;
+                                    # Only restart sockets that actually
+                                    # exist in new configuration:
+                                    if (-e "$out/etc/systemd/system/$socket") {
+                                        $unitsToStart{$socket} = 1;
+                                        recordUnit($startListFile, $socket);
+                                        $socketActivated = 1;
+                                    }
+                                }
+                            }
+                        }
+
+                        # 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 we're interrupted.
+                        if (!$socketActivated) {
+                            $unitsToStart{$unit} = 1;
+                            recordUnit($startListFile, $unit);
+                        }
+
+                        $unitsToStop{$unit} = 1;
+                    }
+                }
+            }
         }
     }
 }
@@ -392,6 +362,8 @@ sub filterUnits {
 }
 
 my @unitsToStopFiltered = filterUnits(\%unitsToStop);
+my @unitsToStartFiltered = filterUnits(\%unitsToStart);
+
 
 # Show dry-run actions.
 if ($action eq "dry-activate") {
@@ -403,44 +375,21 @@ if ($action eq "dry-activate") {
     print STDERR "would activate the configuration...\n";
     system("$out/dry-activate", "$out");
 
-    # Handle the activation script requesting the restart or reload of a unit.
-    my %unitsToAlsoStop;
-    my %unitsToAlsoSkip;
-    foreach (split('\n', read_file($dryRestartByActivationFile, err_mode => 'quiet') // "")) {
-        my $unit = $_;
-        my $baseUnit = $unit;
-        my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-
-        # Detect template instances.
-        if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
-          $baseUnit = "$1\@.$2";
-          $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-        }
-
-        my $baseName = $baseUnit;
-        $baseName =~ s/\.[a-z]*$//;
+    $unitsToRestart{$_} = 1 foreach
+        split('\n', read_file($dryRestartByActivationFile, err_mode => 'quiet') // "");
 
-        handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToAlsoStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToAlsoSkip);
-    }
-    unlink($dryRestartByActivationFile);
-
-    my @unitsToAlsoStopFiltered = filterUnits(\%unitsToAlsoStop);
-    if (scalar(keys %unitsToAlsoStop) > 0) {
-        print STDERR "would stop the following units as well: ", join(", ", @unitsToAlsoStopFiltered), "\n"
-            if scalar @unitsToAlsoStopFiltered;
-    }
-
-    print STDERR "would NOT restart the following changed units as well: ", join(", ", sort(keys %unitsToAlsoSkip)), "\n"
-        if scalar(keys %unitsToAlsoSkip) > 0;
+    $unitsToReload{$_} = 1 foreach
+        split('\n', read_file($dryReloadByActivationFile, err_mode => 'quiet') // "");
 
     print STDERR "would restart systemd\n" if $restartSystemd;
-    print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n"
-        if scalar(keys %unitsToReload) > 0;
     print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"
         if scalar(keys %unitsToRestart) > 0;
-    my @unitsToStartFiltered = filterUnits(\%unitsToStart);
     print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n"
         if scalar @unitsToStartFiltered;
+    print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n"
+        if scalar(keys %unitsToReload) > 0;
+    unlink($dryRestartByActivationFile);
+    unlink($dryReloadByActivationFile);
     exit 0;
 }
 
@@ -451,7 +400,7 @@ if (scalar (keys %unitsToStop) > 0) {
     print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n"
         if scalar @unitsToStopFiltered;
     # Use current version of systemctl binary before daemon is reexeced.
-    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop));
+    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors?
 }
 
 print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
@@ -465,38 +414,12 @@ system("$out/activate", "$out") == 0 or $res = 2;
 
 # Handle the activation script requesting the restart or reload of a unit.
 # We can only restart and reload (not stop/start) because the units to be
-# stopped are already stopped before the activation script is run. We do however
-# make an exception for services that are socket-activated and that have to be stopped
-# instead of being restarted.
-my %unitsToAlsoStop;
-my %unitsToAlsoSkip;
-foreach (split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // "")) {
-    my $unit = $_;
-    my $baseUnit = $unit;
-    my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-
-    # Detect template instances.
-    if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
-      $baseUnit = "$1\@.$2";
-      $newUnitFile = "$out/etc/systemd/system/$baseUnit";
-    }
-
-    my $baseName = $baseUnit;
-    $baseName =~ s/\.[a-z]*$//;
-
-    handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToAlsoStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, %unitsToAlsoSkip);
-}
-unlink($restartByActivationFile);
-
-my @unitsToAlsoStopFiltered = filterUnits(\%unitsToAlsoStop);
-if (scalar(keys %unitsToAlsoStop) > 0) {
-    print STDERR "stopping the following units as well: ", join(", ", @unitsToAlsoStopFiltered), "\n"
-        if scalar @unitsToAlsoStopFiltered;
-    system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToAlsoStop));
-}
+# stopped are already stopped before the activation script is run.
+$unitsToRestart{$_} = 1 foreach
+    split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // "");
 
-print STDERR "NOT restarting the following changed units as well: ", join(", ", sort(keys %unitsToAlsoSkip)), "\n"
-    if scalar(keys %unitsToAlsoSkip) > 0;
+$unitsToReload{$_} = 1 foreach
+    split('\n', read_file($reloadByActivationFile, err_mode => 'quiet') // "");
 
 # Restart systemd if necessary. Note that this is done using the
 # current version of systemd, just in case the new one has trouble
@@ -537,40 +460,14 @@ if (scalar(keys %unitsToReload) > 0) {
     print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n";
     system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4;
     unlink($reloadListFile);
+    unlink($reloadByActivationFile);
 }
 
 # Restart changed services (those that have to be restarted rather
 # than stopped and started).
 if (scalar(keys %unitsToRestart) > 0) {
     print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n";
-
-    # We split the units to be restarted into sockets and non-sockets.
-    # This is because restarting sockets may fail which is not bad by
-    # itself but which will prevent changes on the sockets. We usually
-    # restart the socket and stop the service before that. Restarting
-    # the socket will fail however when the service was re-activated
-    # in the meantime. There is no proper way to prevent that from happening.
-    my @unitsWithErrorHandling = grep { $_ !~ /\.socket$/ } sort(keys %unitsToRestart);
-    my @unitsWithoutErrorHandling = grep { $_ =~ /\.socket$/ } sort(keys %unitsToRestart);
-
-    if (scalar(@unitsWithErrorHandling) > 0) {
-        system("@systemd@/bin/systemctl", "restart", "--", @unitsWithErrorHandling) == 0 or $res = 4;
-    }
-    if (scalar(@unitsWithoutErrorHandling) > 0) {
-        # Don't print warnings from systemctl
-        no warnings 'once';
-        open(OLDERR, ">&", \*STDERR);
-        close(STDERR);
-
-        my $ret = system("@systemd@/bin/systemctl", "restart", "--", @unitsWithoutErrorHandling);
-
-        # Print stderr again
-        open(STDERR, ">&OLDERR");
-
-        if ($ret ne 0) {
-            print STDERR "warning: some sockets failed to restart. Please check your journal (journalctl -eb) and act accordingly.\n";
-        }
-    }
+    system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4;
     unlink($restartListFile);
     unlink($restartByActivationFile);
 }
@@ -581,7 +478,6 @@ if (scalar(keys %unitsToRestart) > 0) {
 # that are symlinks to other units.  We shouldn't start both at the
 # same time because we'll get a "Failed to add path to set" error from
 # systemd.
-my @unitsToStartFiltered = filterUnits(\%unitsToStart);
 print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n"
     if scalar @unitsToStartFiltered;
 system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4;
@@ -589,7 +485,7 @@ unlink($startListFile);
 
 
 # Print failed and new units.
-my (@failed, @new);
+my (@failed, @new, @restarting);
 my $activeNew = getActiveUnits;
 while (my ($unit, $state) = each %{$activeNew}) {
     if ($state->{state} eq "failed") {
@@ -605,9 +501,7 @@ while (my ($unit, $state) = each %{$activeNew}) {
             push @failed, $unit;
         }
     }
-    # Ignore scopes since they are not managed by this script but rather
-    # created and managed by third-party services via the systemd dbus API.
-    elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit} && $unit !~ /\.scope$/) {
+    elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit}) {
         push @new, $unit;
     }
 }
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index 68da910d29c..026fd1791d3 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -84,13 +84,6 @@ let
       export localeArchive="${config.i18n.glibcLocales}/lib/locale/locale-archive"
       substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration
       chmod +x $out/bin/switch-to-configuration
-      ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) ''
-        if ! output=$($perl/bin/perl -c $out/bin/switch-to-configuration 2>&1); then
-          echo "switch-to-configuration syntax is not valid:"
-          echo "$output"
-          exit 1
-        fi
-      ''}
 
       echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies
 
diff --git a/nixos/tests/switch-test.nix b/nixos/tests/switch-test.nix
index 7ea07a390b8..78adf7ffa7d 100644
--- a/nixos/tests/switch-test.nix
+++ b/nixos/tests/switch-test.nix
@@ -7,224 +7,15 @@ import ./make-test-python.nix ({ pkgs, ...} : {
   };
 
   nodes = {
-    machine = { config, pkgs, lib, ... }: {
-      environment.systemPackages = [ pkgs.socat ]; # for the socket activation stuff
+    machine = { ... }: {
       users.mutableUsers = false;
-
-      specialisation = {
-        # A system with a simple socket-activated unit
-        simple-socket.configuration = {
-          systemd.services.socket-activated.serviceConfig = {
-            ExecStart = pkgs.writeScript "socket-test.py" /* python */ ''
-              #!${pkgs.python3}/bin/python3
-
-              from socketserver import TCPServer, StreamRequestHandler
-              import socket
-
-              class Handler(StreamRequestHandler):
-                  def handle(self):
-                      self.wfile.write("hello".encode("utf-8"))
-
-              class Server(TCPServer):
-                  def __init__(self, server_address, handler_cls):
-                      # Invoke base but omit bind/listen steps (performed by systemd activation!)
-                      TCPServer.__init__(
-                          self, server_address, handler_cls, bind_and_activate=False)
-                      # Override socket
-                      self.socket = socket.fromfd(3, self.address_family, self.socket_type)
-
-              if __name__ == "__main__":
-                  server = Server(("localhost", 1234), Handler)
-                  server.serve_forever()
-            '';
-          };
-          systemd.sockets.socket-activated = {
-            wantedBy = [ "sockets.target" ];
-            listenStreams = [ "/run/test.sock" ];
-            socketConfig.SocketMode = lib.mkDefault "0777";
-          };
-        };
-
-        # The same system but the socket is modified
-        modified-socket.configuration = {
-          imports = [ config.specialisation.simple-socket.configuration ];
-          systemd.sockets.socket-activated.socketConfig.SocketMode = "0666";
-        };
-
-        # The same system but the service is modified
-        modified-service.configuration = {
-          imports = [ config.specialisation.simple-socket.configuration ];
-          systemd.services.socket-activated.serviceConfig.X-Test = "test";
-        };
-
-        # The same system but both service and socket are modified
-        modified-service-and-socket.configuration = {
-          imports = [ config.specialisation.simple-socket.configuration ];
-          systemd.services.socket-activated.serviceConfig.X-Test = "some_value";
-          systemd.sockets.socket-activated.socketConfig.SocketMode = "0444";
-        };
-
-        # A system with a socket-activated service and some simple services
-        service-and-socket.configuration = {
-          imports = [ config.specialisation.simple-socket.configuration ];
-          systemd.services.simple-service = {
-            wantedBy = [ "multi-user.target" ];
-            serviceConfig = {
-              Type = "oneshot";
-              RemainAfterExit = true;
-              ExecStart = "${pkgs.coreutils}/bin/true";
-            };
-          };
-
-          systemd.services.simple-restart-service = {
-            stopIfChanged = false;
-            wantedBy = [ "multi-user.target" ];
-            serviceConfig = {
-              Type = "oneshot";
-              RemainAfterExit = true;
-              ExecStart = "${pkgs.coreutils}/bin/true";
-            };
-          };
-
-          systemd.services.simple-reload-service = {
-            reloadIfChanged = true;
-            wantedBy = [ "multi-user.target" ];
-            serviceConfig = {
-              Type = "oneshot";
-              RemainAfterExit = true;
-              ExecStart = "${pkgs.coreutils}/bin/true";
-              ExecReload = "${pkgs.coreutils}/bin/true";
-            };
-          };
-
-          systemd.services.no-restart-service = {
-            restartIfChanged = false;
-            wantedBy = [ "multi-user.target" ];
-            serviceConfig = {
-              Type = "oneshot";
-              RemainAfterExit = true;
-              ExecStart = "${pkgs.coreutils}/bin/true";
-            };
-          };
-        };
-
-        # The same system but with an activation script that restarts all services
-        restart-and-reload-by-activation-script.configuration = {
-          imports = [ config.specialisation.service-and-socket.configuration ];
-          system.activationScripts.restart-and-reload-test = {
-            supportsDryActivation = true;
-            deps = [];
-            text = ''
-              if [ "$NIXOS_ACTION" = dry-activate ]; then
-                f=/run/nixos/dry-activation-restart-list
-              else
-                f=/run/nixos/activation-restart-list
-              fi
-              cat <<EOF >> "$f"
-              simple-service.service
-              simple-restart-service.service
-              simple-reload-service.service
-              no-restart-service.service
-              socket-activated.service
-              EOF
-            '';
-          };
-        };
-
-        # A system with a timer
-        with-timer.configuration = {
-          systemd.timers.test-timer = {
-            wantedBy = [ "timers.target" ];
-            timerConfig.OnCalendar = "@1395716396"; # chosen by fair dice roll
-          };
-          systemd.services.test-timer = {
-            serviceConfig = {
-              Type = "oneshot";
-              ExecStart = "${pkgs.coreutils}/bin/true";
-            };
-          };
-        };
-
-        # The same system but with another time
-        with-timer-modified.configuration = {
-          imports = [ config.specialisation.with-timer.configuration ];
-          systemd.timers.test-timer.timerConfig.OnCalendar = lib.mkForce "Fri 2012-11-23 16:00:00";
-        };
-
-        # A system with a systemd mount
-        with-mount.configuration = {
-          systemd.mounts = [
-            {
-              description = "Testmount";
-              what = "tmpfs";
-              type = "tmpfs";
-              where = "/testmount";
-              options = "size=1M";
-              wantedBy = [ "local-fs.target" ];
-            }
-          ];
-        };
-
-        # The same system but with another time
-        with-mount-modified.configuration = {
-          systemd.mounts = [
-            {
-              description = "Testmount";
-              what = "tmpfs";
-              type = "tmpfs";
-              where = "/testmount";
-              options = "size=10M";
-              wantedBy = [ "local-fs.target" ];
-            }
-          ];
-        };
-
-        # A system with a path unit
-        with-path.configuration = {
-          systemd.paths.test-watch = {
-            wantedBy = [ "paths.target" ];
-            pathConfig.PathExists = "/testpath";
-          };
-          systemd.services.test-watch = {
-            serviceConfig = {
-              Type = "oneshot";
-              ExecStart = "${pkgs.coreutils}/bin/touch /testpath-modified";
-            };
-          };
-        };
-
-        # The same system but watching another file
-        with-path-modified.configuration = {
-          imports = [ config.specialisation.with-path.configuration ];
-          systemd.paths.test-watch.pathConfig.PathExists = lib.mkForce "/testpath2";
-        };
-
-        # A system with a slice
-        with-slice.configuration = {
-          systemd.slices.testslice.sliceConfig.MemoryMax = "1"; # don't allow memory allocation
-          systemd.services.testservice = {
-            serviceConfig = {
-              Type = "oneshot";
-              RemainAfterExit = true;
-              ExecStart = "${pkgs.coreutils}/bin/true";
-              Slice = "testslice.slice";
-            };
-          };
-        };
-
-        # The same system but the slice allows to allocate memory
-        with-slice-non-crashing.configuration = {
-          imports = [ config.specialisation.with-slice.configuration ];
-          systemd.slices.testslice.sliceConfig.MemoryMax = lib.mkForce null;
-        };
-      };
     };
     other = { ... }: {
       users.mutableUsers = true;
     };
   };
 
-  testScript = { nodes, ... }: let
+  testScript = {nodes, ...}: let
     originalSystem = nodes.machine.config.system.build.toplevel;
     otherSystem = nodes.other.config.system.build.toplevel;
 
@@ -236,183 +27,12 @@ import ./make-test-python.nix ({ pkgs, ...} : {
       set -o pipefail
       exec env -i "$@" | tee /dev/stderr
     '';
-  in /* python */ ''
-    def switch_to_specialisation(name, action="test"):
-        out = machine.succeed(f"${originalSystem}/specialisation/{name}/bin/switch-to-configuration {action} 2>&1")
-        assert_lacks(out, "switch-to-configuration line")  # Perl warnings
-        return out
-
-    def assert_contains(haystack, needle):
-        if needle not in haystack:
-            print("The haystack that will cause the following exception is:")
-            print("---")
-            print(haystack)
-            print("---")
-            raise Exception(f"Expected string '{needle}' was not found")
-
-    def assert_lacks(haystack, needle):
-        if needle in haystack:
-            print("The haystack that will cause the following exception is:")
-            print("---")
-            print(haystack, end="")
-            print("---")
-            raise Exception(f"Unexpected string '{needle}' was found")
-
-
+  in ''
     machine.succeed(
         "${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
     )
     machine.succeed(
         "${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
     )
-
-    with subtest("systemd sockets"):
-        machine.succeed("${originalSystem}/bin/switch-to-configuration test")
-
-        # Simple socket is created
-        out = switch_to_specialisation("simple-socket")
-        assert_lacks(out, "stopping the following units:")
-        # not checking for reload because dbus gets reloaded
-        assert_lacks(out, "restarting the following units:")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_contains(out, "the following new units were started: socket-activated.socket\n")
-        assert_lacks(out, "as well:")
-        machine.succeed("[ $(stat -c%a /run/test.sock) = 777 ]")
-
-        # Changing the socket restarts it
-        out = switch_to_specialisation("modified-socket")
-        assert_lacks(out, "stopping the following units:")
-        #assert_lacks(out, "reloading the following units:")
-        assert_contains(out, "restarting the following units: socket-activated.socket\n")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-        machine.succeed("[ $(stat -c%a /run/test.sock) = 666 ]")  # change was applied
-
-        # The unit is properly activated when the socket is accessed
-        if machine.succeed("socat - UNIX-CONNECT:/run/test.sock") != "hello":
-            raise Exception("Socket was not properly activated")
-
-        # Changing the socket restarts it and ignores the active service
-        out = switch_to_specialisation("simple-socket")
-        assert_contains(out, "stopping the following units: socket-activated.service\n")
-        assert_lacks(out, "reloading the following units:")
-        assert_contains(out, "restarting the following units: socket-activated.socket\n")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-        machine.succeed("[ $(stat -c%a /run/test.sock) = 777 ]")  # change was applied
-
-        # Changing the service does nothing when the service is not active
-        out = switch_to_specialisation("modified-service")
-        assert_lacks(out, "stopping the following units:")
-        assert_lacks(out, "reloading the following units:")
-        assert_lacks(out, "restarting the following units:")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-
-        # Activating the service and modifying it stops it but leaves the socket untouched
-        machine.succeed("socat - UNIX-CONNECT:/run/test.sock")
-        out = switch_to_specialisation("simple-socket")
-        assert_contains(out, "stopping the following units: socket-activated.service\n")
-        assert_lacks(out, "reloading the following units:")
-        assert_lacks(out, "restarting the following units:")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-
-        # Activating the service and both the service and the socket stops the service and restarts the socket
-        machine.succeed("socat - UNIX-CONNECT:/run/test.sock")
-        out = switch_to_specialisation("modified-service-and-socket")
-        assert_contains(out, "stopping the following units: socket-activated.service\n")
-        assert_lacks(out, "reloading the following units:")
-        assert_contains(out, "restarting the following units: socket-activated.socket\n")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-
-    with subtest("restart and reload by activation file"):
-        out = switch_to_specialisation("service-and-socket")
-        # Switch to a system where the example services get restarted
-        # by the activation script
-        out = switch_to_specialisation("restart-and-reload-by-activation-script")
-        assert_lacks(out, "stopping the following units:")
-        assert_contains(out, "stopping the following units as well: simple-service.service, socket-activated.service\n")
-        assert_contains(out, "reloading the following units: simple-reload-service.service\n")
-        assert_contains(out, "restarting the following units: simple-restart-service.service\n")
-        assert_contains(out, "\nstarting the following units: simple-service.service")
-
-        # The same, but in dry mode
-        switch_to_specialisation("service-and-socket")
-        out = switch_to_specialisation("restart-and-reload-by-activation-script", action="dry-activate")
-        assert_lacks(out, "would stop the following units:")
-        assert_contains(out, "would stop the following units as well: simple-service.service, socket-activated.service\n")
-        assert_contains(out, "would reload the following units: simple-reload-service.service\n")
-        assert_contains(out, "would restart the following units: simple-restart-service.service\n")
-        assert_contains(out, "\nwould start the following units: simple-service.service")
-
-    with subtest("mounts"):
-        switch_to_specialisation("with-mount")
-        out = machine.succeed("mount | grep 'on /testmount'")
-        assert_contains(out, "size=1024k")
-
-        out = switch_to_specialisation("with-mount-modified")
-        assert_lacks(out, "stopping the following units:")
-        assert_contains(out, "reloading the following units: testmount.mount\n")
-        assert_lacks(out, "restarting the following units:")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-        # It changed
-        out = machine.succeed("mount | grep 'on /testmount'")
-        assert_contains(out, "size=10240k")
-
-    with subtest("timers"):
-        switch_to_specialisation("with-timer")
-        out = machine.succeed("systemctl show test-timer.timer")
-        assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC")
-
-        out = switch_to_specialisation("with-timer-modified")
-        assert_lacks(out, "stopping the following units:")
-        assert_lacks(out, "reloading the following units:")
-        assert_contains(out, "restarting the following units: test-timer.timer\n")
-        assert_lacks(out, "\nstarting the following units:")
-        assert_lacks(out, "the following new units were started:")
-        assert_lacks(out, "as well:")
-        # It changed
-        out = machine.succeed("systemctl show test-timer.timer")
-        assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00")
-
-    with subtest("paths"):
-        switch_to_specialisation("with-path")
-        machine.fail("test -f /testpath-modified")
-
-        # touch the file, unit should be triggered
-        machine.succeed("touch /testpath")
-        machine.wait_until_succeeds("test -f /testpath-modified")
-
-        machine.succeed("rm /testpath")
-        machine.succeed("rm /testpath-modified")
-        switch_to_specialisation("with-path-modified")
-
-        machine.succeed("touch /testpath")
-        machine.fail("test -f /testpath-modified")
-        machine.succeed("touch /testpath2")
-        machine.wait_until_succeeds("test -f /testpath-modified")
-
-    # This test ensures that changes to slice configuration get applied.
-    # We test this by having a slice that allows no memory allocation at
-    # all and starting a service within it. If the service crashes, the slice
-    # is applied and if we modify the slice to allow memory allocation, the
-    # service should successfully start.
-    with subtest("slices"):
-        machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom")  # allow OOMing
-        out = switch_to_specialisation("with-slice")
-        machine.fail("systemctl start testservice.service")
-        out = switch_to_specialisation("with-slice-non-crashing")
-        machine.succeed("systemctl start testservice.service")
-        machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom")  # disallow OOMing
-
   '';
 })