about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-2003.xml6
-rw-r--r--nixos/lib/testing-python.nix15
-rw-r--r--nixos/lib/testing.nix5
-rw-r--r--nixos/modules/hardware/brightnessctl.nix31
-rw-r--r--nixos/modules/installer/cd-dvd/channel.nix4
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix3
-rw-r--r--nixos/modules/installer/tools/nixos-build-vms/build-vms.nix2
-rw-r--r--nixos/modules/installer/tools/nixos-enter.sh18
-rw-r--r--nixos/modules/misc/version.nix6
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/programs/sway.nix4
-rw-r--r--nixos/modules/rename.nix6
-rw-r--r--nixos/modules/services/audio/alsa.nix6
-rw-r--r--nixos/modules/services/databases/postgresql.nix33
-rw-r--r--nixos/modules/services/networking/iwd.nix7
-rw-r--r--nixos/modules/services/networking/knot.nix40
-rw-r--r--nixos/modules/services/networking/pppd.nix4
-rw-r--r--nixos/modules/services/web-apps/mattermost.nix16
-rw-r--r--nixos/modules/services/web-servers/caddy.nix18
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix1
-rw-r--r--nixos/modules/services/x11/unclutter.nix2
-rw-r--r--nixos/modules/services/x11/urxvtd.nix6
-rw-r--r--nixos/modules/system/boot/kernel.nix7
-rw-r--r--nixos/modules/tasks/filesystems.nix3
-rw-r--r--nixos/modules/virtualisation/docker-containers.nix11
-rw-r--r--nixos/release-combined.nix1
-rw-r--r--nixos/release.nix14
-rw-r--r--nixos/tests/all-tests.nix2
-rw-r--r--nixos/tests/docker-containers.nix27
-rw-r--r--nixos/tests/docker-tools.nix6
-rw-r--r--nixos/tests/firefox.nix6
-rw-r--r--nixos/tests/knot.nix15
-rw-r--r--nixos/tests/krb5/deprecated-config.nix6
-rw-r--r--nixos/tests/krb5/example-config.nix6
-rw-r--r--nixos/tests/nsd.nix52
-rw-r--r--nixos/tests/openarena.nix84
-rw-r--r--nixos/tests/plotinus.nix27
-rw-r--r--nixos/tests/solr.nix50
38 files changed, 327 insertions, 224 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2003.xml b/nixos/doc/manual/release-notes/rl-2003.xml
index caa0de3f05f9..31f08d9da341 100644
--- a/nixos/doc/manual/release-notes/rl-2003.xml
+++ b/nixos/doc/manual/release-notes/rl-2003.xml
@@ -625,6 +625,12 @@ auth required pam_succeed_if.so uid >= 1000 quiet
      to a fairly old snapshot  from the <package>gcc7</package>-branch.
     </para>
    </listitem>
+   <listitem>
+    <para>
+     The <citerefentry><refentrytitle>nixos-build-vms</refentrytitle><manvolnum>8</manvolnum>
+     </citerefentry>-script now uses the python test-driver.
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/lib/testing-python.nix b/nixos/lib/testing-python.nix
index a7f6d7926514..6663864f1e56 100644
--- a/nixos/lib/testing-python.nix
+++ b/nixos/lib/testing-python.nix
@@ -218,12 +218,12 @@ in rec {
       '';
 
       testScript = ''
-        startAll;
-        $client->waitForUnit("multi-user.target");
+        start_all()
+        client.wait_for_unit("multi-user.target")
         ${preBuild}
-        $client->succeed("env -i ${bash}/bin/bash ${buildrunner} /tmp/xchg/saved-env >&2");
+        client.succeed("env -i ${bash}/bin/bash ${buildrunner} /tmp/xchg/saved-env >&2")
         ${postBuild}
-        $client->succeed("sync"); # flush all data before pulling the plug
+        client.succeed("sync") # flush all data before pulling the plug
       '';
 
       vmRunCommand = writeText "vm-run" ''
@@ -263,9 +263,12 @@ in rec {
         { ... }:
         {
           inherit require;
+          imports = [
+            ../tests/common/auto.nix
+          ];
           virtualisation.memorySize = 1024;
           services.xserver.enable = true;
-          services.xserver.displayManager.auto.enable = true;
+          test-support.displayManager.auto.enable = true;
           services.xserver.displayManager.defaultSession = "none+icewm";
           services.xserver.windowManager.icewm.enable = true;
         };
@@ -274,7 +277,7 @@ in rec {
         machine = client;
         preBuild =
           ''
-            $client->waitForX;
+            client.wait_for_x()
           '';
       } // args);
 
diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix
index c82abd1f9900..7d6a5c0a2900 100644
--- a/nixos/lib/testing.nix
+++ b/nixos/lib/testing.nix
@@ -250,9 +250,12 @@ in rec {
         { ... }:
         {
           inherit require;
+          imports = [
+            ../tests/common/auto.nix
+          ];
           virtualisation.memorySize = 1024;
           services.xserver.enable = true;
-          services.xserver.displayManager.auto.enable = true;
+          test-support.displayManager.auto.enable = true;
           services.xserver.displayManager.defaultSession = "none+icewm";
           services.xserver.windowManager.icewm.enable = true;
         };
diff --git a/nixos/modules/hardware/brightnessctl.nix b/nixos/modules/hardware/brightnessctl.nix
deleted file mode 100644
index 2d54398d10df..000000000000
--- a/nixos/modules/hardware/brightnessctl.nix
+++ /dev/null
@@ -1,31 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-let
-  cfg = config.hardware.brightnessctl;
-in
-{
-
-  options = {
-
-    hardware.brightnessctl = {
-
-      enable = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Enable brightnessctl in userspace.
-          This will allow brightness control from users in the video group.
-        '';
-
-      };
-    };
-  };
-
-
-  config = mkIf cfg.enable {
-    services.udev.packages = with pkgs; [ brightnessctl ];
-    environment.systemPackages = with pkgs; [ brightnessctl ];
-  };
-
-}
diff --git a/nixos/modules/installer/cd-dvd/channel.nix b/nixos/modules/installer/cd-dvd/channel.nix
index ab5e7c0645f3..92164d65e533 100644
--- a/nixos/modules/installer/cd-dvd/channel.nix
+++ b/nixos/modules/installer/cd-dvd/channel.nix
@@ -21,7 +21,9 @@ let
       if [ ! -e $out/nixos/nixpkgs ]; then
         ln -s . $out/nixos/nixpkgs
       fi
-      echo -n ${config.system.nixos.revision} > $out/nixos/.git-revision
+      ${optionalString (config.system.nixos.revision != null) ''
+        echo -n ${config.system.nixos.revision} > $out/nixos/.git-revision
+      ''}
       echo -n ${config.system.nixos.versionSuffix} > $out/nixos/.version-suffix
       echo ${config.system.nixos.versionSuffix} | sed -e s/pre// > $out/nixos/svn-revision
     '';
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix
index e0b558dcb0d8..fa19daf13280 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix
@@ -44,6 +44,9 @@ with lib;
     pkgs.bvi # binary editor
     pkgs.joe
 
+    # Include some version control tools.
+    pkgs.git
+
     # Firefox for reading the manual.
     pkgs.firefox
 
diff --git a/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix b/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
index c1028a0ad7e9..90f0702f7173 100644
--- a/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
+++ b/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
@@ -5,7 +5,7 @@
 
 let nodes = import networkExpr; in
 
-with import ../../../../lib/testing.nix {
+with import ../../../../lib/testing-python.nix {
   inherit system;
   pkgs = import ../../../../.. { inherit system config; };
 };
diff --git a/nixos/modules/installer/tools/nixos-enter.sh b/nixos/modules/installer/tools/nixos-enter.sh
index 4680cd8ae95a..1fdd4627a902 100644
--- a/nixos/modules/installer/tools/nixos-enter.sh
+++ b/nixos/modules/installer/tools/nixos-enter.sh
@@ -60,15 +60,15 @@ chmod 0755 "$mountPoint/dev" "$mountPoint/sys"
 mount --rbind /dev "$mountPoint/dev"
 mount --rbind /sys "$mountPoint/sys"
 
-# If silent, write both stdout and stderr of activation script to /dev/null
-# otherwise, write both streams to stderr of this process
-if [ "$silent" -eq 0 ]; then
-    PIPE_TARGET="/dev/stderr"
-else
-    PIPE_TARGET="/dev/null"
-fi
+(
+    # If silent, write both stdout and stderr of activation script to /dev/null
+    # otherwise, write both streams to stderr of this process
+    if [ "$silent" -eq 1 ]; then
+        exec 2>/dev/null
+    fi
 
-# Run the activation script. Set $LOCALE_ARCHIVE to supress some Perl locale warnings.
-LOCALE_ARCHIVE="$system/sw/lib/locale/locale-archive" chroot "$mountPoint" "$system/activate" >>$PIPE_TARGET 2>&1 || true
+    # Run the activation script. Set $LOCALE_ARCHIVE to supress some Perl locale warnings.
+    LOCALE_ARCHIVE="$system/sw/lib/locale/locale-archive" chroot "$mountPoint" "$system/activate" 1>&2 || true
+)
 
 exec chroot "$mountPoint" "${command[@]}"
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index c394ff592f49..9557def622d8 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -4,10 +4,6 @@ with lib;
 
 let
   cfg = config.system.nixos;
-
-  gitRepo      = "${toString pkgs.path}/.git";
-  gitRepoValid = lib.pathIsGitRepo gitRepo;
-  gitCommitId  = lib.substring 0 7 (commitIdFromGitRepo gitRepo);
 in
 
 {
@@ -98,8 +94,6 @@ in
       # These defaults are set here rather than up there so that
       # changing them would not rebuild the manual
       version = mkDefault (cfg.release + cfg.versionSuffix);
-      revision      = mkIf gitRepoValid (mkDefault            gitCommitId);
-      versionSuffix = mkIf gitRepoValid (mkDefault (".git." + gitCommitId));
     };
 
     # Generate /etc/os-release.  See
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 6b032f64bdb1..f7e4ee6cd1ed 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -41,7 +41,6 @@
   ./hardware/acpilight.nix
   ./hardware/all-firmware.nix
   ./hardware/bladeRF.nix
-  ./hardware/brightnessctl.nix
   ./hardware/brillo.nix
   ./hardware/ckb-next.nix
   ./hardware/cpu/amd-microcode.nix
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index 7e646f8737d6..364debddb0f1 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -88,10 +88,10 @@ in {
       default = with pkgs; [
         swaylock swayidle
         xwayland alacritty dmenu
-        rxvt_unicode # For backward compatibility (old default terminal)
+        rxvt-unicode # For backward compatibility (old default terminal)
       ];
       defaultText = literalExample ''
-        with pkgs; [ swaylock swayidle xwayland rxvt_unicode dmenu ];
+        with pkgs; [ swaylock swayidle xwayland rxvt-unicode dmenu ];
       '';
       example = literalExample ''
         with pkgs; [
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 3b1b1b8bb55c..2cc6c46e3581 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -42,6 +42,12 @@ with lib;
       instead, or any other display manager in NixOS as they all support auto-login.
     '')
     (mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead")
+    (mkRemovedOptionModule ["hardware" "brightnessctl" ] ''
+      The brightnessctl module was removed because newer versions of
+      brightnessctl don't require the udev rules anymore (they can use the
+      systemd-logind API). Instead of using the module you can now
+      simply add the brightnessctl package to environment.systemPackages.
+    '')
 
     # Do NOT add any option renames here, see top of the file
   ];
diff --git a/nixos/modules/services/audio/alsa.nix b/nixos/modules/services/audio/alsa.nix
index 990398e65463..3fe76a165401 100644
--- a/nixos/modules/services/audio/alsa.nix
+++ b/nixos/modules/services/audio/alsa.nix
@@ -91,11 +91,7 @@ in
     environment.systemPackages = [ alsaUtils ];
 
     environment.etc = mkIf (!pulseaudioEnabled && config.sound.extraConfig != "")
-      [
-        { source = pkgs.writeText "asound.conf" config.sound.extraConfig;
-          target = "asound.conf";
-        }
-      ];
+      { "asound.conf".text = config.sound.extraConfig; };
 
     # ALSA provides a udev rule for restoring volume settings.
     services.udev.packages = [ alsaUtils ];
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index c8fdd89d0d8f..284e2878d64e 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -20,7 +20,9 @@ let
       listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}'
       port = ${toString cfg.port}
       ${cfg.extraConfig}
-    '';
+    ''; 
+
+  groupAccessAvailable = versionAtLeast postgresql.version "11.0";
 
 in
 
@@ -88,6 +90,16 @@ in
         '';
       };
 
+      initdbArgs = mkOption {
+        type = with types; listOf str;
+        default = [];
+        example = [ "--data-checksums" "--allow-group-access" ];
+        description = ''
+          Additional arguments passed to <literal>initdb</literal> during data dir
+          initialisation.
+        '';
+      };
+
       initialScript = mkOption {
         type = types.nullOr types.path;
         default = null;
@@ -220,7 +232,7 @@ in
 
   ###### implementation
 
-  config = mkIf config.services.postgresql.enable {
+  config = mkIf cfg.enable {
 
     services.postgresql.package =
       # Note: when changing the default, make it conditional on
@@ -232,8 +244,9 @@ in
             else throw "postgresql_9_4 was removed, please upgrade your postgresql version.");
 
     services.postgresql.dataDir =
-      mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}"
-                 else "/var/db/postgresql");
+      mkDefault (if versionAtLeast config.system.stateVersion "17.09"
+                  then "/var/lib/postgresql/${cfg.package.psqlSchema}"
+                  else "/var/db/postgresql");
 
     services.postgresql.authentication = mkAfter
       ''
@@ -284,7 +297,7 @@ in
           ''
             # Initialise the database.
             if ! test -e ${cfg.dataDir}/PG_VERSION; then
-              initdb -U ${cfg.superUser}
+              initdb -U ${cfg.superUser} ${concatStringsSep " " cfg.initdbArgs}
               # See postStart!
               touch "${cfg.dataDir}/.first_startup"
             fi
@@ -293,8 +306,12 @@ in
               ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \
                 "${cfg.dataDir}/recovery.conf"
             ''}
+            ${optionalString (!groupAccessAvailable) ''
+              # postgresql pre 11.0 doesn't start if state directory mode is group accessible
+              chmod 0700 "${cfg.dataDir}"
+            ''}
 
-             exec postgres
+            exec postgres
           '';
 
         serviceConfig =
@@ -303,7 +320,7 @@ in
             Group = "postgres";
             PermissionsStartOnly = true;
             RuntimeDirectory = "postgresql";
-            Type = if lib.versionAtLeast cfg.package.version "9.6"
+            Type = if versionAtLeast cfg.package.version "9.6"
                    then "notify"
                    else "simple";
 
@@ -352,5 +369,5 @@ in
   };
 
   meta.doc = ./postgresql.xml;
-  meta.maintainers = with lib.maintainers; [ thoughtpolice ];
+  meta.maintainers = with lib.maintainers; [ thoughtpolice danbst ];
 }
diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix
index 839fa48d9a42..6be67a8b96f4 100644
--- a/nixos/modules/services/networking/iwd.nix
+++ b/nixos/modules/services/networking/iwd.nix
@@ -23,12 +23,7 @@ in {
     systemd.packages = [ pkgs.iwd ];
 
     systemd.services.iwd.wantedBy = [ "multi-user.target" ];
-
-    systemd.tmpfiles.rules = [
-      "d /var/lib/iwd 0700 root root -"
-      "d /var/lib/ead 0700 root root -"
-    ];
   };
 
-  meta.maintainers = with lib.maintainers; [ mic92 ];
+  meta.maintainers = with lib.maintainers; [ mic92 dtzWill ];
 }
diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix
index 47364ecb8464..12ff89fe8492 100644
--- a/nixos/modules/services/networking/knot.nix
+++ b/nixos/modules/services/networking/knot.nix
@@ -5,14 +5,16 @@ with lib;
 let
   cfg = config.services.knot;
 
-  configFile = pkgs.writeText "knot.conf" cfg.extraConfig;
-  socketFile = "/run/knot/knot.sock";
+  configFile = pkgs.writeTextFile {
+    name = "knot.conf";
+    text = (concatMapStringsSep "\n" (file: "include: ${file}") cfg.keyFiles) + "\n" +
+           cfg.extraConfig;
+    checkPhase = lib.optionalString (cfg.keyFiles == []) ''
+      ${cfg.package}/bin/knotc --config=$out conf-check
+    '';
+  };
 
-  knotConfCheck = file: pkgs.runCommand "knot-config-checked"
-    { buildInputs = [ cfg.package ]; } ''
-    ln -s ${configFile} $out
-    knotc --config=${configFile} conf-check
-  '';
+  socketFile = "/run/knot/knot.sock";
 
   knot-cli-wrappers = pkgs.stdenv.mkDerivation {
     name = "knot-cli-wrappers";
@@ -45,6 +47,19 @@ in {
         '';
       };
 
+      keyFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          A list of files containing additional configuration
+          to be included using the include directive. This option
+          allows to include configuration like TSIG keys without
+          exposing them to the nix store readable to any process.
+          Note that using this option will also disable configuration
+          checks at build time.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -65,6 +80,13 @@ in {
   };
 
   config = mkIf config.services.knot.enable {
+    users.users.knot = {
+      isSystemUser = true;
+      group = "knot";
+      description = "Knot daemon user";
+    };
+
+    users.groups.knot.gid = null;
     systemd.services.knot = {
       unitConfig.Documentation = "man:knotd(8) man:knot.conf(5) man:knotc(8) https://www.knot-dns.cz/docs/${cfg.package.version}/html/";
       description = cfg.package.meta.description;
@@ -74,12 +96,12 @@ in {
 
       serviceConfig = {
         Type = "notify";
-        ExecStart = "${cfg.package}/bin/knotd --config=${knotConfCheck configFile} --socket=${socketFile} ${concatStringsSep " " cfg.extraArgs}";
+        ExecStart = "${cfg.package}/bin/knotd --config=${configFile} --socket=${socketFile} ${concatStringsSep " " cfg.extraArgs}";
         ExecReload = "${knot-cli-wrappers}/bin/knotc reload";
         CapabilityBoundingSet = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
         AmbientCapabilities = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
         NoNewPrivileges = true;
-        DynamicUser = "yes";
+        User = "knot";
         RuntimeDirectory = "knot";
         StateDirectory = "knot";
         StateDirectoryMode = "0700";
diff --git a/nixos/modules/services/networking/pppd.nix b/nixos/modules/services/networking/pppd.nix
index b31bfa642358..c1cbdb461765 100644
--- a/nixos/modules/services/networking/pppd.nix
+++ b/nixos/modules/services/networking/pppd.nix
@@ -130,7 +130,7 @@ in
     systemdConfigs = listToAttrs (map mkSystemd enabledConfigs);
 
   in mkIf cfg.enable {
-    environment.etc = mkMerge etcFiles;
-    systemd.services = mkMerge systemdConfigs;
+    environment.etc = etcFiles;
+    systemd.services = systemdConfigs;
   };
 }
diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix
index 41c52b9653bf..853347bf86e2 100644
--- a/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixos/modules/services/web-apps/mattermost.nix
@@ -6,14 +6,18 @@ let
 
   cfg = config.services.mattermost;
 
-  defaultConfig = builtins.fromJSON (readFile "${pkgs.mattermost}/config/config.json");
+  defaultConfig = builtins.fromJSON (builtins.replaceStrings [ "\\u0026" ] [ "&" ]
+    (readFile "${pkgs.mattermost}/config/config.json")
+  );
+
+  database = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10";
 
   mattermostConf = foldl recursiveUpdate defaultConfig
     [ { ServiceSettings.SiteURL = cfg.siteUrl;
         ServiceSettings.ListenAddress = cfg.listenAddress;
         TeamSettings.SiteName = cfg.siteName;
         SqlSettings.DriverName = "postgres";
-        SqlSettings.DataSource = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10";
+        SqlSettings.DataSource = database;
       }
       cfg.extraConfig
     ];
@@ -175,7 +179,9 @@ in
           mkdir -p ${cfg.statePath}/{data,config,logs}
           ln -sf ${pkgs.mattermost}/{bin,fonts,i18n,templates,client} ${cfg.statePath}
         '' + lib.optionalString (!cfg.mutableConfig) ''
-          ln -sf ${mattermostConfJSON} ${cfg.statePath}/config/config.json
+          rm -f ${cfg.statePath}/config/config.json
+          cp ${mattermostConfJSON} ${cfg.statePath}/config/config.json
+          ${pkgs.mattermost}/bin/mattermost config migrate ${cfg.statePath}/config/config.json ${database}
         '' + lib.optionalString cfg.mutableConfig ''
           if ! test -e "${cfg.statePath}/config/.initial-created"; then
             rm -f ${cfg.statePath}/config/config.json
@@ -201,7 +207,8 @@ in
           PermissionsStartOnly = true;
           User = cfg.user;
           Group = cfg.group;
-          ExecStart = "${pkgs.mattermost}/bin/mattermost";
+          ExecStart = "${pkgs.mattermost}/bin/mattermost" +
+            (lib.optionalString (!cfg.mutableConfig) " -c ${database}");
           WorkingDirectory = "${cfg.statePath}";
           Restart = "always";
           RestartSec = "10";
@@ -227,4 +234,3 @@ in
     })
   ];
 }
-
diff --git a/nixos/modules/services/web-servers/caddy.nix b/nixos/modules/services/web-servers/caddy.nix
index 132c50735d96..0e6e10a5f47d 100644
--- a/nixos/modules/services/web-servers/caddy.nix
+++ b/nixos/modules/services/web-servers/caddy.nix
@@ -64,32 +64,38 @@ in {
   config = mkIf cfg.enable {
     systemd.services.caddy = {
       description = "Caddy web server";
+      # upstream unit: https://github.com/caddyserver/caddy/blob/master/dist/init/linux-systemd/caddy.service
       after = [ "network-online.target" ];
+      wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
       wantedBy = [ "multi-user.target" ];
       environment = mkIf (versionAtLeast config.system.stateVersion "17.09")
         { CADDYPATH = cfg.dataDir; };
       serviceConfig = {
         ExecStart = ''
-          ${cfg.package}/bin/caddy -root=/var/tmp -conf=${configFile} \
+          ${cfg.package}/bin/caddy -log stdout -log-timestamps=false \
+            -root=/var/tmp -conf=${configFile} \
             -ca=${cfg.ca} -email=${cfg.email} ${optionalString cfg.agree "-agree"}
         '';
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
         Type = "simple";
         User = "caddy";
         Group = "caddy";
-        Restart = "on-failure";
-        StartLimitInterval = 86400;
-        StartLimitBurst = 5;
+        Restart = "on-abnormal";
+        StartLimitIntervalSec = 14400;
+        StartLimitBurst = 10;
         AmbientCapabilities = "cap_net_bind_service";
         CapabilityBoundingSet = "cap_net_bind_service";
         NoNewPrivileges = true;
-        LimitNPROC = 64;
+        LimitNPROC = 512;
         LimitNOFILE = 1048576;
         PrivateTmp = true;
         PrivateDevices = true;
         ProtectHome = true;
         ProtectSystem = "full";
         ReadWriteDirectories = cfg.dataDir;
+        KillMode = "mixed";
+        KillSignal = "SIGQUIT";
+        TimeoutStopSec = "5s";
       };
     };
 
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 821886e5fdab..5d49ca943872 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -427,6 +427,7 @@ in
                     TryExec=${script}
                     Exec=${script}
                     Name=${sessionName}
+                    DesktopNames=${sessionName}
                   '';
                 } // {
                   providedSessions = [ sessionName ];
diff --git a/nixos/modules/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix
index c0868604a688..56e30c79d1f1 100644
--- a/nixos/modules/services/x11/unclutter.nix
+++ b/nixos/modules/services/x11/unclutter.nix
@@ -61,7 +61,7 @@ in {
       serviceConfig.ExecStart = ''
         ${cfg.package}/bin/unclutter \
           -idle ${toString cfg.timeout} \
-          -jitter ${toString (cfg.threeshold - 1)} \
+          -jitter ${toString (cfg.threshold - 1)} \
           ${optionalString cfg.keystroke "-keystroke"} \
           ${concatMapStrings (x: " -"+x) cfg.extraOptions} \
           -not ${concatStringsSep " " cfg.excluded} \
diff --git a/nixos/modules/services/x11/urxvtd.nix b/nixos/modules/services/x11/urxvtd.nix
index 9bfcfa9b065d..867ac38a944f 100644
--- a/nixos/modules/services/x11/urxvtd.nix
+++ b/nixos/modules/services/x11/urxvtd.nix
@@ -18,10 +18,10 @@ in {
     };
 
     package = mkOption {
-      default = pkgs.rxvt_unicode-with-plugins;
-      defaultText = "pkgs.rxvt_unicode-with-plugins";
+      default = pkgs.rxvt-unicode;
+      defaultText = "pkgs.rxvt-unicode";
       description = ''
-        Package to install. Usually pkgs.rxvt_unicode-with-plugins or pkgs.rxvt_unicode
+        Package to install. Usually pkgs.rxvt-unicode.
       '';
       type = types.package;
     };
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 6edb9082e75a..c247f334c23d 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -101,7 +101,12 @@ in
       type = types.bool;
       default = false;
       description = ''
-        Whether to activate VESA video mode on boot.
+        (Deprecated) This option, if set, activates the VESA 800x600 video
+        mode on boot and disables kernel modesetting. It is equivalent to
+        specifying <literal>[ "vga=0x317" "nomodeset" ]</literal> in the
+        <option>boot.kernelParams</option> option. This option is
+        deprecated as of 2020: Xorg now works better with modesetting, and
+        you might want a different VESA vga setting, anyway.
       '';
     };
 
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index 965a1c9eb1a6..0ade74b957a0 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -305,7 +305,8 @@ in
       in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
 
     systemd.tmpfiles.rules = [
-      "Z /run/keys 0750 root ${toString config.ids.gids.keys}"
+      "d /run/keys 0750 root ${toString config.ids.gids.keys}"
+      "z /run/keys 0750 root ${toString config.ids.gids.keys}"
     ];
 
     # Sync mount options with systemd's src/core/mount-setup.c: mount_table.
diff --git a/nixos/modules/virtualisation/docker-containers.nix b/nixos/modules/virtualisation/docker-containers.nix
index 216ba2c733fc..cae39a56f52f 100644
--- a/nixos/modules/virtualisation/docker-containers.nix
+++ b/nixos/modules/virtualisation/docker-containers.nix
@@ -192,13 +192,22 @@ let
             ["--network=host"]
           '';
         };
+
+        autoStart = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            When enabled, the container is automatically started on boot.
+            If this option is set to false, the container has to be started on-demand via its service.
+          '';
+        };
       };
     };
 
   mkService = name: container: let
     mkAfter = map (x: "docker-${x}.service") container.dependsOn;
   in rec {
-    wantedBy = [ "multi-user.target" ];
+    wantedBy = [] ++ optional (container.autoStart) "multi-user.target";
     after = [ "docker.service" "docker.socket" ] ++ mkAfter;
     requires = after;
 
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index 641699818769..41f8c3d9d52f 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -66,6 +66,7 @@ in rec {
         (all nixos.tests.containers-ip)
         nixos.tests.chromium.x86_64-linux or []
         (all nixos.tests.firefox)
+        (all nixos.tests.firefox-esr)
         (all nixos.tests.firewall)
         (all nixos.tests.fontconfig-default-fonts)
         (all nixos.tests.gnome3-xorg)
diff --git a/nixos/release.nix b/nixos/release.nix
index 512ba7143977..6107f3529715 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -20,7 +20,7 @@ let
   allTestsForSystem = system:
     import ./tests/all-tests.nix {
       inherit system;
-      pkgs = import nixpkgs { inherit system; };
+      pkgs = import ./.. { inherit system; };
       callTest = t: {
         ${system} = hydraJob t.test;
       };
@@ -28,7 +28,7 @@ let
   allTests =
     foldAttrs recursiveUpdate {} (map allTestsForSystem supportedSystems);
 
-  pkgs = import nixpkgs { system = "x86_64-linux"; };
+  pkgs = import ./.. { system = "x86_64-linux"; };
 
 
   versionModule =
@@ -41,7 +41,7 @@ let
   makeIso =
     { module, type, system, ... }:
 
-    with import nixpkgs { inherit system; };
+    with import ./.. { inherit system; };
 
     hydraJob ((import lib/eval-config.nix {
       inherit system;
@@ -54,7 +54,7 @@ let
   makeSdImage =
     { module, system, ... }:
 
-    with import nixpkgs { inherit system; };
+    with import ./.. { inherit system; };
 
     hydraJob ((import lib/eval-config.nix {
       inherit system;
@@ -65,7 +65,7 @@ let
   makeSystemTarball =
     { module, maintainers ? ["viric"], system }:
 
-    with import nixpkgs { inherit system; };
+    with import ./.. { inherit system; };
 
     let
 
@@ -188,7 +188,7 @@ in rec {
   # A bootable VirtualBox virtual appliance as an OVA file (i.e. packaged OVF).
   ova = forMatchingSystems [ "x86_64-linux" ] (system:
 
-    with import nixpkgs { inherit system; };
+    with import ./.. { inherit system; };
 
     hydraJob ((import lib/eval-config.nix {
       inherit system;
@@ -204,7 +204,7 @@ in rec {
   # A disk image that can be imported to Amazon EC2 and registered as an AMI
   amazonImage = forMatchingSystems [ "x86_64-linux" "aarch64-linux" ] (system:
 
-    with import nixpkgs { inherit system; };
+    with import ./.. { inherit system; };
 
     hydraJob ((import lib/eval-config.nix {
       inherit system;
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 33c6441dbc80..a854365f752e 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -88,6 +88,7 @@ in
   fancontrol = handleTest ./fancontrol.nix {};
   ferm = handleTest ./ferm.nix {};
   firefox = handleTest ./firefox.nix {};
+  firefox-esr = handleTest ./firefox.nix { esr = true; };
   firewall = handleTest ./firewall.nix {};
   fish = handleTest ./fish.nix {};
   flannel = handleTestOn ["x86_64-linux"] ./flannel.nix {};
@@ -144,6 +145,7 @@ in
   kernel-testing = handleTest ./kernel-testing.nix {};
   keymap = handleTest ./keymap.nix {};
   knot = handleTest ./knot.nix {};
+  krb5 = discoverTests (import ./krb5 {});
   kubernetes.dns = handleTestOn ["x86_64-linux"] ./kubernetes/dns.nix {};
   # kubernetes.e2e should eventually replace kubernetes.rbac when it works
   #kubernetes.e2e = handleTestOn ["x86_64-linux"] ./kubernetes/e2e.nix {};
diff --git a/nixos/tests/docker-containers.nix b/nixos/tests/docker-containers.nix
index 9be9bfa80ce0..0e318a52d9f1 100644
--- a/nixos/tests/docker-containers.nix
+++ b/nixos/tests/docker-containers.nix
@@ -1,30 +1,27 @@
 # Test Docker containers as systemd units
 
-import ./make-test.nix ({ pkgs, lib, ... }:
-
-{
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "docker-containers";
   meta = {
     maintainers = with lib.maintainers; [ benley mkaito ];
   };
 
   nodes = {
-    docker = { pkgs, ... }:
-      {
-        virtualisation.docker.enable = true;
+    docker = { pkgs, ... }: {
+      virtualisation.docker.enable = true;
 
-        docker-containers.nginx = {
-          image = "nginx-container";
-          imageFile = pkgs.dockerTools.examples.nginx;
-          ports = ["8181:80"];
-        };
+      docker-containers.nginx = {
+        image = "nginx-container";
+        imageFile = pkgs.dockerTools.examples.nginx;
+        ports = ["8181:80"];
       };
+    };
   };
 
   testScript = ''
-    startAll;
-    $docker->waitForUnit("docker-nginx.service");
-    $docker->waitForOpenPort(8181);
-    $docker->waitUntilSucceeds("curl http://localhost:8181|grep Hello");
+    start_all()
+    docker.wait_for_unit("docker-nginx.service")
+    docker.wait_for_open_port(8181)
+    docker.wait_until_succeeds("curl http://localhost:8181 | grep Hello")
   '';
 })
diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix
index 07fac5336803..ca750e8ba3cd 100644
--- a/nixos/tests/docker-tools.nix
+++ b/nixos/tests/docker-tools.nix
@@ -83,5 +83,11 @@ import ./make-test.nix ({ pkgs, ... }: {
 
       # Ensure image with only 2 layers can be loaded
       $docker->succeed("docker load --input='${pkgs.dockerTools.examples.two-layered-image}'");
+
+      # Ensure the bulk layer didn't miss store paths
+      # Regression test for https://github.com/NixOS/nixpkgs/issues/78744
+      $docker->succeed("docker load --input='${pkgs.dockerTools.examples.bulk-layer}'");
+      # This ensure the two output paths (ls and hello) are in the layer
+      $docker->succeed("docker run bulk-layer ls /bin/hello");
     '';
 })
diff --git a/nixos/tests/firefox.nix b/nixos/tests/firefox.nix
index 56ddabbae771..7071baceba73 100644
--- a/nixos/tests/firefox.nix
+++ b/nixos/tests/firefox.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix ({ pkgs, ... }: {
+import ./make-test-python.nix ({ pkgs, esr ? false, ... }: {
   name = "firefox";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ eelco shlevy ];
@@ -8,7 +8,9 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     { pkgs, ... }:
 
     { imports = [ ./common/x11.nix ];
-      environment.systemPackages = [ pkgs.firefox pkgs.xdotool ];
+      environment.systemPackages =
+        (if esr then [ pkgs.firefox-esr ] else [ pkgs.firefox ])
+        ++ [ pkgs.xdotool ];
     };
 
   testScript = ''
diff --git a/nixos/tests/knot.nix b/nixos/tests/knot.nix
index 0588cf86ac09..8bab917a351e 100644
--- a/nixos/tests/knot.nix
+++ b/nixos/tests/knot.nix
@@ -28,6 +28,13 @@ let
     name = "knot-zones";
     paths = [ exampleZone delegatedZone ];
   };
+  # DO NOT USE pkgs.writeText IN PRODUCTION. This put secrets in the nix store!
+  tsigFile = pkgs.writeText "tsig.conf" ''
+    key:
+      - id: slave_key
+        algorithm: hmac-sha256
+        secret: zOYgOgnzx3TGe5J5I/0kxd7gTcxXhLYMEq3Ek3fY37s=
+  '';
 in {
   name = "knot";
   meta = with pkgs.stdenv.lib.maintainers; {
@@ -48,6 +55,7 @@ in {
       };
       services.knot.enable = true;
       services.knot.extraArgs = [ "-v" ];
+      services.knot.keyFiles = [ tsigFile ];
       services.knot.extraConfig = ''
         server:
             listen: 0.0.0.0@53
@@ -56,6 +64,7 @@ in {
         acl:
           - id: slave_acl
             address: 192.168.0.2
+            key: slave_key
             action: transfer
 
         remote:
@@ -103,6 +112,7 @@ in {
         ];
       };
       services.knot.enable = true;
+      services.knot.keyFiles = [ tsigFile ];
       services.knot.extraArgs = [ "-v" ];
       services.knot.extraConfig = ''
         server:
@@ -117,6 +127,7 @@ in {
         remote:
           - id: master
             address: 192.168.0.1@53
+            key: slave_key
 
         template:
           - id: default
@@ -155,10 +166,10 @@ in {
         ];
       };
       environment.systemPackages = [ pkgs.knot-dns ];
-    };    
+    };
   };
 
-  testScript = { nodes, ... }: let 
+  testScript = { nodes, ... }: let
     master4 = (lib.head nodes.master.config.networking.interfaces.eth1.ipv4.addresses).address;
     master6 = (lib.head nodes.master.config.networking.interfaces.eth1.ipv6.addresses).address;
 
diff --git a/nixos/tests/krb5/deprecated-config.nix b/nixos/tests/krb5/deprecated-config.nix
index 7d7926309c95..be6ebce9e051 100644
--- a/nixos/tests/krb5/deprecated-config.nix
+++ b/nixos/tests/krb5/deprecated-config.nix
@@ -1,7 +1,7 @@
 # Verifies that the configuration suggested in deprecated example values
 # will result in the expected output.
 
-import ../make-test.nix ({ pkgs, ...} : {
+import ../make-test-python.nix ({ pkgs, ...} : {
   name = "krb5-with-deprecated-config";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ eqyiel ];
@@ -43,6 +43,8 @@ import ../make-test.nix ({ pkgs, ...} : {
 
     '';
   in ''
-    $machine->succeed("diff /etc/krb5.conf ${snapshot}");
+    machine.succeed(
+        "diff /etc/krb5.conf ${snapshot}"
+    )
   '';
 })
diff --git a/nixos/tests/krb5/example-config.nix b/nixos/tests/krb5/example-config.nix
index f01cf6988eef..be195b513935 100644
--- a/nixos/tests/krb5/example-config.nix
+++ b/nixos/tests/krb5/example-config.nix
@@ -1,7 +1,7 @@
 # Verifies that the configuration suggested in (non-deprecated) example values
 # will result in the expected output.
 
-import ../make-test.nix ({ pkgs, ...} : {
+import ../make-test-python.nix ({ pkgs, ...} : {
   name = "krb5-with-example-config";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ eqyiel ];
@@ -101,6 +101,8 @@ import ../make-test.nix ({ pkgs, ...} : {
         default      = SYSLOG:NOTICE
     '';
   in ''
-    $machine->succeed("diff /etc/krb5.conf ${snapshot}");
+    machine.succeed(
+        "diff /etc/krb5.conf ${snapshot}"
+    )
   '';
 })
diff --git a/nixos/tests/nsd.nix b/nixos/tests/nsd.nix
index c3c91e71b5ca..bcc14e817a87 100644
--- a/nixos/tests/nsd.nix
+++ b/nixos/tests/nsd.nix
@@ -5,7 +5,7 @@ let
     # for a host utility with IPv6 support
     environment.systemPackages = [ pkgs.bind ];
   };
-in import ./make-test.nix ({ pkgs, ...} : {
+in import ./make-test-python.nix ({ pkgs, ...} : {
   name = "nsd";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ aszlig ];
@@ -65,37 +65,35 @@ in import ./make-test.nix ({ pkgs, ...} : {
   };
 
   testScript = ''
-    startAll;
+    start_all()
 
-    $clientv4->waitForUnit("network.target");
-    $clientv6->waitForUnit("network.target");
-    $server->waitForUnit("nsd.service");
+    clientv4.wait_for_unit("network.target")
+    clientv6.wait_for_unit("network.target")
+    server.wait_for_unit("nsd.service")
 
-    sub assertHost {
-      my ($type, $rr, $query, $expected) = @_;
-      my $self = $type eq 4 ? $clientv4 : $clientv6;
-      my $out = $self->succeed("host -$type -t $rr $query");
-      $self->log("output: $out");
-      chomp $out;
-      die "DNS IPv$type query on $query gave '$out' instead of '$expected'"
-        if ($out !~ $expected);
-    }
 
-    foreach (4, 6) {
-      subtest "ipv$_", sub {
-        assertHost($_, "a", "example.com", qr/has no [^ ]+ record/);
-        assertHost($_, "aaaa", "example.com", qr/has no [^ ]+ record/);
+    def assert_host(type, rr, query, expected):
+        self = clientv4 if type == 4 else clientv6
+        out = self.succeed(f"host -{type} -t {rr} {query}").rstrip()
+        self.log(f"output: {out}")
+        assert re.search(
+            expected, out
+        ), f"DNS IPv{type} query on {query} gave '{out}' instead of '{expected}'"
 
-        assertHost($_, "soa", "example.com", qr/SOA.*?noc\.example\.com/);
-        assertHost($_, "a", "ipv4.example.com", qr/address 1.2.3.4$/);
-        assertHost($_, "aaaa", "ipv6.example.com", qr/address abcd::eeff$/);
 
-        assertHost($_, "a", "deleg.example.com", qr/address 9.8.7.6$/);
-        assertHost($_, "aaaa", "deleg.example.com", qr/address fedc::bbaa$/);
+    for ipv in 4, 6:
+        with subtest(f"IPv{ipv}"):
+            assert_host(ipv, "a", "example.com", "has no [^ ]+ record")
+            assert_host(ipv, "aaaa", "example.com", "has no [^ ]+ record")
 
-        assertHost($_, "a", "root", qr/address 1.8.7.4$/);
-        assertHost($_, "aaaa", "root", qr/address acbd::4$/);
-      };
-    }
+            assert_host(ipv, "soa", "example.com", "SOA.*?noc\.example\.com")
+            assert_host(ipv, "a", "ipv4.example.com", "address 1.2.3.4$")
+            assert_host(ipv, "aaaa", "ipv6.example.com", "address abcd::eeff$")
+
+            assert_host(ipv, "a", "deleg.example.com", "address 9.8.7.6$")
+            assert_host(ipv, "aaaa", "deleg.example.com", "address fedc::bbaa$")
+
+            assert_host(ipv, "a", "root", "address 1.8.7.4$")
+            assert_host(ipv, "aaaa", "root", "address acbd::4$")
   '';
 })
diff --git a/nixos/tests/openarena.nix b/nixos/tests/openarena.nix
index b315426532ba..395ed9153ea1 100644
--- a/nixos/tests/openarena.nix
+++ b/nixos/tests/openarena.nix
@@ -1,41 +1,71 @@
-import ./make-test-python.nix ({ pkgs, ...} : {
+import ./make-test-python.nix ({ pkgs, ...} :
+
+let
+  client =
+    { pkgs, ... }:
+
+    { imports = [ ./common/x11.nix ];
+      hardware.opengl.driSupport = true;
+      environment.systemPackages = [ pkgs.openarena ];
+    };
+
+in {
   name = "openarena";
   meta = with pkgs.stdenv.lib.maintainers; {
-    maintainers = [ tomfitzhenry ];
+    maintainers = [ fpletz ];
   };
 
-  machine =
-    { pkgs, ... }:
+  nodes =
+    { server =
+        { services.openarena = {
+            enable = true;
+            extraFlags = [ "+set g_gametype 0" "+map oa_dm7" "+addbot Angelyss" "+addbot Arachna" ];
+            openPorts = true;
+          };
+        };
 
-    { imports = [];
-      environment.systemPackages = with pkgs; [
-        socat
-      ];
-      services.openarena = {
-        enable = true;
-        extraFlags = [
-          "+set dedicated 2"
-          "+set sv_hostname 'My NixOS server'"
-          "+map oa_dm1"
-        ];
-      };
+      client1 = client;
+      client2 = client;
     };
 
   testScript =
     ''
-      machine.wait_for_unit("openarena.service")
-      machine.wait_until_succeeds("ss --numeric --udp --listening | grep -q 27960")
+      start_all()
 
-      # The log line containing 'resolve address' is last and only message that occurs after
-      # the server starts accepting clients.
-      machine.wait_until_succeeds(
-          "journalctl -u openarena.service | grep 'resolve address: dpmaster.deathmask.net'"
-      )
+      server.wait_for_unit("openarena")
+      server.wait_until_succeeds("ss --numeric --udp --listening | grep -q 27960")
+
+      client1.wait_for_x()
+      client2.wait_for_x()
 
-      # Check it's possible to join the server.
-      # Can't use substring match instead of grep because the output is not utf-8
-      machine.succeed(
-          "echo -n -e '\\xff\\xff\\xff\\xffgetchallenge' | socat - UDP4-DATAGRAM:127.0.0.1:27960 | grep -q challengeResponse"
+      client1.execute("openarena +set r_fullscreen 0 +set name Foo +connect server &")
+      client2.execute("openarena +set r_fullscreen 0 +set name Bar +connect server &")
+
+      server.wait_until_succeeds(
+          "journalctl -u openarena -e | grep -q 'Foo.*entered the game'"
+      )
+      server.wait_until_succeeds(
+          "journalctl -u openarena -e | grep -q 'Bar.*entered the game'"
       )
+
+      server.sleep(10)  # wait for a while to get a nice screenshot
+
+      client1.screenshot("screen_client1_1")
+      client2.screenshot("screen_client2_1")
+
+      client1.block()
+
+      server.sleep(10)
+
+      client1.screenshot("screen_client1_2")
+      client2.screenshot("screen_client2_2")
+
+      client1.unblock()
+
+      server.sleep(10)
+
+      client1.screenshot("screen_client1_3")
+      client2.screenshot("screen_client2_3")
     '';
+
 })
diff --git a/nixos/tests/plotinus.nix b/nixos/tests/plotinus.nix
index 609afe7b2145..39a4234dbf73 100644
--- a/nixos/tests/plotinus.nix
+++ b/nixos/tests/plotinus.nix
@@ -1,4 +1,4 @@
-import ./make-test.nix ({ pkgs, ... }: {
+import ./make-test-python.nix ({ pkgs, ... }: {
   name = "plotinus";
   meta = {
     maintainers = pkgs.plotinus.meta.maintainers;
@@ -12,16 +12,17 @@ import ./make-test.nix ({ pkgs, ... }: {
       environment.systemPackages = [ pkgs.gnome3.gnome-calculator pkgs.xdotool ];
     };
 
-  testScript =
-    ''
-      $machine->waitForX;
-      $machine->succeed("gnome-calculator &");
-      $machine->waitForWindow(qr/gnome-calculator/);
-      $machine->succeed("xdotool search --sync --onlyvisible --class gnome-calculator windowfocus --sync key ctrl+shift+p");
-      $machine->sleep(5); # wait for the popup
-      $machine->succeed("xdotool key --delay 100 p r e f e r e n c e s Return");
-      $machine->waitForWindow(qr/Preferences/);
-      $machine->screenshot("screen");
-    '';
-
+  testScript = ''
+    machine.wait_for_x()
+    machine.succeed("gnome-calculator &")
+    machine.wait_for_window("gnome-calculator")
+    machine.succeed(
+        "xdotool search --sync --onlyvisible --class gnome-calculator "
+        + "windowfocus --sync key --clearmodifiers --delay 1 'ctrl+shift+p'"
+    )
+    machine.sleep(5)  # wait for the popup
+    machine.succeed("xdotool key --delay 100 p r e f e r e n c e s Return")
+    machine.wait_for_window("Preferences")
+    machine.screenshot("screen")
+  '';
 })
diff --git a/nixos/tests/solr.nix b/nixos/tests/solr.nix
index 23e1a960fb37..dc5770e16bc7 100644
--- a/nixos/tests/solr.nix
+++ b/nixos/tests/solr.nix
@@ -1,4 +1,4 @@
-import ./make-test.nix ({ pkgs, ... }:
+import ./make-test-python.nix ({ pkgs, ... }:
 
 {
   name = "solr";
@@ -21,28 +21,36 @@ import ./make-test.nix ({ pkgs, ... }:
     };
 
   testScript = ''
-    startAll;
+    start_all()
 
-    $machine->waitForUnit('solr.service');
-    $machine->waitForOpenPort('8983');
-    $machine->succeed('curl --fail http://localhost:8983/solr/');
+    machine.wait_for_unit("solr.service")
+    machine.wait_for_open_port(8983)
+    machine.succeed("curl --fail http://localhost:8983/solr/")
 
     # adapted from pkgs.solr/examples/films/README.txt
-    $machine->succeed('sudo -u solr solr create -c films');
-    $machine->succeed(q(curl http://localhost:8983/solr/films/schema -X POST -H 'Content-type:application/json' --data-binary '{
-      "add-field" : {
-        "name":"name",
-        "type":"text_general",
-        "multiValued":false,
-        "stored":true
-      },
-      "add-field" : {
-        "name":"initial_release_date",
-        "type":"pdate",
-        "stored":true
-      }
-    }')) =~ /"status":0/ or die;
-    $machine->succeed('sudo -u solr post -c films ${pkgs.solr}/example/films/films.json');
-    $machine->succeed('curl http://localhost:8983/solr/films/query?q=name:batman') =~ /"name":"Batman Begins"/ or die;
+    machine.succeed("sudo -u solr solr create -c films")
+    assert '"status":0' in machine.succeed(
+        """
+      curl http://localhost:8983/solr/films/schema -X POST -H 'Content-type:application/json' --data-binary '{
+        "add-field" : {
+          "name":"name",
+          "type":"text_general",
+          "multiValued":false,
+          "stored":true
+        },
+        "add-field" : {
+          "name":"initial_release_date",
+          "type":"pdate",
+          "stored":true
+        }
+      }'
+    """
+    )
+    machine.succeed(
+        "sudo -u solr post -c films ${pkgs.solr}/example/films/films.json"
+    )
+    assert '"name":"Batman Begins"' in machine.succeed(
+        "curl http://localhost:8983/solr/films/query?q=name:batman"
+    )
   '';
 })