about summary refs log tree commit diff
path: root/nixpkgs/nixos
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-07-09 12:30:28 +0000
committerAlyssa Ross <hi@alyssa.is>2021-07-23 09:11:31 +0000
commit55cc63c079f49e81d695a25bc2f5b3902f2bd290 (patch)
treee705335d97f50b927c76ccb4a3fbde9fab8372b9 /nixpkgs/nixos
parentc26eb6f74d9393127a21eee7a9620a920769f613 (diff)
parent87807e64a5ef5206b745a40af118c7be8db73681 (diff)
downloadnixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.gz
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.bz2
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.lz
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.xz
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.tar.zst
nixlib-55cc63c079f49e81d695a25bc2f5b3902f2bd290.zip
Merge commit '87807e64a5ef5206b745a40af118c7be8db73681'
Diffstat (limited to 'nixpkgs/nixos')
-rw-r--r--nixpkgs/nixos/doc/manual/administration/boot-problems.section.md6
-rw-r--r--nixpkgs/nixos/doc/manual/development/nixos-tests.xml6
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md44
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml49
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md31
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml36
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md301
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml517
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/administration/boot-problems.section.xml17
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml50
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml34
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml526
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2105.section.xml16
-rw-r--r--nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml139
-rw-r--r--nixpkgs/nixos/doc/manual/installation/installing.xml4
-rw-r--r--nixpkgs/nixos/doc/manual/preface.xml4
-rw-r--r--nixpkgs/nixos/doc/manual/release-notes/rl-2105.section.md4
-rw-r--r--nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md34
-rw-r--r--nixpkgs/nixos/modules/config/shells-environment.nix12
-rw-r--r--nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-base.nix11
-rw-r--r--nixpkgs/nixos/modules/installer/tools/tools.nix2
-rw-r--r--nixpkgs/nixos/modules/module-list.nix4
-rw-r--r--nixpkgs/nixos/modules/programs/flashrom.nix26
-rw-r--r--nixpkgs/nixos/modules/programs/hamster.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/ssmtp.nix3
-rw-r--r--nixpkgs/nixos/modules/programs/zsh/zsh.nix2
-rw-r--r--nixpkgs/nixos/modules/security/acme.nix16
-rw-r--r--nixpkgs/nixos/modules/security/systemd-confinement.nix2
-rw-r--r--nixpkgs/nixos/modules/services/amqp/rabbitmq.nix2
-rw-r--r--nixpkgs/nixos/modules/services/audio/slimserver.nix1
-rw-r--r--nixpkgs/nixos/modules/services/backup/btrbk.nix220
-rw-r--r--nixpkgs/nixos/modules/services/backup/sanoid.nix88
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix1
-rw-r--r--nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix2
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix31
-rw-r--r--nixpkgs/nixos/modules/services/databases/mysql.nix2
-rw-r--r--nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json197
-rw-r--r--nixpkgs/nixos/modules/services/desktops/pipewire/jack.conf.json2
-rw-r--r--nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix6
-rw-r--r--nixpkgs/nixos/modules/services/editors/infinoted.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/docker-registry.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/geoipupdate.nix50
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitea.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/gitlab.nix108
-rw-r--r--nixpkgs/nixos/modules/services/misc/gpsd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/leaps.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/mwlib.nix6
-rw-r--r--nixpkgs/nixos/modules/services/misc/octoprint.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/paperless.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/redmine.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/subsonic.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/grafana.nix2
-rw-r--r--nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix8
-rw-r--r--nixpkgs/nixos/modules/services/networking/coturn.nix99
-rw-r--r--nixpkgs/nixos/modules/services/networking/murmur.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/namecoind.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/nar-serve.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/nix-serve.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/ssh/sshd.nix1
-rw-r--r--nixpkgs/nixos/modules/services/networking/tailscale.nix2
-rw-r--r--nixpkgs/nixos/modules/services/security/vaultwarden/backup.sh (renamed from nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh)2
-rw-r--r--nixpkgs/nixos/modules/services/security/vaultwarden/default.nix (renamed from nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix)57
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/discourse.nix5
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/minio.nix25
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/ttyd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix3
-rw-r--r--nixpkgs/nixos/modules/services/x11/window-managers/fvwm.nix2
-rw-r--r--nixpkgs/nixos/modules/system/activation/top-level.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/kernel.nix6
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py2
-rw-r--r--nixpkgs/nixos/modules/system/boot/luksroot.nix2
-rw-r--r--nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix11
-rw-r--r--nixpkgs/nixos/modules/virtualisation/oci-containers.nix3
-rw-r--r--nixpkgs/nixos/tests/acme.nix24
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix4
-rw-r--r--nixpkgs/nixos/tests/btrbk.nix110
-rw-r--r--nixpkgs/nixos/tests/coturn.nix29
-rw-r--r--nixpkgs/nixos/tests/jenkins-cli.nix30
-rw-r--r--nixpkgs/nixos/tests/kubernetes/base.nix9
-rw-r--r--nixpkgs/nixos/tests/mysql/mysql.nix16
-rw-r--r--nixpkgs/nixos/tests/sanoid.nix2
-rw-r--r--nixpkgs/nixos/tests/trafficserver.nix1
-rw-r--r--nixpkgs/nixos/tests/vault.nix4
-rw-r--r--nixpkgs/nixos/tests/vaultwarden.nix (renamed from nixpkgs/nixos/tests/bitwarden.nix)20
-rw-r--r--nixpkgs/nixos/tests/yggdrasil.nix18
-rw-r--r--nixpkgs/nixos/tests/zsh-history.nix2
86 files changed, 2305 insertions, 840 deletions
diff --git a/nixpkgs/nixos/doc/manual/administration/boot-problems.section.md b/nixpkgs/nixos/doc/manual/administration/boot-problems.section.md
index eb9209602a32..dee83e7ec225 100644
--- a/nixpkgs/nixos/doc/manual/administration/boot-problems.section.md
+++ b/nixpkgs/nixos/doc/manual/administration/boot-problems.section.md
@@ -30,6 +30,12 @@ If NixOS fails to boot, there are a number of kernel command line parameters tha
 
 : Make systemd very verbose and send log messages to the console instead of the journal. For more parameters recognised by systemd, see systemd(1).
 
+In addition, these arguments are recognised by the live image only:
+
+`live.nixos.passwd=password`
+
+: Set the password for the `nixos` live user. This can be used for SSH access if there are issues using the terminal.
+
 Notice that for `boot.shell_on_fail`, `boot.debug1`, `boot.debug1devices`, and `boot.debug1mounts`, if you did **not** select "start the new shell as pid 1", and you `exit` from the new shell, boot will proceed normally from the point where it failed, as if you'd chosen "ignore the error and continue".
 
 If no login prompts or X11 login screens appear (e.g. due to hanging dependencies), you can press Alt+ArrowUp. If you’re lucky, this will start rescue mode (described above). (Also note that since most units have a 90-second timeout before systemd gives up on them, the `agetty` login prompts should appear eventually unless something is very wrong.)
diff --git a/nixpkgs/nixos/doc/manual/development/nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
index 2695082e3867..702fc03f6686 100644
--- a/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
+++ b/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
@@ -13,7 +13,7 @@ xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/test
   one or more virtual machines containing the NixOS system(s) required for the
   test.
  </para>
- <xi:include href="writing-nixos-tests.xml" />
- <xi:include href="running-nixos-tests.xml" />
- <xi:include href="running-nixos-tests-interactively.xml" />
+ <xi:include href="../from_md/development/writing-nixos-tests.section.xml" />
+ <xi:include href="../from_md/development/running-nixos-tests.section.xml" />
+ <xi:include href="../from_md/development/running-nixos-tests-interactively.section.xml" />
 </chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
new file mode 100644
index 000000000000..3ba4e16e77f4
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
@@ -0,0 +1,44 @@
+# Running Tests interactively {#sec-running-nixos-tests-interactively}
+
+The test itself can be run interactively. This is particularly useful
+when developing or debugging a test:
+
+```ShellSession
+$ nix-build nixos/tests/login.nix -A driverInteractive
+$ ./result/bin/nixos-test-driver
+starting VDE switch for network 1
+>
+```
+
+You can then take any Python statement, e.g.
+
+```py
+> start_all()
+> test_script()
+> machine.succeed("touch /tmp/foo")
+> print(machine.succeed("pwd")) # Show stdout of command
+```
+
+The function `test_script` executes the entire test script and drops you
+back into the test driver command line upon its completion. This allows
+you to inspect the state of the VMs after the test (e.g. to debug the
+test script).
+
+To just start and experiment with the VMs, run:
+
+```ShellSession
+$ nix-build nixos/tests/login.nix -A driverInteractive
+$ ./result/bin/nixos-run-vms
+```
+
+The script `nixos-run-vms` starts the virtual machines defined by test.
+
+You can re-use the VM states coming from a previous run by setting the
+`--keep-vm-state` flag.
+
+```ShellSession
+$ ./result/bin/nixos-run-vms --keep-vm-state
+```
+
+The machine state is stored in the `$TMPDIR/vm-state-machinename`
+directory.
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml
deleted file mode 100644
index a6044d5f89e8..000000000000
--- a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-running-nixos-tests-interactively">
- <title>Running Tests interactively</title>
-
- <para>
-  The test itself can be run interactively. This is particularly useful when
-  developing or debugging a test:
-<screen>
-<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
-<prompt>$ </prompt>./result/bin/nixos-test-driver
-starting VDE switch for network 1
-<prompt>&gt;</prompt>
-</screen>
-  You can then take any Python statement, e.g.
-<screen>
-<prompt>&gt;</prompt> start_all()
-<prompt>&gt;</prompt> test_script()
-<prompt>&gt;</prompt> machine.succeed("touch /tmp/foo")
-<prompt>&gt;</prompt> print(machine.succeed("pwd")) # Show stdout of command
-</screen>
-  The function <command>test_script</command> executes the entire test script
-  and drops you back into the test driver command line upon its completion.
-  This allows you to inspect the state of the VMs after the test (e.g. to debug
-  the test script).
- </para>
-
- <para>
-  To just start and experiment with the VMs, run:
-<screen>
-<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
-<prompt>$ </prompt>./result/bin/nixos-run-vms
-</screen>
-  The script <command>nixos-run-vms</command> starts the virtual machines
-  defined by test.
- </para>
-
- <para>
-   You can re-use the VM states coming from a previous run
-   by setting the <command>--keep-vm-state</command> flag.
-<screen>
-<prompt>$ </prompt>./result/bin/nixos-run-vms --keep-vm-state
-</screen>
-  The machine state is stored in the
-  <filename>$TMPDIR/vm-state-</filename><varname>machinename</varname> directory.
- </para>
-</section>
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md
new file mode 100644
index 000000000000..d6a456f01883
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.section.md
@@ -0,0 +1,31 @@
+# Running Tests {#sec-running-nixos-tests}
+
+You can run tests using `nix-build`. For example, to run the test
+[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix),
+you just do:
+
+```ShellSession
+$ nix-build '<nixpkgs/nixos/tests/login.nix>'
+```
+
+or, if you don't want to rely on `NIX_PATH`:
+
+```ShellSession
+$ cd /my/nixpkgs/nixos/tests
+$ nix-build login.nix
+…
+running the VM test script
+machine: QEMU running (pid 8841)
+…
+6 out of 6 tests succeeded
+```
+
+After building/downloading all required dependencies, this will perform
+a build that starts a QEMU/KVM virtual machine containing a NixOS
+system. The virtual machine mounts the Nix store of the host; this makes
+VM creation very fast, as no disk image needs to be created. Afterwards,
+you can view a pretty-printed log of the test:
+
+```ShellSession
+$ firefox result/log.html
+```
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml
deleted file mode 100644
index e9257c907daf..000000000000
--- a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-running-nixos-tests">
- <title>Running Tests</title>
-
- <para>
-  You can run tests using <command>nix-build</command>. For example, to run the
-  test
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>,
-  you just do:
-<screen>
-<prompt>$ </prompt>nix-build '&lt;nixpkgs/nixos/tests/login.nix>'
-</screen>
-  or, if you don’t want to rely on <envar>NIX_PATH</envar>:
-<screen>
-<prompt>$ </prompt>cd /my/nixpkgs/nixos/tests
-<prompt>$ </prompt>nix-build login.nix
-…
-running the VM test script
-machine: QEMU running (pid 8841)
-…
-6 out of 6 tests succeeded
-</screen>
-  After building/downloading all required dependencies, this will perform a
-  build that starts a QEMU/KVM virtual machine containing a NixOS system. The
-  virtual machine mounts the Nix store of the host; this makes VM creation very
-  fast, as no disk image needs to be created. Afterwards, you can view a
-  pretty-printed log of the test:
-<screen>
-<prompt>$ </prompt>firefox result/log.html
-</screen>
- </para>
-</section>
diff --git a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md
new file mode 100644
index 000000000000..8471e7608af9
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.section.md
@@ -0,0 +1,301 @@
+# Writing Tests {#sec-writing-nixos-tests}
+
+A NixOS test is a Nix expression that has the following structure:
+
+```nix
+import ./make-test-python.nix {
+
+  # Either the configuration of a single machine:
+  machine =
+    { config, pkgs, ... }:
+    { configuration…
+    };
+
+  # Or a set of machines:
+  nodes =
+    { machine1 =
+        { config, pkgs, ... }: { … };
+      machine2 =
+        { config, pkgs, ... }: { … };
+      …
+    };
+
+  testScript =
+    ''
+      Python code…
+    '';
+}
+```
+
+The attribute `testScript` is a bit of Python code that executes the
+test (described below). During the test, it will start one or more
+virtual machines, the configuration of which is described by the
+attribute `machine` (if you need only one machine in your test) or by
+the attribute `nodes` (if you need multiple machines). For instance,
+[`login.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix)
+only needs a single machine to test whether users can log in
+on the virtual console, whether device ownership is correctly maintained
+when switching between consoles, and so on. On the other hand,
+[`nfs/simple.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix),
+which tests NFS client and server functionality in the
+Linux kernel (including whether locks are maintained across server
+crashes), requires three machines: a server and two clients.
+
+There are a few special NixOS configuration options for test VMs:
+
+`virtualisation.memorySize`
+
+:   The memory of the VM in megabytes.
+
+`virtualisation.vlans`
+
+:   The virtual networks to which the VM is connected. See
+    [`nat.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix)
+    for an example.
+
+`virtualisation.writableStore`
+
+:   By default, the Nix store in the VM is not writable. If you enable
+    this option, a writable union file system is mounted on top of the
+    Nix store to make it appear writable. This is necessary for tests
+    that run Nix operations that modify the store.
+
+For more options, see the module
+[`qemu-vm.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix).
+
+The test script is a sequence of Python statements that perform various
+actions, such as starting VMs, executing commands in the VMs, and so on.
+Each virtual machine is represented as an object stored in the variable
+`name` if this is also the identifier of the machine in the declarative
+config. If you didn\'t specify multiple machines using the `nodes`
+attribute, it is just `machine`. The following example starts the
+machine, waits until it has finished booting, then executes a command
+and checks that the output is more-or-less correct:
+
+```py
+machine.start()
+machine.wait_for_unit("default.target")
+if not "Linux" in machine.succeed("uname"):
+  raise Exception("Wrong OS")
+```
+
+The first line is actually unnecessary; machines are implicitly started
+when you first execute an action on them (such as `wait_for_unit` or
+`succeed`). If you have multiple machines, you can speed up the test by
+starting them in parallel:
+
+```py
+start_all()
+```
+
+The following methods are available on machine objects:
+
+`start`
+
+:   Start the virtual machine. This method is asynchronous --- it does
+    not wait for the machine to finish booting.
+
+`shutdown`
+
+:   Shut down the machine, waiting for the VM to exit.
+
+`crash`
+
+:   Simulate a sudden power failure, by telling the VM to exit
+    immediately.
+
+`block`
+
+:   Simulate unplugging the Ethernet cable that connects the machine to
+    the other machines.
+
+`unblock`
+
+:   Undo the effect of `block`.
+
+`screenshot`
+
+:   Take a picture of the display of the virtual machine, in PNG format.
+    The screenshot is linked from the HTML log.
+
+`get_screen_text_variants`
+
+:   Return a list of different interpretations of what is currently
+    visible on the machine\'s screen using optical character
+    recognition. The number and order of the interpretations is not
+    specified and is subject to change, but if no exception is raised at
+    least one will be returned.
+
+    ::: {.note}
+    This requires passing `enableOCR` to the test attribute set.
+    :::
+
+`get_screen_text`
+
+:   Return a textual representation of what is currently visible on the
+    machine\'s screen using optical character recognition.
+
+    ::: {.note}
+    This requires passing `enableOCR` to the test attribute set.
+    :::
+
+`send_monitor_command`
+
+:   Send a command to the QEMU monitor. This is rarely used, but allows
+    doing stuff such as attaching virtual USB disks to a running
+    machine.
+
+`send_key`
+
+:   Simulate pressing keys on the virtual keyboard, e.g.,
+    `send_key("ctrl-alt-delete")`.
+
+`send_chars`
+
+:   Simulate typing a sequence of characters on the virtual keyboard,
+    e.g., `send_chars("foobar\n")` will type the string `foobar`
+    followed by the Enter key.
+
+`execute`
+
+:   Execute a shell command, returning a list `(status, stdout)`.
+
+`succeed`
+
+:   Execute a shell command, raising an exception if the exit status is
+    not zero, otherwise returning the standard output. Commands are run
+    with `set -euo pipefail` set:
+
+    -   If several commands are separated by `;` and one fails, the
+        command as a whole will fail.
+
+    -   For pipelines, the last non-zero exit status will be returned
+        (if there is one, zero will be returned otherwise).
+
+    -   Dereferencing unset variables fail the command.
+
+`fail`
+
+:   Like `succeed`, but raising an exception if the command returns a zero
+    status.
+
+`wait_until_succeeds`
+
+:   Repeat a shell command with 1-second intervals until it succeeds.
+
+`wait_until_fails`
+
+:   Repeat a shell command with 1-second intervals until it fails.
+
+`wait_for_unit`
+
+:   Wait until the specified systemd unit has reached the "active"
+    state.
+
+`wait_for_file`
+
+:   Wait until the specified file exists.
+
+`wait_for_open_port`
+
+:   Wait until a process is listening on the given TCP port (on
+    `localhost`, at least).
+
+`wait_for_closed_port`
+
+:   Wait until nobody is listening on the given TCP port.
+
+`wait_for_x`
+
+:   Wait until the X11 server is accepting connections.
+
+`wait_for_text`
+
+:   Wait until the supplied regular expressions matches the textual
+    contents of the screen by using optical character recognition (see
+    `get_screen_text` and `get_screen_text_variants`).
+
+    ::: {.note}
+    This requires passing `enableOCR` to the test attribute set.
+    :::
+
+`wait_for_console_text`
+
+:   Wait until the supplied regular expressions match a line of the
+    serial console output. This method is useful when OCR is not
+    possibile or accurate enough.
+
+`wait_for_window`
+
+:   Wait until an X11 window has appeared whose name matches the given
+    regular expression, e.g., `wait_for_window("Terminal")`.
+
+`copy_from_host`
+
+:   Copies a file from host to machine, e.g.,
+    `copy_from_host("myfile", "/etc/my/important/file")`.
+
+    The first argument is the file on the host. The file needs to be
+    accessible while building the nix derivation. The second argument is
+    the location of the file on the machine.
+
+`systemctl`
+
+:   Runs `systemctl` commands with optional support for
+    `systemctl --user`
+
+    ```py
+    machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
+    machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
+    ```
+
+`shell_interact`
+
+:   Allows you to directly interact with the guest shell. This should
+    only be used during test development, not in production tests.
+    Killing the interactive session with `Ctrl-d` or `Ctrl-c` also ends
+    the guest session.
+
+To test user units declared by `systemd.user.services` the optional
+`user` argument can be used:
+
+```py
+machine.start()
+machine.wait_for_x()
+machine.wait_for_unit("xautolock.service", "x-session-user")
+```
+
+This applies to `systemctl`, `get_unit_info`, `wait_for_unit`,
+`start_job` and `stop_job`.
+
+For faster dev cycles it\'s also possible to disable the code-linters
+(this shouldn\'t be commited though):
+
+```nix
+import ./make-test-python.nix {
+  skipLint = true;
+  machine =
+    { config, pkgs, ... }:
+    { configuration…
+    };
+
+  testScript =
+    ''
+      Python code…
+    '';
+}
+```
+
+This will produce a Nix warning at evaluation time. To fully disable the
+linter, wrap the test script in comment directives to disable the Black
+linter directly (again, don\'t commit this within the Nixpkgs
+repository):
+
+```nix
+  testScript =
+    ''
+      # fmt: off
+      Python code…
+      # fmt: on
+    '';
+```
diff --git a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml
deleted file mode 100644
index e372c66410de..000000000000
--- a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml
+++ /dev/null
@@ -1,517 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:xi="http://www.w3.org/2001/XInclude"
-        version="5.0"
-        xml:id="sec-writing-nixos-tests">
- <title>Writing Tests</title>
-
- <para>
-  A NixOS test is a Nix expression that has the following structure:
-<programlisting>
-import ./make-test-python.nix {
-
-  # Either the configuration of a single machine:
-  machine =
-    { config, pkgs, ... }:
-    { <replaceable>configuration…</replaceable>
-    };
-
-  # Or a set of machines:
-  nodes =
-    { <replaceable>machine1</replaceable> =
-        { config, pkgs, ... }: { <replaceable>…</replaceable> };
-      <replaceable>machine2</replaceable> =
-        { config, pkgs, ... }: { <replaceable>…</replaceable> };
-      …
-    };
-
-  testScript =
-    ''
-      <replaceable>Python code…</replaceable>
-    '';
-}
-</programlisting>
-  The attribute <literal>testScript</literal> is a bit of Python code that
-  executes the test (described below). During the test, it will start one or
-  more virtual machines, the configuration of which is described by the
-  attribute <literal>machine</literal> (if you need only one machine in your
-  test) or by the attribute <literal>nodes</literal> (if you need multiple
-  machines). For instance,
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>
-  only needs a single machine to test whether users can log in on the virtual
-  console, whether device ownership is correctly maintained when switching
-  between consoles, and so on. On the other hand,
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix">nfs/simple.nix</filename>,
-  which tests NFS client and server functionality in the Linux kernel
-  (including whether locks are maintained across server crashes), requires
-  three machines: a server and two clients.
- </para>
-
- <para>
-  There are a few special NixOS configuration options for test VMs:
-<!-- FIXME: would be nice to generate this automatically. -->
-  <variablelist>
-   <varlistentry>
-    <term>
-     <option>virtualisation.memorySize</option>
-    </term>
-    <listitem>
-     <para>
-      The memory of the VM in megabytes.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <option>virtualisation.vlans</option>
-    </term>
-    <listitem>
-     <para>
-      The virtual networks to which the VM is connected. See
-      <filename
-    xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename>
-      for an example.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <option>virtualisation.writableStore</option>
-    </term>
-    <listitem>
-     <para>
-      By default, the Nix store in the VM is not writable. If you enable this
-      option, a writable union file system is mounted on top of the Nix store
-      to make it appear writable. This is necessary for tests that run Nix
-      operations that modify the store.
-     </para>
-    </listitem>
-   </varlistentry>
-  </variablelist>
-  For more options, see the module
-  <filename
-xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.
- </para>
-
- <para>
-  The test script is a sequence of Python statements that perform various
-  actions, such as starting VMs, executing commands in the VMs, and so on. Each
-  virtual machine is represented as an object stored in the variable
-  <literal><replaceable>name</replaceable></literal> if this is also the
-  identifier of the machine in the declarative config.
-  If you didn't specify multiple machines using the <literal>nodes</literal>
-  attribute, it is just <literal>machine</literal>.
-  The following example starts the machine, waits until it has finished booting,
-  then executes a command and checks that the output is more-or-less correct:
-<programlisting>
-machine.start()
-machine.wait_for_unit("default.target")
-if not "Linux" in machine.succeed("uname"):
-  raise Exception("Wrong OS")
-</programlisting>
-  The first line is actually unnecessary; machines are implicitly started when
-  you first execute an action on them (such as <literal>wait_for_unit</literal>
-  or <literal>succeed</literal>). If you have multiple machines, you can speed
-  up the test by starting them in parallel:
-<programlisting>
-start_all()
-</programlisting>
- </para>
-
- <para>
-  The following methods are available on machine objects:
-  <variablelist>
-   <varlistentry>
-    <term>
-     <methodname>start</methodname>
-    </term>
-    <listitem>
-     <para>
-      Start the virtual machine. This method is asynchronous — it does not
-      wait for the machine to finish booting.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>shutdown</methodname>
-    </term>
-    <listitem>
-     <para>
-      Shut down the machine, waiting for the VM to exit.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>crash</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate a sudden power failure, by telling the VM to exit immediately.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>block</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate unplugging the Ethernet cable that connects the machine to the
-      other machines.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>unblock</methodname>
-    </term>
-    <listitem>
-     <para>
-      Undo the effect of <methodname>block</methodname>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>screenshot</methodname>
-    </term>
-    <listitem>
-     <para>
-      Take a picture of the display of the virtual machine, in PNG format. The
-      screenshot is linked from the HTML log.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>get_screen_text_variants</methodname>
-    </term>
-    <listitem>
-     <para>
-      Return a list of different interpretations of what is currently visible
-      on the machine's screen using optical character recognition. The number
-      and order of the interpretations is not specified and is subject to
-      change, but if no exception is raised at least one will be returned.
-     </para>
-     <note>
-      <para>
-       This requires passing <option>enableOCR</option> to the test attribute
-       set.
-      </para>
-     </note>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>get_screen_text</methodname>
-    </term>
-    <listitem>
-     <para>
-      Return a textual representation of what is currently visible on the
-      machine's screen using optical character recognition.
-     </para>
-     <note>
-      <para>
-       This requires passing <option>enableOCR</option> to the test attribute
-       set.
-      </para>
-     </note>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>send_monitor_command</methodname>
-    </term>
-    <listitem>
-     <para>
-      Send a command to the QEMU monitor. This is rarely used, but allows doing
-      stuff such as attaching virtual USB disks to a running machine.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>send_key</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate pressing keys on the virtual keyboard, e.g.,
-      <literal>send_key("ctrl-alt-delete")</literal>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>send_chars</methodname>
-    </term>
-    <listitem>
-     <para>
-      Simulate typing a sequence of characters on the virtual keyboard, e.g.,
-      <literal>send_chars("foobar\n")</literal> will type the string
-      <literal>foobar</literal> followed by the Enter key.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>execute</methodname>
-    </term>
-    <listitem>
-     <para>
-      Execute a shell command, returning a list
-      <literal>(<replaceable>status</replaceable>,
-      <replaceable>stdout</replaceable>)</literal>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>succeed</methodname>
-    </term>
-    <listitem>
-     <para>
-      Execute a shell command, raising an exception if the exit status
-      is not zero, otherwise returning the standard output. Commands
-      are run with <literal>set -euo pipefail</literal> set:
-      <itemizedlist>
-        <listitem>
-          <para>
-            If several commands are separated by <literal>;</literal>
-            and one fails, the command as a whole will fail.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            For pipelines, the last non-zero exit status will be
-            returned (if there is one, zero will be returned
-            otherwise).
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Dereferencing unset variables fail the command.
-          </para>
-        </listitem>
-      </itemizedlist>
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>fail</methodname>
-    </term>
-    <listitem>
-     <para>
-      Like <methodname>succeed</methodname>, but raising an exception if the
-      command returns a zero status.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_until_succeeds</methodname>
-    </term>
-    <listitem>
-     <para>
-      Repeat a shell command with 1-second intervals until it succeeds.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_until_fails</methodname>
-    </term>
-    <listitem>
-     <para>
-      Repeat a shell command with 1-second intervals until it fails.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_unit</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the specified systemd unit has reached the “active” state.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_file</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the specified file exists.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_open_port</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until a process is listening on the given TCP port (on
-      <literal>localhost</literal>, at least).
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_closed_port</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until nobody is listening on the given TCP port.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_x</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the X11 server is accepting connections.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_text</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the supplied regular expressions matches the textual contents
-      of the screen by using optical character recognition (see
-     <methodname>get_screen_text</methodname> and
-     <methodname>get_screen_text_variants</methodname>).
-     </para>
-     <note>
-      <para>
-       This requires passing <option>enableOCR</option> to the test attribute
-       set.
-      </para>
-     </note>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_console_text</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until the supplied regular expressions match a line of the serial
-      console output. This method is useful when OCR is not possibile or
-      accurate enough.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>wait_for_window</methodname>
-    </term>
-    <listitem>
-     <para>
-      Wait until an X11 window has appeared whose name matches the given
-      regular expression, e.g., <literal>wait_for_window("Terminal")</literal>.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>copy_from_host</methodname>
-    </term>
-    <listitem>
-     <para>
-      Copies a file from host to machine, e.g.,
-      <literal>copy_from_host("myfile", "/etc/my/important/file")</literal>.
-     </para>
-     <para>
-      The first argument is the file on the host. The file needs to be
-      accessible while building the nix derivation. The second argument is the
-      location of the file on the machine.
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>systemctl</methodname>
-    </term>
-    <listitem>
-     <para>
-      Runs <literal>systemctl</literal> commands with optional support for
-      <literal>systemctl --user</literal>
-     </para>
-     <para>
-<programlisting>
-machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
-machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
-</programlisting>
-     </para>
-    </listitem>
-   </varlistentry>
-   <varlistentry>
-    <term>
-     <methodname>shell_interact</methodname>
-    </term>
-    <listitem>
-     <para>
-      Allows you to directly interact with the guest shell.
-      This should only be used during test development, not in production tests.
-      Killing the interactive session with <literal>Ctrl-d</literal> or <literal>Ctrl-c</literal> also ends the guest session.
-     </para>
-    </listitem>
-   </varlistentry>
-  </variablelist>
- </para>
-
- <para>
-  To test user units declared by <literal>systemd.user.services</literal> the
-  optional <literal>user</literal> argument can be used:
-<programlisting>
-machine.start()
-machine.wait_for_x()
-machine.wait_for_unit("xautolock.service", "x-session-user")
-</programlisting>
-  This applies to <literal>systemctl</literal>, <literal>get_unit_info</literal>,
-  <literal>wait_for_unit</literal>, <literal>start_job</literal> and
-  <literal>stop_job</literal>.
- </para>
-
- <para>
-  For faster dev cycles it's also possible to disable the code-linters (this shouldn't
-  be commited though):
-<programlisting>
-import ./make-test-python.nix {
-  skipLint = true;
-  machine =
-    { config, pkgs, ... }:
-    { <replaceable>configuration…</replaceable>
-    };
-
-  testScript =
-    ''
-      <replaceable>Python code…</replaceable>
-    '';
-}
-</programlisting>
-  This will produce a Nix warning at evaluation time. To fully disable the
-  linter, wrap the test script in comment directives to disable the Black linter
-  directly (again, don't commit this within the Nixpkgs repository):
-<programlisting>
-  testScript =
-    ''
-      # fmt: off
-      <replaceable>Python code…</replaceable>
-      # fmt: on
-    '';
-</programlisting>
- </para>
-</section>
diff --git a/nixpkgs/nixos/doc/manual/from_md/administration/boot-problems.section.xml b/nixpkgs/nixos/doc/manual/from_md/administration/boot-problems.section.xml
index b484d075818a..4ea01e78f32f 100644
--- a/nixpkgs/nixos/doc/manual/from_md/administration/boot-problems.section.xml
+++ b/nixpkgs/nixos/doc/manual/from_md/administration/boot-problems.section.xml
@@ -107,6 +107,23 @@
     </varlistentry>
   </variablelist>
   <para>
+    In addition, these arguments are recognised by the live image only:
+  </para>
+  <variablelist>
+    <varlistentry>
+      <term>
+        <literal>live.nixos.passwd=password</literal>
+      </term>
+      <listitem>
+        <para>
+          Set the password for the <literal>nixos</literal> live user.
+          This can be used for SSH access if there are issues using the
+          terminal.
+        </para>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+  <para>
     Notice that for <literal>boot.shell_on_fail</literal>,
     <literal>boot.debug1</literal>,
     <literal>boot.debug1devices</literal>, and
diff --git a/nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml b/nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
new file mode 100644
index 000000000000..a2030e9c0739
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
@@ -0,0 +1,50 @@
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-running-nixos-tests-interactively">
+  <title>Running Tests interactively</title>
+  <para>
+    The test itself can be run interactively. This is particularly
+    useful when developing or debugging a test:
+  </para>
+  <programlisting>
+$ nix-build nixos/tests/login.nix -A driverInteractive
+$ ./result/bin/nixos-test-driver
+starting VDE switch for network 1
+&gt;
+</programlisting>
+  <para>
+    You can then take any Python statement, e.g.
+  </para>
+  <programlisting language="python">
+&gt; start_all()
+&gt; test_script()
+&gt; machine.succeed(&quot;touch /tmp/foo&quot;)
+&gt; print(machine.succeed(&quot;pwd&quot;)) # Show stdout of command
+</programlisting>
+  <para>
+    The function <literal>test_script</literal> executes the entire test
+    script and drops you back into the test driver command line upon its
+    completion. This allows you to inspect the state of the VMs after
+    the test (e.g. to debug the test script).
+  </para>
+  <para>
+    To just start and experiment with the VMs, run:
+  </para>
+  <programlisting>
+$ nix-build nixos/tests/login.nix -A driverInteractive
+$ ./result/bin/nixos-run-vms
+</programlisting>
+  <para>
+    The script <literal>nixos-run-vms</literal> starts the virtual
+    machines defined by test.
+  </para>
+  <para>
+    You can re-use the VM states coming from a previous run by setting
+    the <literal>--keep-vm-state</literal> flag.
+  </para>
+  <programlisting>
+$ ./result/bin/nixos-run-vms --keep-vm-state
+</programlisting>
+  <para>
+    The machine state is stored in the
+    <literal>$TMPDIR/vm-state-machinename</literal> directory.
+  </para>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml b/nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml
new file mode 100644
index 000000000000..7159b95b22b0
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml
@@ -0,0 +1,34 @@
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-running-nixos-tests">
+  <title>Running Tests</title>
+  <para>
+    You can run tests using <literal>nix-build</literal>. For example,
+    to run the test
+    <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix"><literal>login.nix</literal></link>,
+    you just do:
+  </para>
+  <programlisting>
+$ nix-build '&lt;nixpkgs/nixos/tests/login.nix&gt;'
+</programlisting>
+  <para>
+    or, if you don’t want to rely on <literal>NIX_PATH</literal>:
+  </para>
+  <programlisting>
+$ cd /my/nixpkgs/nixos/tests
+$ nix-build login.nix
+…
+running the VM test script
+machine: QEMU running (pid 8841)
+…
+6 out of 6 tests succeeded
+</programlisting>
+  <para>
+    After building/downloading all required dependencies, this will
+    perform a build that starts a QEMU/KVM virtual machine containing a
+    NixOS system. The virtual machine mounts the Nix store of the host;
+    this makes VM creation very fast, as no disk image needs to be
+    created. Afterwards, you can view a pretty-printed log of the test:
+  </para>
+  <programlisting>
+$ firefox result/log.html
+</programlisting>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml b/nixpkgs/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml
new file mode 100644
index 000000000000..83a96d5bb224
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml
@@ -0,0 +1,526 @@
+<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-writing-nixos-tests">
+  <title>Writing Tests</title>
+  <para>
+    A NixOS test is a Nix expression that has the following structure:
+  </para>
+  <programlisting language="bash">
+import ./make-test-python.nix {
+
+  # Either the configuration of a single machine:
+  machine =
+    { config, pkgs, ... }:
+    { configuration…
+    };
+
+  # Or a set of machines:
+  nodes =
+    { machine1 =
+        { config, pkgs, ... }: { … };
+      machine2 =
+        { config, pkgs, ... }: { … };
+      …
+    };
+
+  testScript =
+    ''
+      Python code…
+    '';
+}
+</programlisting>
+  <para>
+    The attribute <literal>testScript</literal> is a bit of Python code
+    that executes the test (described below). During the test, it will
+    start one or more virtual machines, the configuration of which is
+    described by the attribute <literal>machine</literal> (if you need
+    only one machine in your test) or by the attribute
+    <literal>nodes</literal> (if you need multiple machines). For
+    instance,
+    <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix"><literal>login.nix</literal></link>
+    only needs a single machine to test whether users can log in on the
+    virtual console, whether device ownership is correctly maintained
+    when switching between consoles, and so on. On the other hand,
+    <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix"><literal>nfs/simple.nix</literal></link>,
+    which tests NFS client and server functionality in the Linux kernel
+    (including whether locks are maintained across server crashes),
+    requires three machines: a server and two clients.
+  </para>
+  <para>
+    There are a few special NixOS configuration options for test VMs:
+  </para>
+  <variablelist>
+    <varlistentry>
+      <term>
+        <literal>virtualisation.memorySize</literal>
+      </term>
+      <listitem>
+        <para>
+          The memory of the VM in megabytes.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>virtualisation.vlans</literal>
+      </term>
+      <listitem>
+        <para>
+          The virtual networks to which the VM is connected. See
+          <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix"><literal>nat.nix</literal></link>
+          for an example.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>virtualisation.writableStore</literal>
+      </term>
+      <listitem>
+        <para>
+          By default, the Nix store in the VM is not writable. If you
+          enable this option, a writable union file system is mounted on
+          top of the Nix store to make it appear writable. This is
+          necessary for tests that run Nix operations that modify the
+          store.
+        </para>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+  <para>
+    For more options, see the module
+    <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix"><literal>qemu-vm.nix</literal></link>.
+  </para>
+  <para>
+    The test script is a sequence of Python statements that perform
+    various actions, such as starting VMs, executing commands in the
+    VMs, and so on. Each virtual machine is represented as an object
+    stored in the variable <literal>name</literal> if this is also the
+    identifier of the machine in the declarative config. If you didn't
+    specify multiple machines using the <literal>nodes</literal>
+    attribute, it is just <literal>machine</literal>. The following
+    example starts the machine, waits until it has finished booting,
+    then executes a command and checks that the output is more-or-less
+    correct:
+  </para>
+  <programlisting language="python">
+machine.start()
+machine.wait_for_unit(&quot;default.target&quot;)
+if not &quot;Linux&quot; in machine.succeed(&quot;uname&quot;):
+  raise Exception(&quot;Wrong OS&quot;)
+</programlisting>
+  <para>
+    The first line is actually unnecessary; machines are implicitly
+    started when you first execute an action on them (such as
+    <literal>wait_for_unit</literal> or <literal>succeed</literal>). If
+    you have multiple machines, you can speed up the test by starting
+    them in parallel:
+  </para>
+  <programlisting language="python">
+start_all()
+</programlisting>
+  <para>
+    The following methods are available on machine objects:
+  </para>
+  <variablelist>
+    <varlistentry>
+      <term>
+        <literal>start</literal>
+      </term>
+      <listitem>
+        <para>
+          Start the virtual machine. This method is asynchronous — it
+          does not wait for the machine to finish booting.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>shutdown</literal>
+      </term>
+      <listitem>
+        <para>
+          Shut down the machine, waiting for the VM to exit.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>crash</literal>
+      </term>
+      <listitem>
+        <para>
+          Simulate a sudden power failure, by telling the VM to exit
+          immediately.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>block</literal>
+      </term>
+      <listitem>
+        <para>
+          Simulate unplugging the Ethernet cable that connects the
+          machine to the other machines.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>unblock</literal>
+      </term>
+      <listitem>
+        <para>
+          Undo the effect of <literal>block</literal>.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>screenshot</literal>
+      </term>
+      <listitem>
+        <para>
+          Take a picture of the display of the virtual machine, in PNG
+          format. The screenshot is linked from the HTML log.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>get_screen_text_variants</literal>
+      </term>
+      <listitem>
+        <para>
+          Return a list of different interpretations of what is
+          currently visible on the machine's screen using optical
+          character recognition. The number and order of the
+          interpretations is not specified and is subject to change, but
+          if no exception is raised at least one will be returned.
+        </para>
+        <note>
+          <para>
+            This requires passing <literal>enableOCR</literal> to the
+            test attribute set.
+          </para>
+        </note>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>get_screen_text</literal>
+      </term>
+      <listitem>
+        <para>
+          Return a textual representation of what is currently visible
+          on the machine's screen using optical character recognition.
+        </para>
+        <note>
+          <para>
+            This requires passing <literal>enableOCR</literal> to the
+            test attribute set.
+          </para>
+        </note>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>send_monitor_command</literal>
+      </term>
+      <listitem>
+        <para>
+          Send a command to the QEMU monitor. This is rarely used, but
+          allows doing stuff such as attaching virtual USB disks to a
+          running machine.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>send_key</literal>
+      </term>
+      <listitem>
+        <para>
+          Simulate pressing keys on the virtual keyboard, e.g.,
+          <literal>send_key(&quot;ctrl-alt-delete&quot;)</literal>.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>send_chars</literal>
+      </term>
+      <listitem>
+        <para>
+          Simulate typing a sequence of characters on the virtual
+          keyboard, e.g.,
+          <literal>send_chars(&quot;foobar\n&quot;)</literal> will type
+          the string <literal>foobar</literal> followed by the Enter
+          key.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>execute</literal>
+      </term>
+      <listitem>
+        <para>
+          Execute a shell command, returning a list
+          <literal>(status, stdout)</literal>.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>succeed</literal>
+      </term>
+      <listitem>
+        <para>
+          Execute a shell command, raising an exception if the exit
+          status is not zero, otherwise returning the standard output.
+          Commands are run with <literal>set -euo pipefail</literal>
+          set:
+        </para>
+        <itemizedlist>
+          <listitem>
+            <para>
+              If several commands are separated by <literal>;</literal>
+              and one fails, the command as a whole will fail.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              For pipelines, the last non-zero exit status will be
+              returned (if there is one, zero will be returned
+              otherwise).
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              Dereferencing unset variables fail the command.
+            </para>
+          </listitem>
+        </itemizedlist>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>fail</literal>
+      </term>
+      <listitem>
+        <para>
+          Like <literal>succeed</literal>, but raising an exception if
+          the command returns a zero status.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_until_succeeds</literal>
+      </term>
+      <listitem>
+        <para>
+          Repeat a shell command with 1-second intervals until it
+          succeeds.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_until_fails</literal>
+      </term>
+      <listitem>
+        <para>
+          Repeat a shell command with 1-second intervals until it fails.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_unit</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until the specified systemd unit has reached the
+          <quote>active</quote> state.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_file</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until the specified file exists.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_open_port</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until a process is listening on the given TCP port (on
+          <literal>localhost</literal>, at least).
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_closed_port</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until nobody is listening on the given TCP port.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_x</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until the X11 server is accepting connections.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_text</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until the supplied regular expressions matches the
+          textual contents of the screen by using optical character
+          recognition (see <literal>get_screen_text</literal> and
+          <literal>get_screen_text_variants</literal>).
+        </para>
+        <note>
+          <para>
+            This requires passing <literal>enableOCR</literal> to the
+            test attribute set.
+          </para>
+        </note>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_console_text</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until the supplied regular expressions match a line of
+          the serial console output. This method is useful when OCR is
+          not possibile or accurate enough.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>wait_for_window</literal>
+      </term>
+      <listitem>
+        <para>
+          Wait until an X11 window has appeared whose name matches the
+          given regular expression, e.g.,
+          <literal>wait_for_window(&quot;Terminal&quot;)</literal>.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>copy_from_host</literal>
+      </term>
+      <listitem>
+        <para>
+          Copies a file from host to machine, e.g.,
+          <literal>copy_from_host(&quot;myfile&quot;, &quot;/etc/my/important/file&quot;)</literal>.
+        </para>
+        <para>
+          The first argument is the file on the host. The file needs to
+          be accessible while building the nix derivation. The second
+          argument is the location of the file on the machine.
+        </para>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>systemctl</literal>
+      </term>
+      <listitem>
+        <para>
+          Runs <literal>systemctl</literal> commands with optional
+          support for <literal>systemctl --user</literal>
+        </para>
+        <programlisting language="python">
+machine.systemctl(&quot;list-jobs --no-pager&quot;) # runs `systemctl list-jobs --no-pager`
+machine.systemctl(&quot;list-jobs --no-pager&quot;, &quot;any-user&quot;) # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
+</programlisting>
+      </listitem>
+    </varlistentry>
+    <varlistentry>
+      <term>
+        <literal>shell_interact</literal>
+      </term>
+      <listitem>
+        <para>
+          Allows you to directly interact with the guest shell. This
+          should only be used during test development, not in production
+          tests. Killing the interactive session with
+          <literal>Ctrl-d</literal> or <literal>Ctrl-c</literal> also
+          ends the guest session.
+        </para>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+  <para>
+    To test user units declared by
+    <literal>systemd.user.services</literal> the optional
+    <literal>user</literal> argument can be used:
+  </para>
+  <programlisting language="python">
+machine.start()
+machine.wait_for_x()
+machine.wait_for_unit(&quot;xautolock.service&quot;, &quot;x-session-user&quot;)
+</programlisting>
+  <para>
+    This applies to <literal>systemctl</literal>,
+    <literal>get_unit_info</literal>, <literal>wait_for_unit</literal>,
+    <literal>start_job</literal> and <literal>stop_job</literal>.
+  </para>
+  <para>
+    For faster dev cycles it's also possible to disable the code-linters
+    (this shouldn't be commited though):
+  </para>
+  <programlisting language="bash">
+import ./make-test-python.nix {
+  skipLint = true;
+  machine =
+    { config, pkgs, ... }:
+    { configuration…
+    };
+
+  testScript =
+    ''
+      Python code…
+    '';
+}
+</programlisting>
+  <para>
+    This will produce a Nix warning at evaluation time. To fully disable
+    the linter, wrap the test script in comment directives to disable
+    the Black linter directly (again, don't commit this within the
+    Nixpkgs repository):
+  </para>
+  <programlisting language="bash">
+  testScript =
+    ''
+      # fmt: off
+      Python code…
+      # fmt: on
+    '';
+</programlisting>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2105.section.xml b/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2105.section.xml
index e043bee7761d..f4155d6f8ce6 100644
--- a/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2105.section.xml
+++ b/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2105.section.xml
@@ -101,16 +101,18 @@
       <listitem>
         <para>
           <link xlink:href="https://www.gnuradio.org/">GNURadio</link>
-          3.8 was
+          3.8 and 3.9 were
           <link xlink:href="https://github.com/NixOS/nixpkgs/issues/82263">finally</link>
           packaged, along with a rewrite to the Nix expressions,
           allowing users to override the features upstream supports
           selecting to compile or not to. Additionally, the attribute
-          <literal>gnuradio</literal> and <literal>gnuradio3_7</literal>
-          now point to an externally wrapped by default derivations,
-          that allow you to also add `extraPythonPackages` to the Python
-          interpreter used by GNURadio. Missing environmental variables
-          needed for operational GUI were also added
+          <literal>gnuradio</literal> (3.9),
+          <literal>gnuradio3_8</literal> and
+          <literal>gnuradio3_7</literal> now point to an externally
+          wrapped by default derivations, that allow you to also add
+          `extraPythonPackages` to the Python interpreter used by
+          GNURadio. Missing environmental variables needed for
+          operational GUI were also added
           (<link xlink:href="https://github.com/NixOS/nixpkgs/issues/75478">#75478</link>).
         </para>
       </listitem>
@@ -1026,7 +1028,7 @@ self: super:
         <para>
           <link xlink:href="https://kodi.tv/">Kodi</link> has been
           updated to version 19.1 &quot;Matrix&quot;. See the
-          <link xlink:href="https://kodi.tv/article/kodi-190-matrix-release">announcement</link>
+          <link xlink:href="https://kodi.tv/article/kodi-19-0-matrix-release">announcement</link>
           for further details.
         </para>
       </listitem>
diff --git a/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
index 896a797cefbd..a95b1dd66b96 100644
--- a/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
+++ b/nixpkgs/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
@@ -27,6 +27,15 @@
     <itemizedlist>
       <listitem>
         <para>
+          <link xlink:href="https://digint.ch/btrbk/index.html">btrbk</link>,
+          a backup tool for btrfs subvolumes, taking advantage of btrfs
+          specific capabilities to create atomic snapshots and transfer
+          them incrementally to your backup locations. Available as
+          <link xlink:href="options.html#opt-services.brtbk.instances">services.btrbk</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://github.com/maxmind/geoipupdate">geoipupdate</link>,
           a GeoIP database updater from MaxMind. Available as
           <link xlink:href="options.html#opt-services.geoipupdate.enable">services.geoipupdate</link>.
@@ -48,6 +57,14 @@
           <link xlink:href="options.html#opt-networking.ucarp.enable">networking.ucarp</link>.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          Users of flashrom should migrate to
+          <link xlink:href="options.html#opt-programs.flashrom.enable">programs.flashrom.enable</link>
+          and add themselves to the <literal>flashrom</literal> group to
+          be able to access programmers supported by flashrom.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-21.11-incompatibilities">
@@ -56,7 +73,7 @@
       <listitem>
         <para>
           The <literal>staticjinja</literal> package has been upgraded
-          from 1.0.4 to 2.0.0
+          from 1.0.4 to 3.0.1
         </para>
       </listitem>
       <listitem>
@@ -331,6 +348,126 @@
           release instead of the old 2.31.0 version.
         </para>
       </listitem>
+      <listitem>
+        <para>
+          The <literal>bitwarden_rs</literal> packages and modules were
+          renamed to <literal>vaultwarden</literal>
+          <link xlink:href="https://github.com/dani-garcia/vaultwarden/discussions/1642">following
+          upstream</link>. More specifically,
+        </para>
+        <itemizedlist>
+          <listitem>
+            <para>
+              <literal>pkgs.bitwarden_rs</literal>,
+              <literal>pkgs.bitwarden_rs-sqlite</literal>,
+              <literal>pkgs.bitwarden_rs-mysql</literal> and
+              <literal>pkgs.bitwarden_rs-postgresql</literal> were
+              renamed to <literal>pkgs.vaultwarden</literal>,
+              <literal>pkgs.vaultwarden-sqlite</literal>,
+              <literal>pkgs.vaultwarden-mysql</literal> and
+              <literal>pkgs.vaultwarden-postgresql</literal>,
+              respectively.
+            </para>
+            <itemizedlist spacing="compact">
+              <listitem>
+                <para>
+                  Old names are preserved as aliases for backwards
+                  compatibility, but may be removed in the future.
+                </para>
+              </listitem>
+              <listitem>
+                <para>
+                  The <literal>bitwarden_rs</literal> executable was
+                  also renamed to <literal>vaultwarden</literal> in all
+                  packages.
+                </para>
+              </listitem>
+            </itemizedlist>
+          </listitem>
+          <listitem>
+            <para>
+              <literal>pkgs.bitwarden_rs-vault</literal> was renamed to
+              <literal>pkgs.vaultwarden-vault</literal>.
+            </para>
+            <itemizedlist spacing="compact">
+              <listitem>
+                <para>
+                  <literal>pkgs.bitwarden_rs-vault</literal> is
+                  preserved as an alias for backwards compatibility, but
+                  may be removed in the future.
+                </para>
+              </listitem>
+              <listitem>
+                <para>
+                  The static files were moved from
+                  <literal>/usr/share/bitwarden_rs</literal> to
+                  <literal>/usr/share/vaultwarden</literal>.
+                </para>
+              </listitem>
+            </itemizedlist>
+          </listitem>
+          <listitem>
+            <para>
+              The <literal>services.bitwarden_rs</literal> config module
+              was renamed to <literal>services.vaultwarden</literal>.
+            </para>
+            <itemizedlist spacing="compact">
+              <listitem>
+                <para>
+                  <literal>services.bitwarden_rs</literal> is preserved
+                  as an alias for backwards compatibility, but may be
+                  removed in the future.
+                </para>
+              </listitem>
+            </itemizedlist>
+          </listitem>
+          <listitem>
+            <para>
+              <literal>systemd.services.bitwarden_rs</literal>,
+              <literal>systemd.services.backup-bitwarden_rs</literal>
+              and <literal>systemd.timers.backup-bitwarden_rs</literal>
+              were renamed to
+              <literal>systemd.services.vaultwarden</literal>,
+              <literal>systemd.services.backup-vaultwarden</literal> and
+              <literal>systemd.timers.backup-vaultwarden</literal>,
+              respectively.
+            </para>
+            <itemizedlist spacing="compact">
+              <listitem>
+                <para>
+                  Old names are preserved as aliases for backwards
+                  compatibility, but may be removed in the future.
+                </para>
+              </listitem>
+            </itemizedlist>
+          </listitem>
+          <listitem>
+            <para>
+              <literal>users.users.bitwarden_rs</literal> and
+              <literal>users.groups.bitwarden_rs</literal> were renamed
+              to <literal>users.users.vaultwarden</literal> and
+              <literal>users.groups.vaultwarden</literal>, respectively.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              The data directory remains located at
+              <literal>/var/lib/bitwarden_rs</literal>, for backwards
+              compatibility.
+            </para>
+          </listitem>
+        </itemizedlist>
+      </listitem>
+    </itemizedlist>
+    <itemizedlist spacing="compact">
+      <listitem>
+        <para>
+          <literal>yggdrasil</literal> was upgraded to a new major
+          release with breaking changes, see
+          <link xlink:href="https://github.com/yggdrasil-network/yggdrasil-go/releases/tag/v0.4.0">upstream
+          changelog</link>.
+        </para>
+      </listitem>
     </itemizedlist>
   </section>
   <section xml:id="sec-release-21.11-notable-changes">
diff --git a/nixpkgs/nixos/doc/manual/installation/installing.xml b/nixpkgs/nixos/doc/manual/installation/installing.xml
index f03b9443d23b..d019bb318096 100644
--- a/nixpkgs/nixos/doc/manual/installation/installing.xml
+++ b/nixpkgs/nixos/doc/manual/installation/installing.xml
@@ -446,8 +446,8 @@
      password for the <literal>root</literal> user, e.g.
 <screen>
 setting root password...
-Enter new UNIX password: ***
-Retype new UNIX password: ***</screen>
+New password: ***
+Retype new password: ***</screen>
      <note>
       <para>
        For unattended installations, it is possible to use
diff --git a/nixpkgs/nixos/doc/manual/preface.xml b/nixpkgs/nixos/doc/manual/preface.xml
index 0f7db6ef1a82..ded6bdc87deb 100644
--- a/nixpkgs/nixos/doc/manual/preface.xml
+++ b/nixpkgs/nixos/doc/manual/preface.xml
@@ -20,8 +20,8 @@
   <literal
    xlink:href="https://discourse.nixos.org">Discourse</literal> or
   on the <link
-   xlink:href="irc://irc.freenode.net/#nixos">
-  <literal>#nixos</literal> channel on Freenode</link>, or
+   xlink:href="irc://irc.libera.chat/#nixos">
+  <literal>#nixos</literal> channel on Libera.Chat</link>, or
   consider
   <link
    xlink:href="#chap-contributing">
diff --git a/nixpkgs/nixos/doc/manual/release-notes/rl-2105.section.md b/nixpkgs/nixos/doc/manual/release-notes/rl-2105.section.md
index e4565b8ca605..49b97c203fe6 100644
--- a/nixpkgs/nixos/doc/manual/release-notes/rl-2105.section.md
+++ b/nixpkgs/nixos/doc/manual/release-notes/rl-2105.section.md
@@ -36,7 +36,7 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 The following new services were added since the last release:
 
-- [GNURadio](https://www.gnuradio.org/) 3.8 was [finally](https://github.com/NixOS/nixpkgs/issues/82263) packaged, along with a rewrite to the Nix expressions, allowing users to override the features upstream supports selecting to compile or not to. Additionally, the attribute `gnuradio` and `gnuradio3_7` now point to an externally wrapped by default derivations, that allow you to also add \`extraPythonPackages\` to the Python interpreter used by GNURadio. Missing environmental variables needed for operational GUI were also added ([\#75478](https://github.com/NixOS/nixpkgs/issues/75478)).
+- [GNURadio](https://www.gnuradio.org/) 3.8 and 3.9 were [finally](https://github.com/NixOS/nixpkgs/issues/82263) packaged, along with a rewrite to the Nix expressions, allowing users to override the features upstream supports selecting to compile or not to. Additionally, the attribute `gnuradio` (3.9), `gnuradio3_8` and `gnuradio3_7` now point to an externally wrapped by default derivations, that allow you to also add \`extraPythonPackages\` to the Python interpreter used by GNURadio. Missing environmental variables needed for operational GUI were also added ([\#75478](https://github.com/NixOS/nixpkgs/issues/75478)).
 
 - [Keycloak](https://www.keycloak.org/), an open source identity and access management server with support for [OpenID Connect](https://openid.net/connect/), [OAUTH 2.0](https://oauth.net/2/) and [SAML 2.0](https://en.wikipedia.org/wiki/SAML_2.0).
 
@@ -300,7 +300,7 @@ When upgrading from a previous release, please be aware of the following incompa
 
   Regarding the NixOS module, new options for HTTPS inspection have been added and `services.privoxy.extraConfig` has been replaced by the new [services.privoxy.settings](options.html#opt-services.privoxy.settings) (See [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) for the motivation).
 
-- [Kodi](https://kodi.tv/) has been updated to version 19.1 \"Matrix\". See the [announcement](https://kodi.tv/article/kodi-190-matrix-release) for further details.
+- [Kodi](https://kodi.tv/) has been updated to version 19.1 \"Matrix\". See the [announcement](https://kodi.tv/article/kodi-19-0-matrix-release) for further details.
 
 - The `services.packagekit.backend` option has been removed as it only supported a single setting which would always be the default. Instead new [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) compliant [services.packagekit.settings](options.html#opt-services.packagekit.settings) and [services.packagekit.vendorSettings](options.html#opt-services.packagekit.vendorSettings) options have been introduced.
 
diff --git a/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md b/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md
index afb129960411..be46591dfa16 100644
--- a/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md
+++ b/nixpkgs/nixos/doc/manual/release-notes/rl-2111.section.md
@@ -10,15 +10,19 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 ## New Services {#sec-release-21.11-new-services}
 
+- [btrbk](https://digint.ch/btrbk/index.html), a backup tool for btrfs subvolumes, taking advantage of btrfs specific capabilities to create atomic snapshots and transfer them incrementally to your backup locations. Available as [services.btrbk](options.html#opt-services.brtbk.instances).
+
 - [geoipupdate](https://github.com/maxmind/geoipupdate), a GeoIP database updater from MaxMind. Available as [services.geoipupdate](options.html#opt-services.geoipupdate.enable).
 
 - [sourcehut](https://sr.ht), a collection of tools useful for software development. Available as [services.sourcehut](options.html#opt-services.sourcehut.enable).
 
 - [ucarp](https://download.pureftpd.org/pub/ucarp/README), an userspace implementation of the Common Address Redundancy Protocol (CARP). Available as [networking.ucarp](options.html#opt-networking.ucarp.enable).
 
+- Users of flashrom should migrate to [programs.flashrom.enable](options.html#opt-programs.flashrom.enable) and add themselves to the `flashrom` group to be able to access programmers supported by flashrom.
+
 ## Backward Incompatibilities {#sec-release-21.11-incompatibilities}
 
-- The `staticjinja` package has been upgraded from 1.0.4 to 2.0.0
+- The `staticjinja` package has been upgraded from 1.0.4 to 3.0.1
 
 - `services.geoip-updater` was broken and has been replaced by [services.geoipupdate](options.html#opt-services.geoipupdate.enable).
 
@@ -83,6 +87,34 @@ In addition to numerous new and upgraded packages, this release has the followin
 * The `libwnck` package now defaults to the 3.x release instead of the
   old 2.31.0 version.
 
+* The `bitwarden_rs` packages and modules were renamed to `vaultwarden`
+  [following upstream](https://github.com/dani-garcia/vaultwarden/discussions/1642). More specifically,
+
+  * `pkgs.bitwarden_rs`, `pkgs.bitwarden_rs-sqlite`, `pkgs.bitwarden_rs-mysql` and
+    `pkgs.bitwarden_rs-postgresql` were renamed to `pkgs.vaultwarden`, `pkgs.vaultwarden-sqlite`,
+    `pkgs.vaultwarden-mysql` and `pkgs.vaultwarden-postgresql`, respectively.
+    * Old names are preserved as aliases for backwards compatibility, but may be removed in the future.
+    * The `bitwarden_rs` executable was also renamed to `vaultwarden` in all packages.
+
+  * `pkgs.bitwarden_rs-vault` was renamed to `pkgs.vaultwarden-vault`.
+    * `pkgs.bitwarden_rs-vault` is preserved as an alias for backwards compatibility, but may be removed in the future.
+    * The static files were moved from `/usr/share/bitwarden_rs` to `/usr/share/vaultwarden`.
+
+  * The `services.bitwarden_rs` config module was renamed to `services.vaultwarden`.
+    * `services.bitwarden_rs` is preserved as an alias for backwards compatibility, but may be removed in the future.
+
+  * `systemd.services.bitwarden_rs`, `systemd.services.backup-bitwarden_rs` and `systemd.timers.backup-bitwarden_rs`
+    were renamed to `systemd.services.vaultwarden`, `systemd.services.backup-vaultwarden` and
+    `systemd.timers.backup-vaultwarden`, respectively.
+    * Old names are preserved as aliases for backwards compatibility, but may be removed in the future.
+
+  * `users.users.bitwarden_rs` and `users.groups.bitwarden_rs` were renamed to `users.users.vaultwarden` and
+    `users.groups.vaultwarden`, respectively.
+
+  * The data directory remains located at `/var/lib/bitwarden_rs`, for backwards compatibility.
+
+- `yggdrasil` was upgraded to a new major release with breaking changes, see [upstream changelog](https://github.com/yggdrasil-network/yggdrasil-go/releases/tag/v0.4.0).
+
 ## Other Notable Changes {#sec-release-21.11-notable-changes}
 
 - The setting [`services.openssh.logLevel`](options.html#opt-services.openssh.logLevel) `"VERBOSE"` `"INFO"`. This brings NixOS in line with upstream and other Linux distributions, and reduces log spam on servers due to bruteforcing botnets.
diff --git a/nixpkgs/nixos/modules/config/shells-environment.nix b/nixpkgs/nixos/modules/config/shells-environment.nix
index a0a20228a742..34e558d8603d 100644
--- a/nixpkgs/nixos/modules/config/shells-environment.nix
+++ b/nixpkgs/nixos/modules/config/shells-environment.nix
@@ -126,6 +126,14 @@ in
       type = types.bool;
     };
 
+    environment.localBinInPath = mkOption {
+      description = ''
+        Add ~/.local/bin/ to $PATH
+      '';
+      default = false;
+      type = types.bool;
+    };
+
     environment.binsh = mkOption {
       default = "${config.system.build.binsh}/bin/sh";
       defaultText = "\${config.system.build.binsh}/bin/sh";
@@ -198,6 +206,10 @@ in
           # ~/bin if it exists overrides other bin directories.
           export PATH="$HOME/bin:$PATH"
         ''}
+
+        ${optionalString cfg.localBinInPath ''
+          export PATH="$HOME/.local/bin:$PATH"
+        ''}
       '';
 
     system.activationScripts.binsh = stringAfter [ "stdio" ]
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-base.nix
index 6c7ea293e8ac..aecb65b8c576 100644
--- a/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-base.nix
+++ b/nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-base.nix
@@ -30,5 +30,16 @@ with lib;
   # Add Memtest86+ to the CD.
   boot.loader.grub.memtest86.enable = true;
 
+  boot.postBootCommands = ''
+    for o in $(</proc/cmdline); do
+      case "$o" in
+        live.nixos.passwd=*)
+          set -- $(IFS==; echo $o)
+          echo "nixos:$2" | ${pkgs.shadow}/bin/chpasswd
+          ;;
+      esac
+    done
+  '';
+
   system.stateVersion = mkDefault "18.03";
 }
diff --git a/nixpkgs/nixos/modules/installer/tools/tools.nix b/nixpkgs/nixos/modules/installer/tools/tools.nix
index cb2dbf6c8591..1dc0578daca6 100644
--- a/nixpkgs/nixos/modules/installer/tools/tools.nix
+++ b/nixpkgs/nixos/modules/installer/tools/tools.nix
@@ -40,7 +40,7 @@ let
   };
 
   nixos-option =
-    if lib.versionAtLeast (lib.getVersion pkgs.nix) "2.4pre"
+    if lib.versionAtLeast (lib.getVersion config.nix.package) "2.4pre"
     then null
     else pkgs.callPackage ./nixos-option { };
 
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index 0eeea81967f3..9ea1c3fb62e1 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -138,6 +138,7 @@
   ./programs/file-roller.nix
   ./programs/firejail.nix
   ./programs/fish.nix
+  ./programs/flashrom.nix
   ./programs/flexoptix-app.nix
   ./programs/freetds.nix
   ./programs/fuse.nix
@@ -259,6 +260,7 @@
   ./services/backup/bacula.nix
   ./services/backup/borgbackup.nix
   ./services/backup/borgmatic.nix
+  ./services/backup/btrbk.nix
   ./services/backup/duplicati.nix
   ./services/backup/duplicity.nix
   ./services/backup/mysql-backup.nix
@@ -875,7 +877,6 @@
   ./services/search/hound.nix
   ./services/search/kibana.nix
   ./services/search/solr.nix
-  ./services/security/bitwarden_rs/default.nix
   ./services/security/certmgr.nix
   ./services/security/cfssl.nix
   ./services/security/clamav.nix
@@ -901,6 +902,7 @@
   ./services/security/torsocks.nix
   ./services/security/usbguard.nix
   ./services/security/vault.nix
+  ./services/security/vaultwarden/default.nix
   ./services/security/yubikey-agent.nix
   ./services/system/cloud-init.nix
   ./services/system/dbus.nix
diff --git a/nixpkgs/nixos/modules/programs/flashrom.nix b/nixpkgs/nixos/modules/programs/flashrom.nix
new file mode 100644
index 000000000000..f026c2e31cda
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/flashrom.nix
@@ -0,0 +1,26 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.flashrom;
+in
+{
+  options.programs.flashrom = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Installs flashrom and configures udev rules for programmers
+        used by flashrom. Grants access to users in the "flashrom"
+        group.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.udev.packages = [ pkgs.flashrom ];
+    environment.systemPackages = [ pkgs.flashrom ];
+    users.groups.flashrom = { };
+  };
+}
diff --git a/nixpkgs/nixos/modules/programs/hamster.nix b/nixpkgs/nixos/modules/programs/hamster.nix
index b2f4a82b260e..0bb56ad7ff36 100644
--- a/nixpkgs/nixos/modules/programs/hamster.nix
+++ b/nixpkgs/nixos/modules/programs/hamster.nix
@@ -6,7 +6,7 @@ with lib;
   meta.maintainers = pkgs.hamster.meta.maintainers;
 
   options.programs.hamster.enable =
-    mkEnableOption "Whether to enable hamster time tracking.";
+    mkEnableOption "hamster, a time tracking program";
 
   config = lib.mkIf config.programs.hamster.enable {
     environment.systemPackages = [ pkgs.hamster ];
diff --git a/nixpkgs/nixos/modules/programs/ssmtp.nix b/nixpkgs/nixos/modules/programs/ssmtp.nix
index 8039763faccc..8b500f0383f4 100644
--- a/nixpkgs/nixos/modules/programs/ssmtp.nix
+++ b/nixpkgs/nixos/modules/programs/ssmtp.nix
@@ -124,7 +124,8 @@ in
         example = "/run/keys/ssmtp-authpass";
         description = ''
           Path to a file that contains the password used for SMTP auth. The file
-          should not contain a trailing newline, if the password does not contain one.
+          should not contain a trailing newline, if the password does not contain one
+          (e.g. use <command>echo -n "password" > file</command>).
           This file should be readable by the users that need to execute ssmtp.
         '';
       };
diff --git a/nixpkgs/nixos/modules/programs/zsh/zsh.nix b/nixpkgs/nixos/modules/programs/zsh/zsh.nix
index 049a315c7622..48638fda28da 100644
--- a/nixpkgs/nixos/modules/programs/zsh/zsh.nix
+++ b/nixpkgs/nixos/modules/programs/zsh/zsh.nix
@@ -91,7 +91,7 @@ in
           # before setting your PS1 and etc. Otherwise this will likely to interact with
           # your ~/.zshrc configuration in unexpected ways as the default prompt sets
           # a lot of different prompt variables.
-          autoload -U promptinit && promptinit && prompt walters && setopt prompt_sp
+          autoload -U promptinit && promptinit && prompt suse && setopt prompt_sp
         '';
         description = ''
           Shell script code used to initialise the zsh prompt.
diff --git a/nixpkgs/nixos/modules/security/acme.nix b/nixpkgs/nixos/modules/security/acme.nix
index c0250171109f..22bf34198a30 100644
--- a/nixpkgs/nixos/modules/security/acme.nix
+++ b/nixpkgs/nixos/modules/security/acme.nix
@@ -46,6 +46,7 @@ let
     serviceConfig = commonServiceConfig // {
       StateDirectory = "acme/.minica";
       BindPaths = "/var/lib/acme/.minica:/tmp/ca";
+      UMask = 0077;
     };
 
     # Working directory will be /tmp
@@ -54,8 +55,6 @@ let
         --ca-key ca/key.pem \
         --ca-cert ca/cert.pem \
         --domains selfsigned.local
-
-      chmod 600 ca/*
     '';
   };
 
@@ -196,6 +195,7 @@ let
 
       serviceConfig = commonServiceConfig // {
         Group = data.group;
+        UMask = 0027;
 
         StateDirectory = "acme/${cert}";
 
@@ -220,10 +220,12 @@ let
         cat cert.pem chain.pem > fullchain.pem
         cat key.pem fullchain.pem > full.pem
 
-        chmod 640 *
-
         # Group might change between runs, re-apply it
         chown 'acme:${data.group}' *
+
+        # Default permissions make the files unreadable by group + anon
+        # Need to be readable by group
+        chmod 640 *
       '';
     };
 
@@ -340,8 +342,6 @@ let
         fi
 
         mv domainhash.txt certificates/
-        chmod 640 certificates/*
-        chmod -R u=rwX,g=,o= accounts/*
 
         # Group might change between runs, re-apply it
         chown 'acme:${data.group}' certificates/*
@@ -357,6 +357,10 @@ let
           ln -sf fullchain.pem out/cert.pem
           cat out/key.pem out/fullchain.pem > out/full.pem
         fi
+
+        # By default group will have no access to the cert files.
+        # This chmod will fix that.
+        chmod 640 out/*
       '';
     };
   };
diff --git a/nixpkgs/nixos/modules/security/systemd-confinement.nix b/nixpkgs/nixos/modules/security/systemd-confinement.nix
index afb81a2b56be..0a09a755e93c 100644
--- a/nixpkgs/nixos/modules/security/systemd-confinement.nix
+++ b/nixpkgs/nixos/modules/security/systemd-confinement.nix
@@ -105,7 +105,7 @@ in {
         wantsAPIVFS = lib.mkDefault (config.confinement.mode == "full-apivfs");
       in lib.mkIf config.confinement.enable {
         serviceConfig = {
-          RootDirectory = pkgs.runCommand rootName {} "mkdir \"$out\"";
+          RootDirectory = "/var/empty";
           TemporaryFileSystem = "/";
           PrivateMounts = lib.mkDefault true;
 
diff --git a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
index 646708e01c48..fc8a1bc3c23c 100644
--- a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix
@@ -57,7 +57,7 @@ in {
         description = ''
           Port on which RabbitMQ will listen for AMQP connections.
         '';
-        type = types.int;
+        type = types.port;
       };
 
       dataDir = mkOption {
diff --git a/nixpkgs/nixos/modules/services/audio/slimserver.nix b/nixpkgs/nixos/modules/services/audio/slimserver.nix
index 8f94a2b49404..21632919699c 100644
--- a/nixpkgs/nixos/modules/services/audio/slimserver.nix
+++ b/nixpkgs/nixos/modules/services/audio/slimserver.nix
@@ -63,6 +63,7 @@ in {
         description = "Slimserver daemon user";
         home = cfg.dataDir;
         group = "slimserver";
+        isSystemUser = true;
       };
       groups.slimserver = {};
     };
diff --git a/nixpkgs/nixos/modules/services/backup/btrbk.nix b/nixpkgs/nixos/modules/services/backup/btrbk.nix
new file mode 100644
index 000000000000..a8ff71f609a5
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/backup/btrbk.nix
@@ -0,0 +1,220 @@
+{ config, pkgs, lib, ... }:
+let
+  cfg = config.services.btrbk;
+  sshEnabled = cfg.sshAccess != [ ];
+  serviceEnabled = cfg.instances != { };
+  attr2Lines = attr:
+    let
+      pairs = lib.attrsets.mapAttrsToList (name: value: { inherit name value; }) attr;
+      isSubsection = value:
+        if builtins.isAttrs value then true
+        else if builtins.isString value then false
+        else throw "invalid type in btrbk config ${builtins.typeOf value}";
+      sortedPairs = lib.lists.partition (x: isSubsection x.value) pairs;
+    in
+    lib.flatten (
+      # non subsections go first
+      (
+        map (pair: [ "${pair.name} ${pair.value}" ]) sortedPairs.wrong
+      )
+      ++ # subsections go last
+      (
+        map
+          (
+            pair:
+            lib.mapAttrsToList
+              (
+                childname: value:
+                  [ "${pair.name} ${childname}" ] ++ (map (x: " " + x) (attr2Lines value))
+              )
+              pair.value
+          )
+          sortedPairs.right
+      )
+    )
+  ;
+  addDefaults = settings: { backend = "btrfs-progs-sudo"; } // settings;
+  mkConfigFile = settings: lib.concatStringsSep "\n" (attr2Lines (addDefaults settings));
+  mkTestedConfigFile = name: settings:
+    let
+      configFile = pkgs.writeText "btrbk-${name}.conf" (mkConfigFile settings);
+    in
+    pkgs.runCommand "btrbk-${name}-tested.conf" { } ''
+      mkdir foo
+      cp ${configFile} $out
+      if (set +o pipefail; ${pkgs.btrbk}/bin/btrbk -c $out ls foo 2>&1 | grep $out);
+      then
+      echo btrbk configuration is invalid
+      cat $out
+      exit 1
+      fi;
+    '';
+in
+{
+  options = {
+    services.btrbk = {
+      extraPackages = lib.mkOption {
+        description = "Extra packages for btrbk, like compression utilities for <literal>stream_compress</literal>";
+        type = lib.types.listOf lib.types.package;
+        default = [ ];
+        example = lib.literalExample "[ pkgs.xz ]";
+      };
+      niceness = lib.mkOption {
+        description = "Niceness for local instances of btrbk. Also applies to remote ones connecting via ssh when positive.";
+        type = lib.types.ints.between (-20) 19;
+        default = 10;
+      };
+      ioSchedulingClass = lib.mkOption {
+        description = "IO scheduling class for btrbk (see ionice(1) for a quick description). Applies to local instances, and remote ones connecting by ssh if set to idle.";
+        type = lib.types.enum [ "idle" "best-effort" "realtime" ];
+        default = "best-effort";
+      };
+      instances = lib.mkOption {
+        description = "Set of btrbk instances. The instance named <literal>btrbk</literal> is the default one.";
+        type = with lib.types;
+          attrsOf (
+            submodule {
+              options = {
+                onCalendar = lib.mkOption {
+                  type = lib.types.str;
+                  default = "daily";
+                  description = "How often this btrbk instance is started. See systemd.time(7) for more information about the format.";
+                };
+                settings = lib.mkOption {
+                  type = let t = lib.types.attrsOf (lib.types.either lib.types.str (t // { description = "instances of this type recursively"; })); in t;
+                  default = { };
+                  example = {
+                    snapshot_preserve_min = "2d";
+                    snapshot_preserve = "14d";
+                    volume = {
+                      "/mnt/btr_pool" = {
+                        target = "/mnt/btr_backup/mylaptop";
+                        subvolume = {
+                          "rootfs" = { };
+                          "home" = { snapshot_create = "always"; };
+                        };
+                      };
+                    };
+                  };
+                  description = "configuration options for btrbk. Nested attrsets translate to subsections.";
+                };
+              };
+            }
+          );
+        default = { };
+      };
+      sshAccess = lib.mkOption {
+        description = "SSH keys that should be able to make or push snapshots on this system remotely with btrbk";
+        type = with lib.types; listOf (
+          submodule {
+            options = {
+              key = lib.mkOption {
+                type = str;
+                description = "SSH public key allowed to login as user <literal>btrbk</literal> to run remote backups.";
+              };
+              roles = lib.mkOption {
+                type = listOf (enum [ "info" "source" "target" "delete" "snapshot" "send" "receive" ]);
+                example = [ "source" "info" "send" ];
+                description = "What actions can be performed with this SSH key. See ssh_filter_btrbk(1) for details";
+              };
+            };
+          }
+        );
+        default = [ ];
+      };
+    };
+
+  };
+  config = lib.mkIf (sshEnabled || serviceEnabled) {
+    environment.systemPackages = [ pkgs.btrbk ] ++ cfg.extraPackages;
+    security.sudo.extraRules = [
+      {
+        users = [ "btrbk" ];
+        commands = [
+          { command = "${pkgs.btrfs-progs}/bin/btrfs"; options = [ "NOPASSWD" ]; }
+          { command = "${pkgs.coreutils}/bin/mkdir"; options = [ "NOPASSWD" ]; }
+          { command = "${pkgs.coreutils}/bin/readlink"; options = [ "NOPASSWD" ]; }
+          # for ssh, they are not the same than the one hard coded in ${pkgs.btrbk}
+          { command = "/run/current-system/bin/btrfs"; options = [ "NOPASSWD" ]; }
+          { command = "/run/current-system/sw/bin/mkdir"; options = [ "NOPASSWD" ]; }
+          { command = "/run/current-system/sw/bin/readlink"; options = [ "NOPASSWD" ]; }
+        ];
+      }
+    ];
+    users.users.btrbk = {
+      isSystemUser = true;
+      # ssh needs a home directory
+      home = "/var/lib/btrbk";
+      createHome = true;
+      shell = "${pkgs.bash}/bin/bash";
+      group = "btrbk";
+      openssh.authorizedKeys.keys = map
+        (
+          v:
+          let
+            options = lib.concatMapStringsSep " " (x: "--" + x) v.roles;
+            ioniceClass = {
+              "idle" = 3;
+              "best-effort" = 2;
+              "realtime" = 1;
+            }.${cfg.ioSchedulingClass};
+          in
+          ''command="${pkgs.util-linux}/bin/ionice -t -c ${toString ioniceClass} ${lib.optionalString (cfg.niceness >= 1) "${pkgs.coreutils}/bin/nice -n ${toString cfg.niceness}"} ${pkgs.btrbk}/share/btrbk/scripts/ssh_filter_btrbk.sh --sudo ${options}" ${v.key}''
+        )
+        cfg.sshAccess;
+    };
+    users.groups.btrbk = { };
+    systemd.tmpfiles.rules = [
+      "d /var/lib/btrbk 0750 btrbk btrbk"
+      "d /var/lib/btrbk/.ssh 0700 btrbk btrbk"
+      "f /var/lib/btrbk/.ssh/config 0700 btrbk btrbk - StrictHostKeyChecking=accept-new"
+    ];
+    environment.etc = lib.mapAttrs'
+      (
+        name: instance: {
+          name = "btrbk/${name}.conf";
+          value.source = mkTestedConfigFile name instance.settings;
+        }
+      )
+      cfg.instances;
+    systemd.services = lib.mapAttrs'
+      (
+        name: _: {
+          name = "btrbk-${name}";
+          value = {
+            description = "Takes BTRFS snapshots and maintains retention policies.";
+            unitConfig.Documentation = "man:btrbk(1)";
+            path = [ "/run/wrappers" ] ++ cfg.extraPackages;
+            serviceConfig = {
+              User = "btrbk";
+              Group = "btrbk";
+              Type = "oneshot";
+              ExecStart = "${pkgs.btrbk}/bin/btrbk -c /etc/btrbk/${name}.conf run";
+              Nice = cfg.niceness;
+              IOSchedulingClass = cfg.ioSchedulingClass;
+              StateDirectory = "btrbk";
+            };
+          };
+        }
+      )
+      cfg.instances;
+
+    systemd.timers = lib.mapAttrs'
+      (
+        name: instance: {
+          name = "btrbk-${name}";
+          value = {
+            description = "Timer to take BTRFS snapshots and maintain retention policies.";
+            wantedBy = [ "timers.target" ];
+            timerConfig = {
+              OnCalendar = instance.onCalendar;
+              AccuracySec = "10min";
+              Persistent = true;
+            };
+          };
+        }
+      )
+      cfg.instances;
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/backup/sanoid.nix b/nixpkgs/nixos/modules/services/backup/sanoid.nix
index 0472fb4ba1e7..be44a43b6d3f 100644
--- a/nixpkgs/nixos/modules/services/backup/sanoid.nix
+++ b/nixpkgs/nixos/modules/services/backup/sanoid.nix
@@ -10,74 +10,51 @@ let
       description = "dataset/template options";
     };
 
-  # Default values from https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf
-
   commonOptions = {
     hourly = mkOption {
       description = "Number of hourly snapshots.";
-      type = types.ints.unsigned;
-      default = 48;
+      type = with types; nullOr ints.unsigned;
+      default = null;
     };
 
     daily = mkOption {
       description = "Number of daily snapshots.";
-      type = types.ints.unsigned;
-      default = 90;
+      type = with types; nullOr ints.unsigned;
+      default = null;
     };
 
     monthly = mkOption {
       description = "Number of monthly snapshots.";
-      type = types.ints.unsigned;
-      default = 6;
+      type = with types; nullOr ints.unsigned;
+      default = null;
     };
 
     yearly = mkOption {
       description = "Number of yearly snapshots.";
-      type = types.ints.unsigned;
-      default = 0;
+      type = with types; nullOr ints.unsigned;
+      default = null;
     };
 
     autoprune = mkOption {
       description = "Whether to automatically prune old snapshots.";
-      type = types.bool;
-      default = true;
+      type = with types; nullOr bool;
+      default = null;
     };
 
     autosnap = mkOption {
       description = "Whether to automatically take snapshots.";
-      type = types.bool;
-      default = true;
-    };
-
-    settings = mkOption {
-      description = ''
-        Free-form settings for this template/dataset. See
-        <link xlink:href="https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf"/>
-        for allowed values.
-      '';
-      type = datasetSettingsType;
-    };
-  };
-
-  commonConfig = config: {
-    settings = {
-      hourly = mkDefault config.hourly;
-      daily = mkDefault config.daily;
-      monthly = mkDefault config.monthly;
-      yearly = mkDefault config.yearly;
-      autoprune = mkDefault config.autoprune;
-      autosnap = mkDefault config.autosnap;
+      type = with types; nullOr bool;
+      default = null;
     };
   };
 
-  datasetOptions = {
-    useTemplate = mkOption {
+  datasetOptions = rec {
+    use_template = mkOption {
       description = "Names of the templates to use for this dataset.";
-      type = (types.listOf (types.enum (attrNames cfg.templates))) // {
-        description = "list of template names";
-      };
+      type = types.listOf (types.enum (attrNames cfg.templates));
       default = [];
     };
+    useTemplate = use_template;
 
     recursive = mkOption {
       description = "Whether to recursively snapshot dataset children.";
@@ -85,19 +62,12 @@ let
       default = false;
     };
 
-    processChildrenOnly = mkOption {
+    process_children_only = mkOption {
       description = "Whether to only snapshot child datasets if recursing.";
       type = types.bool;
       default = false;
     };
-  };
-
-  datasetConfig = config: {
-    settings = {
-      use_template = mkDefault config.useTemplate;
-      recursive = mkDefault config.recursive;
-      process_children_only = mkDefault config.processChildrenOnly;
-    };
+    processChildrenOnly = process_children_only;
   };
 
   # Extract pool names from configured datasets
@@ -109,11 +79,11 @@ let
       else generators.mkValueStringDefault {} v;
 
     mkKeyValue = k: v: if v == null then ""
+      else if k == "processChildrenOnly" then ""
+      else if k == "useTemplate" then ""
       else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v;
   in generators.toINI { inherit mkKeyValue; } cfg.settings;
 
-  configDir = pkgs.writeTextDir "sanoid.conf" configFile;
-
 in {
 
     # Interface
@@ -135,19 +105,21 @@ in {
       };
 
       datasets = mkOption {
-        type = types.attrsOf (types.submodule ({ config, ... }: {
+        type = types.attrsOf (types.submodule ({config, options, ...}: {
+          freeformType = datasetSettingsType;
           options = commonOptions // datasetOptions;
-          config = mkMerge [ (commonConfig config) (datasetConfig config) ];
+          config.use_template = mkAliasDefinitions (options.useTemplate or {});
+          config.process_children_only = mkAliasDefinitions (options.processChildrenOnly or {});
         }));
         default = {};
         description = "Datasets to snapshot.";
       };
 
       templates = mkOption {
-        type = types.attrsOf (types.submodule ({ config, ... }: {
+        type = types.attrsOf (types.submodule {
+          freeformType = datasetSettingsType;
           options = commonOptions;
-          config = commonConfig config;
-        }));
+        });
         default = {};
         description = "Templates for datasets.";
       };
@@ -177,8 +149,8 @@ in {
 
     config = mkIf cfg.enable {
       services.sanoid.settings = mkMerge [
-        (mapAttrs' (d: v: nameValuePair ("template_" + d) v.settings) cfg.templates)
-        (mapAttrs (d: v: v.settings) cfg.datasets)
+        (mapAttrs' (d: v: nameValuePair ("template_" + d) v) cfg.templates)
+        (mapAttrs (d: v: v) cfg.datasets)
       ];
 
       systemd.services.sanoid = {
@@ -191,7 +163,7 @@ in {
           ExecStart = lib.escapeShellArgs ([
             "${pkgs.sanoid}/bin/sanoid"
             "--cron"
-            "--configdir" configDir
+            "--configdir" (pkgs.writeTextDir "sanoid.conf" configFile)
           ] ++ cfg.extraArgs);
           ExecStopPost = map (pool: lib.escapeShellArgs [
             "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" pool
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
index 8de6a3ba0d80..d9311d3e3a04 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix
@@ -189,6 +189,7 @@ in
         # manually paste it in place. Just symlink.
         # otherwise, create the target file, ready for users to insert the token
 
+        mkdir -p $(dirname ${certmgrAPITokenPath})
         if [ -f "${cfsslAPITokenPath}" ]; then
           ln -fs "${cfsslAPITokenPath}" "${certmgrAPITokenPath}"
         else
diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix
index 7aa449f9aa21..42729f54643b 100644
--- a/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix
+++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix
@@ -59,7 +59,7 @@ in
       description = "Kubernetes Proxy Service";
       wantedBy = [ "kubernetes.target" ];
       after = [ "kube-apiserver.service" ];
-      path = with pkgs; [ iptables conntrack_tools ];
+      path = with pkgs; [ iptables conntrack-tools ];
       serviceConfig = {
         Slice = "kubernetes.slice";
         ExecStart = ''${top.package}/bin/kube-proxy \
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix
index cdc3b4b5c58f..889688a26853 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -2,6 +2,7 @@
 with lib;
 let
   cfg = config.services.jenkins;
+  jenkinsUrl = "http://${cfg.listenAddress}:${toString cfg.port}${cfg.prefix}";
 in {
   options = {
     services.jenkins = {
@@ -141,14 +142,34 @@ in {
           Additional command line arguments to pass to the Java run time (as opposed to Jenkins).
         '';
       };
+
+      withCLI = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to make the CLI available.
+
+          More info about the CLI available at
+          <link xlink:href="https://www.jenkins.io/doc/book/managing/cli">
+          https://www.jenkins.io/doc/book/managing/cli</link> .
+        '';
+      };
     };
   };
 
   config = mkIf cfg.enable {
-    # server references the dejavu fonts
-    environment.systemPackages = [
-      pkgs.dejavu_fonts
-    ];
+    environment = {
+      # server references the dejavu fonts
+      systemPackages = [
+        pkgs.dejavu_fonts
+      ] ++ optional cfg.withCLI cfg.package;
+
+      variables = {}
+        // optionalAttrs cfg.withCLI {
+          # Make it more convenient to use the `jenkins-cli`.
+          JENKINS_URL = jenkinsUrl;
+        };
+    };
 
     users.groups = optionalAttrs (cfg.group == "jenkins") {
       jenkins.gid = config.ids.gids.jenkins;
@@ -215,7 +236,7 @@ in {
       '';
 
       postStart = ''
-        until [[ $(${pkgs.curl.bin}/bin/curl -L -s --head -w '\n%{http_code}' http://${cfg.listenAddress}:${toString cfg.port}${cfg.prefix} | tail -n1) =~ ^(200|403)$ ]]; do
+        until [[ $(${pkgs.curl.bin}/bin/curl -L -s --head -w '\n%{http_code}' ${jenkinsUrl} | tail -n1) =~ ^(200|403)$ ]]; do
           sleep 1
         done
       '';
diff --git a/nixpkgs/nixos/modules/services/databases/mysql.nix b/nixpkgs/nixos/modules/services/databases/mysql.nix
index 2d8d613ed88e..b801b5cce635 100644
--- a/nixpkgs/nixos/modules/services/databases/mysql.nix
+++ b/nixpkgs/nixos/modules/services/databases/mysql.nix
@@ -48,7 +48,7 @@ in
       };
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 3306;
         description = "Port of MySQL.";
       };
diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json
new file mode 100644
index 000000000000..7c527b292158
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/desktops/pipewire/bluez-hardware.conf.json
@@ -0,0 +1,197 @@
+{
+  "bluez5.features.device": [
+    {
+      "name": "Air 1 Plus",
+      "no-features": [
+        "hw-volume-mic"
+      ]
+    },
+    {
+      "name": "AirPods",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "name": "AirPods Pro",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "name": "AXLOIE Goin",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "name": "JBL Endurance RUN BT",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl",
+        "sbc-xq"
+      ]
+    },
+    {
+      "name": "JBL LIVE650BTNC"
+    },
+    {
+      "name": "Soundcore Life P2-L",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "name": "Urbanista Stockholm Plus",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "address": "~^94:16:25:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^9c:64:8b:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^a0:e9:db:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^0c:a6:94:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^00:14:02:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^44:5e:f3:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^d4:9c:28:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^00:18:6b:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^b8:ad:3e:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^a0:e9:db:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^00:24:1c:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^00:11:b1:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^a4:15:66:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^00:14:f1:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^00:26:7e:",
+      "no-features": [
+        "hw-volume"
+      ]
+    },
+    {
+      "address": "~^90:03:b7:",
+      "no-features": [
+        "hw-volume"
+      ]
+    }
+  ],
+  "bluez5.features.adapter": [
+    {
+      "bus-type": "usb",
+      "vendor-id": "usb:0bda"
+    },
+    {
+      "bus-type": "usb",
+      "no-features": [
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "no-features": [
+        "msbc-alt1-rtl"
+      ]
+    }
+  ],
+  "bluez5.features.kernel": [
+    {
+      "sysname": "Linux",
+      "release": "~^[0-4]\\.",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "sysname": "Linux",
+      "release": "~^5\\.[1-7]\\.",
+      "no-features": [
+        "msbc-alt1",
+        "msbc-alt1-rtl"
+      ]
+    },
+    {
+      "sysname": "Linux",
+      "release": "~^5\\.(8|9|10)\\.",
+      "no-features": [
+        "msbc-alt1"
+      ]
+    },
+    {
+      "no-features": []
+    }
+  ]
+}
diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/jack.conf.json b/nixpkgs/nixos/modules/services/desktops/pipewire/jack.conf.json
index a6bd34917851..e36e04fffcf2 100644
--- a/nixpkgs/nixos/modules/services/desktops/pipewire/jack.conf.json
+++ b/nixpkgs/nixos/modules/services/desktops/pipewire/jack.conf.json
@@ -7,7 +7,7 @@
   },
   "context.modules": [
     {
-      "name": "libpipewire-module-rtkit",
+      "name": "libpipewire-module-rt",
       "args": {},
       "flags": [
         "ifexists",
diff --git a/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix b/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
index 17a2d49bb1f3..41ab995e3292 100644
--- a/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
+++ b/nixpkgs/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
@@ -15,6 +15,7 @@ let
   defaults = {
     alsa-monitor = (builtins.fromJSON (builtins.readFile ./alsa-monitor.conf.json));
     bluez-monitor = (builtins.fromJSON (builtins.readFile ./bluez-monitor.conf.json));
+    bluez-hardware = (builtins.fromJSON (builtins.readFile ./bluez-hardware.conf.json));
     media-session = (builtins.fromJSON (builtins.readFile ./media-session.conf.json));
     v4l2-monitor = (builtins.fromJSON (builtins.readFile ./v4l2-monitor.conf.json));
   };
@@ -22,6 +23,7 @@ let
   configs = {
     alsa-monitor = recursiveUpdate defaults.alsa-monitor cfg.config.alsa-monitor;
     bluez-monitor = recursiveUpdate defaults.bluez-monitor cfg.config.bluez-monitor;
+    bluez-hardware = defaults.bluez-hardware;
     media-session = recursiveUpdate defaults.media-session cfg.config.media-session;
     v4l2-monitor = recursiveUpdate defaults.v4l2-monitor cfg.config.v4l2-monitor;
   };
@@ -120,6 +122,10 @@ in {
       mkIf config.services.pipewire.pulse.enable {
         source = json.generate "bluez-monitor.conf" configs.bluez-monitor;
       };
+    environment.etc."pipewire/media-session.d/bluez-hardware.conf" =
+      mkIf config.services.pipewire.pulse.enable {
+        source = json.generate "bluez-hardware.conf" configs.bluez-hardware;
+      };
 
     environment.etc."pipewire/media-session.d/with-jack" =
       mkIf config.services.pipewire.jack.enable {
diff --git a/nixpkgs/nixos/modules/services/editors/infinoted.nix b/nixpkgs/nixos/modules/services/editors/infinoted.nix
index 10d868b7f161..3eb0753194dd 100644
--- a/nixpkgs/nixos/modules/services/editors/infinoted.nix
+++ b/nixpkgs/nixos/modules/services/editors/infinoted.nix
@@ -51,7 +51,7 @@ in {
     };
 
     port = mkOption {
-      type = types.int;
+      type = types.port;
       default = 6523;
       description = ''
         Port to listen on
diff --git a/nixpkgs/nixos/modules/services/misc/docker-registry.nix b/nixpkgs/nixos/modules/services/misc/docker-registry.nix
index 1c2e2cc53590..e212f581c28a 100644
--- a/nixpkgs/nixos/modules/services/misc/docker-registry.nix
+++ b/nixpkgs/nixos/modules/services/misc/docker-registry.nix
@@ -58,7 +58,7 @@ in {
     port = mkOption {
       description = "Docker registry port to bind to.";
       default = 5000;
-      type = types.int;
+      type = types.port;
     };
 
     storagePath = mkOption {
diff --git a/nixpkgs/nixos/modules/services/misc/geoipupdate.nix b/nixpkgs/nixos/modules/services/misc/geoipupdate.nix
index 5d87be928d98..3211d4d88e4d 100644
--- a/nixpkgs/nixos/modules/services/misc/geoipupdate.nix
+++ b/nixpkgs/nixos/modules/services/misc/geoipupdate.nix
@@ -99,9 +99,22 @@ in
       LockFile = "/run/geoipupdate/.lock";
     };
 
+    systemd.services.geoipupdate-create-db-dir = {
+      serviceConfig.Type = "oneshot";
+      script = ''
+        mkdir -p ${cfg.settings.DatabaseDirectory}
+        chmod 0755 ${cfg.settings.DatabaseDirectory}
+      '';
+    };
+
     systemd.services.geoipupdate = {
       description = "GeoIP Updater";
-      after = [ "network-online.target" "nss-lookup.target" ];
+      requires = [ "geoipupdate-create-db-dir.service" ];
+      after = [
+        "geoipupdate-create-db-dir.service"
+        "network-online.target"
+        "nss-lookup.target"
+      ];
       wants = [ "network-online.target" ];
       startAt = cfg.interval;
       serviceConfig = {
@@ -119,11 +132,9 @@ in
               };
             };
 
-            geoipupdateConf = pkgs.writeText "discourse.conf" (geoipupdateKeyValue cfg.settings);
+            geoipupdateConf = pkgs.writeText "geoipupdate.conf" (geoipupdateKeyValue cfg.settings);
 
             script = ''
-              mkdir -p "${cfg.settings.DatabaseDirectory}"
-              chmod 755 "${cfg.settings.DatabaseDirectory}"
               chown geoip "${cfg.settings.DatabaseDirectory}"
 
               cp ${geoipupdateConf} /run/geoipupdate/GeoIP.conf
@@ -139,7 +150,38 @@ in
         ReadWritePaths = cfg.settings.DatabaseDirectory;
         RuntimeDirectory = "geoipupdate";
         RuntimeDirectoryMode = 0700;
+        CapabilityBoundingSet = "";
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateUsers = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProcSubset = "pid";
+        SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictRealtime = true;
+        RestrictNamespaces = true;
+        MemoryDenyWriteExecute = true;
+        LockPersonality = true;
+        SystemCallArchitectures = "native";
+      };
+    };
+
+    systemd.timers.geoipupdate-initial-run = {
+      wantedBy = [ "timers.target" ];
+      unitConfig.ConditionPathExists = "!${cfg.settings.DatabaseDirectory}";
+      timerConfig = {
+        Unit = "geoipupdate.service";
+        OnActiveSec = 0;
       };
     };
   };
+
+  meta.maintainers = [ lib.maintainers.talyz ];
 }
diff --git a/nixpkgs/nixos/modules/services/misc/gitea.nix b/nixpkgs/nixos/modules/services/misc/gitea.nix
index 95369ff7ee48..b6c1ca3e61a9 100644
--- a/nixpkgs/nixos/modules/services/misc/gitea.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitea.nix
@@ -82,7 +82,7 @@ in
         };
 
         port = mkOption {
-          type = types.int;
+          type = types.port;
           default = (if !usePostgresql then 3306 else pg.port);
           description = "Database host port.";
         };
diff --git a/nixpkgs/nixos/modules/services/misc/gitlab.nix b/nixpkgs/nixos/modules/services/misc/gitlab.nix
index 237c20e4b7f6..40e35ed1cd16 100644
--- a/nixpkgs/nixos/modules/services/misc/gitlab.nix
+++ b/nixpkgs/nixos/modules/services/misc/gitlab.nix
@@ -140,6 +140,14 @@ let
           port = 3807;
         };
       };
+      registry = lib.optionalAttrs cfg.registry.enable {
+        enabled = true;
+        host = cfg.registry.externalAddress;
+        port = cfg.registry.externalPort;
+        key = cfg.registry.keyFile;
+        api_url = "http://${config.services.dockerRegistry.listenAddress}:${toString config.services.dockerRegistry.port}/";
+        issuer = "gitlab-issuer";
+      };
       extra = {};
       uploads.storage_path = cfg.statePath;
     };
@@ -156,7 +164,7 @@ let
     prometheus_multiproc_dir = "/run/gitlab";
     RAILS_ENV = "production";
     MALLOC_ARENA_MAX = "2";
-  };
+  } // cfg.extraEnv;
 
   gitlab-rake = pkgs.stdenv.mkDerivation {
     name = "gitlab-rake";
@@ -277,6 +285,14 @@ in {
         '';
       };
 
+      extraEnv = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = ''
+          Additional environment variables for the GitLab environment.
+        '';
+      };
+
       backup.startAt = mkOption {
         type = with types; either str (listOf str);
         default = [];
@@ -508,6 +524,58 @@ in {
         '';
       };
 
+      registry = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = "Enable GitLab container registry.";
+        };
+        host = mkOption {
+          type = types.str;
+          default = config.services.gitlab.host;
+          description = "GitLab container registry host name.";
+        };
+        port = mkOption {
+          type = types.int;
+          default = 4567;
+          description = "GitLab container registry port.";
+        };
+        certFile = mkOption {
+          type = types.path;
+          default = null;
+          description = "Path to GitLab container registry certificate.";
+        };
+        keyFile = mkOption {
+          type = types.path;
+          default = null;
+          description = "Path to GitLab container registry certificate-key.";
+        };
+        defaultForProjects = mkOption {
+          type = types.bool;
+          default = cfg.registry.enable;
+          description = "If GitLab container registry should be enabled by default for projects.";
+        };
+        issuer = mkOption {
+          type = types.str;
+          default = "gitlab-issuer";
+          description = "GitLab container registry issuer.";
+        };
+        serviceName = mkOption {
+          type = types.str;
+          default = "container_registry";
+          description = "GitLab container registry service name.";
+        };
+        externalAddress = mkOption {
+          type = types.str;
+          default = "";
+          description = "External address used to access registry from the internet";
+        };
+        externalPort = mkOption {
+          type = types.int;
+          description = "External port used to access registry from the internet";
+        };
+      };
+
       smtp = {
         enable = mkOption {
           type = types.bool;
@@ -905,6 +973,44 @@ in {
       };
     };
 
+    systemd.services.gitlab-registry-cert = optionalAttrs cfg.registry.enable {
+      path = with pkgs; [ openssl ];
+
+      script = ''
+        mkdir -p $(dirname ${cfg.registry.keyFile})
+        mkdir -p $(dirname ${cfg.registry.certFile})
+        openssl req -nodes -newkey rsa:4096 -keyout ${cfg.registry.keyFile} -out /tmp/registry-auth.csr -subj "/CN=${cfg.registry.issuer}"
+        openssl x509 -in /tmp/registry-auth.csr -out ${cfg.registry.certFile} -req -signkey ${cfg.registry.keyFile} -days 3650
+        chown ${cfg.user}:${cfg.group} $(dirname ${cfg.registry.keyFile})
+        chown ${cfg.user}:${cfg.group} $(dirname ${cfg.registry.certFile})
+        chown ${cfg.user}:${cfg.group} ${cfg.registry.keyFile}
+        chown ${cfg.user}:${cfg.group} ${cfg.registry.certFile}
+      '';
+
+      serviceConfig = {
+        ConditionPathExists = "!${cfg.registry.certFile}";
+      };
+    };
+
+    # Ensure Docker Registry launches after the certificate generation job
+    systemd.services.docker-registry = optionalAttrs cfg.registry.enable {
+      wants = [ "gitlab-registry-cert.service" ];
+    };
+
+    # Enable Docker Registry, if GitLab-Container Registry is enabled
+    services.dockerRegistry = optionalAttrs cfg.registry.enable {
+      enable = true;
+      enableDelete = true; # This must be true, otherwise GitLab won't manage it correctly
+      extraConfig = {
+        auth.token = {
+          realm = "http${if cfg.https == true then "s" else ""}://${cfg.host}/jwt/auth";
+          service = cfg.registry.serviceName;
+          issuer = cfg.registry.issuer;
+          rootcertbundle = cfg.registry.certFile;
+        };
+      };
+    };
+
     # Use postfix to send out mails.
     services.postfix.enable = mkDefault (cfg.smtp.enable && cfg.smtp.address == "localhost");
 
diff --git a/nixpkgs/nixos/modules/services/misc/gpsd.nix b/nixpkgs/nixos/modules/services/misc/gpsd.nix
index f954249942a8..fafea10daba7 100644
--- a/nixpkgs/nixos/modules/services/misc/gpsd.nix
+++ b/nixpkgs/nixos/modules/services/misc/gpsd.nix
@@ -62,7 +62,7 @@ in
       };
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 2947;
         description = ''
           The port where to listen for TCP connections.
diff --git a/nixpkgs/nixos/modules/services/misc/leaps.nix b/nixpkgs/nixos/modules/services/misc/leaps.nix
index ef89d3e64d0c..f797218522c5 100644
--- a/nixpkgs/nixos/modules/services/misc/leaps.nix
+++ b/nixpkgs/nixos/modules/services/misc/leaps.nix
@@ -11,7 +11,7 @@ in
     services.leaps = {
       enable = mkEnableOption "leaps";
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 8080;
         description = "A port where leaps listens for incoming http requests";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/mwlib.nix b/nixpkgs/nixos/modules/services/misc/mwlib.nix
index 6b41b552a86d..8dd17c06c0b3 100644
--- a/nixpkgs/nixos/modules/services/misc/mwlib.nix
+++ b/nixpkgs/nixos/modules/services/misc/mwlib.nix
@@ -34,7 +34,7 @@ in
 
       port = mkOption {
         default = 8899;
-        type = types.int;
+        type = types.port;
         description = "Specify port to listen on.";
       }; # nserve.port
 
@@ -68,7 +68,7 @@ in
 
       port = mkOption {
         default = 14311;
-        type = types.int;
+        type = types.port;
         description = "Specify port to listen on.";
       }; # qserve.port
 
@@ -137,7 +137,7 @@ in
 
             port = mkOption {
               default = 8898;
-              type = types.int;
+              type = types.port;
               description = "Port to listen to when serving files from cache.";
             }; # nslave.http.port
 
diff --git a/nixpkgs/nixos/modules/services/misc/octoprint.nix b/nixpkgs/nixos/modules/services/misc/octoprint.nix
index 5a64946f9f63..c926d889b37a 100644
--- a/nixpkgs/nixos/modules/services/misc/octoprint.nix
+++ b/nixpkgs/nixos/modules/services/misc/octoprint.nix
@@ -40,7 +40,7 @@ in
       };
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 5000;
         description = ''
           Port to bind OctoPrint to.
diff --git a/nixpkgs/nixos/modules/services/misc/paperless.nix b/nixpkgs/nixos/modules/services/misc/paperless.nix
index bfaf760fb836..43730b80eb2c 100644
--- a/nixpkgs/nixos/modules/services/misc/paperless.nix
+++ b/nixpkgs/nixos/modules/services/misc/paperless.nix
@@ -67,7 +67,7 @@ in
     };
 
     port = mkOption {
-      type = types.int;
+      type = types.port;
       default = 28981;
       description = "Server port to listen on.";
     };
diff --git a/nixpkgs/nixos/modules/services/misc/redmine.nix b/nixpkgs/nixos/modules/services/misc/redmine.nix
index e0055576d6f6..66c8e558fb04 100644
--- a/nixpkgs/nixos/modules/services/misc/redmine.nix
+++ b/nixpkgs/nixos/modules/services/misc/redmine.nix
@@ -71,7 +71,7 @@ in
       };
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 3000;
         description = "Port on which Redmine is ran.";
       };
diff --git a/nixpkgs/nixos/modules/services/misc/subsonic.nix b/nixpkgs/nixos/modules/services/misc/subsonic.nix
index 152917d345cc..e17a98a5e1de 100644
--- a/nixpkgs/nixos/modules/services/misc/subsonic.nix
+++ b/nixpkgs/nixos/modules/services/misc/subsonic.nix
@@ -28,7 +28,7 @@ let cfg = config.services.subsonic; in {
       };
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 4040;
         description = ''
           The port on which Subsonic will listen for
@@ -37,7 +37,7 @@ let cfg = config.services.subsonic; in {
       };
 
       httpsPort = mkOption {
-        type = types.int;
+        type = types.port;
         default = 0;
         description = ''
           The port on which Subsonic will listen for
diff --git a/nixpkgs/nixos/modules/services/monitoring/grafana.nix b/nixpkgs/nixos/modules/services/monitoring/grafana.nix
index c3e1f72945bf..e0b2624b6cac 100644
--- a/nixpkgs/nixos/modules/services/monitoring/grafana.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/grafana.nix
@@ -292,7 +292,7 @@ in {
     port = mkOption {
       description = "Listening port.";
       default = 3000;
-      type = types.int;
+      type = types.port;
     };
 
     socket = mkOption {
diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
index 6d8dfcce933c..2748571be1f7 100644
--- a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix
@@ -231,9 +231,9 @@ in {
           }
         fi
       '' + optionalString cfg.autoMount ''
-        ipfs --local config Mounts.FuseAllowOther --json true
-        ipfs --local config Mounts.IPFS ${cfg.ipfsMountDir}
-        ipfs --local config Mounts.IPNS ${cfg.ipnsMountDir}
+        ipfs --offline config Mounts.FuseAllowOther --json true
+        ipfs --offline config Mounts.IPFS ${cfg.ipfsMountDir}
+        ipfs --offline config Mounts.IPNS ${cfg.ipnsMountDir}
       '' + concatStringsSep "\n" (collect
             isString
             (mapAttrsRecursive
@@ -243,7 +243,7 @@ in {
                 read value <<EOF
                 ${builtins.toJSON value}
                 EOF
-                ipfs --local config --json "${concatStringsSep "." path}" "$value"
+                ipfs --offline config --json "${concatStringsSep "." path}" "$value"
               '')
               ({ Addresses.API = cfg.apiAddress;
                  Addresses.Gateway = cfg.gatewayAddress;
diff --git a/nixpkgs/nixos/modules/services/networking/coturn.nix b/nixpkgs/nixos/modules/services/networking/coturn.nix
index 1bfbc307c59d..5f7d2893ae27 100644
--- a/nixpkgs/nixos/modules/services/networking/coturn.nix
+++ b/nixpkgs/nixos/modules/services/networking/coturn.nix
@@ -16,6 +16,7 @@ ${lib.optionalString cfg.lt-cred-mech "lt-cred-mech"}
 ${lib.optionalString cfg.no-auth "no-auth"}
 ${lib.optionalString cfg.use-auth-secret "use-auth-secret"}
 ${lib.optionalString (cfg.static-auth-secret != null) ("static-auth-secret=${cfg.static-auth-secret}")}
+${lib.optionalString (cfg.static-auth-secret-file != null) ("static-auth-secret=#static-auth-secret#")}
 realm=${cfg.realm}
 ${lib.optionalString cfg.no-udp "no-udp"}
 ${lib.optionalString cfg.no-tcp "no-tcp"}
@@ -182,6 +183,13 @@ in {
           by a separate program, so this is why that other mode is 'dynamic'.
         '';
       };
+      static-auth-secret-file = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Path to the file containing the static authentication secret.
+        '';
+      };
       realm = mkOption {
         type = types.str;
         default = config.networking.hostName;
@@ -293,42 +301,63 @@ in {
     };
   };
 
-  config = mkIf cfg.enable {
-    users.users.turnserver =
-      { uid = config.ids.uids.turnserver;
-        description = "coturn TURN server user";
-      };
-    users.groups.turnserver =
-      { gid = config.ids.gids.turnserver;
-        members = [ "turnserver" ];
-      };
+  config = mkIf cfg.enable (mkMerge ([
+    { assertions = [
+      { assertion = cfg.static-auth-secret != null -> cfg.static-auth-secret-file == null ;
+        message = "static-auth-secret and static-auth-secret-file cannot be set at the same time";
+      }
+    ];}
 
-    systemd.services.coturn = {
-      description = "coturn TURN server";
-      after = [ "network-online.target" ];
-      wants = [ "network-online.target" ];
-      wantedBy = [ "multi-user.target" ];
+    {
+      users.users.turnserver =
+        { uid = config.ids.uids.turnserver;
+          description = "coturn TURN server user";
+        };
+      users.groups.turnserver =
+        { gid = config.ids.gids.turnserver;
+          members = [ "turnserver" ];
+        };
 
-      unitConfig = {
-        Documentation = "man:coturn(1) man:turnadmin(1) man:turnserver(1)";
-      };
+      systemd.services.coturn = let
+        runConfig = "/run/coturn/turnserver.cfg";
+      in {
+        description = "coturn TURN server";
+        after = [ "network-online.target" ];
+        wants = [ "network-online.target" ];
+        wantedBy = [ "multi-user.target" ];
 
-      serviceConfig = {
-        Type = "simple";
-        ExecStart = "${pkgs.coturn}/bin/turnserver -c ${configFile}";
-        RuntimeDirectory = "turnserver";
-        User = "turnserver";
-        Group = "turnserver";
-        AmbientCapabilities =
-          mkIf (
-            cfg.listening-port < 1024 ||
-            cfg.alt-listening-port < 1024 ||
-            cfg.tls-listening-port < 1024 ||
-            cfg.alt-tls-listening-port < 1024 ||
-            cfg.min-port < 1024
-          ) "cap_net_bind_service";
-        Restart = "on-abort";
-      };
-    };
-  };
+        unitConfig = {
+          Documentation = "man:coturn(1) man:turnadmin(1) man:turnserver(1)";
+        };
+
+        preStart = ''
+          cat ${configFile} > ${runConfig}
+          ${optionalString (cfg.static-auth-secret-file != null) ''
+            STATIC_AUTH_SECRET="$(head -n1 ${cfg.static-auth-secret-file} || :)"
+            sed -e "s,#static-auth-secret#,$STATIC_AUTH_SECRET,g" \
+              -i ${runConfig}
+          '' }
+          chmod 640 ${runConfig}
+        '';
+        serviceConfig = {
+          Type = "simple";
+          ExecStart = "${pkgs.coturn}/bin/turnserver -c ${runConfig}";
+          RuntimeDirectory = "turnserver";
+          User = "turnserver";
+          Group = "turnserver";
+          AmbientCapabilities =
+            mkIf (
+              cfg.listening-port < 1024 ||
+              cfg.alt-listening-port < 1024 ||
+              cfg.tls-listening-port < 1024 ||
+              cfg.alt-tls-listening-port < 1024 ||
+              cfg.min-port < 1024
+            ) "cap_net_bind_service";
+          Restart = "on-abort";
+        };
+      };
+    systemd.tmpfiles.rules = [
+      "d  /run/coturn 0700 turnserver turnserver - -"
+    ];
+  }]));
 }
diff --git a/nixpkgs/nixos/modules/services/networking/murmur.nix b/nixpkgs/nixos/modules/services/networking/murmur.nix
index b03630208df8..f8bb878ec65d 100644
--- a/nixpkgs/nixos/modules/services/networking/murmur.nix
+++ b/nixpkgs/nixos/modules/services/networking/murmur.nix
@@ -98,7 +98,7 @@ in
       };
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 64738;
         description = "Ports to bind to (UDP and TCP).";
       };
diff --git a/nixpkgs/nixos/modules/services/networking/namecoind.nix b/nixpkgs/nixos/modules/services/networking/namecoind.nix
index 4966ed2cac8d..8f7a5123f7e1 100644
--- a/nixpkgs/nixos/modules/services/networking/namecoind.nix
+++ b/nixpkgs/nixos/modules/services/networking/namecoind.nix
@@ -105,7 +105,7 @@ in
       };
 
       rpc.port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 8332;
         description = ''
           Port the RPC server will bind to.
diff --git a/nixpkgs/nixos/modules/services/networking/nar-serve.nix b/nixpkgs/nixos/modules/services/networking/nar-serve.nix
index ddd42fa01073..745138186a20 100644
--- a/nixpkgs/nixos/modules/services/networking/nar-serve.nix
+++ b/nixpkgs/nixos/modules/services/networking/nar-serve.nix
@@ -13,7 +13,7 @@ in
       enable = mkEnableOption "Serve NAR file contents via HTTP";
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 8383;
         description = ''
           Port number where nar-serve will listen on.
diff --git a/nixpkgs/nixos/modules/services/networking/nix-serve.nix b/nixpkgs/nixos/modules/services/networking/nix-serve.nix
index 347d87b3f385..b17f35c769bb 100644
--- a/nixpkgs/nixos/modules/services/networking/nix-serve.nix
+++ b/nixpkgs/nixos/modules/services/networking/nix-serve.nix
@@ -11,7 +11,7 @@ in
       enable = mkEnableOption "nix-serve, the standalone Nix binary cache server";
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 5000;
         description = ''
           Port number where nix-serve will listen on.
diff --git a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
index 4cad8f8663b4..d804c017f5d6 100644
--- a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
@@ -464,6 +464,7 @@ in
               { ExecStart =
                   (optionalString cfg.startWhenNeeded "-") +
                   "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") +
+                  "-D " +  # don't detach into a daemon process
                   "-f /etc/ssh/sshd_config";
                 KillMode = "process";
               } // (if cfg.startWhenNeeded then {
diff --git a/nixpkgs/nixos/modules/services/networking/tailscale.nix b/nixpkgs/nixos/modules/services/networking/tailscale.nix
index c33a38179ee4..3f88ff53dff0 100644
--- a/nixpkgs/nixos/modules/services/networking/tailscale.nix
+++ b/nixpkgs/nixos/modules/services/networking/tailscale.nix
@@ -34,7 +34,7 @@ in {
     systemd.packages = [ cfg.package ];
     systemd.services.tailscaled = {
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.openresolv ];
+      path = [ pkgs.openresolv pkgs.procps ];
       serviceConfig.Environment = [
         "PORT=${toString cfg.port}"
         ''"FLAGS=--tun ${lib.escapeShellArg cfg.interfaceName}"''
diff --git a/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh b/nixpkgs/nixos/modules/services/security/vaultwarden/backup.sh
index 264a7da9cbb6..2a3de0ab1dee 100644
--- a/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh
+++ b/nixpkgs/nixos/modules/services/security/vaultwarden/backup.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-# Based on: https://github.com/dani-garcia/bitwarden_rs/wiki/Backing-up-your-vault
+# Based on: https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault
 if ! mkdir -p "$BACKUP_FOLDER"; then
   echo "Could not create backup folder '$BACKUP_FOLDER'" >&2
   exit 1
diff --git a/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix b/nixpkgs/nixos/modules/services/security/vaultwarden/default.nix
index bed59dbf821f..940ac7832dae 100644
--- a/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix
+++ b/nixpkgs/nixos/modules/services/security/vaultwarden/default.nix
@@ -3,9 +3,9 @@
 with lib;
 
 let
-  cfg = config.services.bitwarden_rs;
-  user = config.users.users.bitwarden_rs.name;
-  group = config.users.groups.bitwarden_rs.name;
+  cfg = config.services.vaultwarden;
+  user = config.users.users.vaultwarden.name;
+  group = config.users.groups.vaultwarden.name;
 
   # Convert name from camel case (e.g. disable2FARemember) to upper case snake case (e.g. DISABLE_2FA_REMEMBER).
   nameToEnvVar = name:
@@ -26,22 +26,26 @@ let
         if value != null then [ (nameValuePair (nameToEnvVar name) (if isBool value then boolToString value else toString value)) ] else []
       ) cfg.config));
     in { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") {
-      WEB_VAULT_FOLDER = "${pkgs.bitwarden_rs-vault}/share/bitwarden_rs/vault";
+      WEB_VAULT_FOLDER = "${pkgs.vaultwarden-vault}/share/vaultwarden/vault";
     } // configEnv;
 
-  configFile = pkgs.writeText "bitwarden_rs.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
+  configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
 
-  bitwarden_rs = pkgs.bitwarden_rs.override { inherit (cfg) dbBackend; };
+  vaultwarden = pkgs.vaultwarden.override { inherit (cfg) dbBackend; };
 
 in {
-  options.services.bitwarden_rs = with types; {
-    enable = mkEnableOption "bitwarden_rs";
+  imports = [
+    (mkRenamedOptionModule [ "services" "bitwarden_rs" ] [ "services" "vaultwarden" ])
+  ];
+
+  options.services.vaultwarden = with types; {
+    enable = mkEnableOption "vaultwarden";
 
     dbBackend = mkOption {
       type = enum [ "sqlite" "mysql" "postgresql" ];
       default = "sqlite";
       description = ''
-        Which database backend bitwarden_rs will be using.
+        Which database backend vaultwarden will be using.
       '';
     };
 
@@ -49,7 +53,7 @@ in {
       type = nullOr str;
       default = null;
       description = ''
-        The directory under which bitwarden_rs will backup its persistent data.
+        The directory under which vaultwarden will backup its persistent data.
       '';
     };
 
@@ -65,7 +69,7 @@ in {
         }
       '';
       description = ''
-        The configuration of bitwarden_rs is done through environment variables,
+        The configuration of vaultwarden is done through environment variables,
         therefore the names are converted from camel case (e.g. disable2FARemember)
         to upper case snake case (e.g. DISABLE_2FA_REMEMBER).
         In this conversion digits (0-9) are handled just like upper case characters,
@@ -75,17 +79,17 @@ in {
         This allows working around any potential future conflicting naming conventions.
 
         Based on the attributes passed to this config option an environment file will be generated
-        that is passed to bitwarden_rs's systemd service.
+        that is passed to vaultwarden's systemd service.
 
         The available configuration options can be found in
-        <link xlink:href="https://github.com/dani-garcia/bitwarden_rs/blob/${bitwarden_rs.version}/.env.template">the environment template file</link>.
+        <link xlink:href="https://github.com/dani-garcia/vaultwarden/blob/${vaultwarden.version}/.env.template">the environment template file</link>.
       '';
     };
 
     environmentFile = mkOption {
       type = with types; nullOr path;
       default = null;
-      example = "/root/bitwarden_rs.env";
+      example = "/root/vaultwarden.env";
       description = ''
         Additional environment file as defined in <citerefentry>
         <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
@@ -95,7 +99,7 @@ in {
         may be passed to the service without adding them to the world-readable Nix store.
 
         Note that this file needs to be available on the host on which
-        <literal>bitwarden_rs</literal> is running.
+        <literal>vaultwarden</literal> is running.
       '';
     };
   };
@@ -106,20 +110,21 @@ in {
       message = "Backups for database backends other than sqlite will need customization";
     } ];
 
-    users.users.bitwarden_rs = {
+    users.users.vaultwarden = {
       inherit group;
       isSystemUser = true;
     };
-    users.groups.bitwarden_rs = { };
+    users.groups.vaultwarden = { };
 
-    systemd.services.bitwarden_rs = {
+    systemd.services.vaultwarden = {
+      aliases = [ "bitwarden_rs" ];
       after = [ "network.target" ];
       path = with pkgs; [ openssl ];
       serviceConfig = {
         User = user;
         Group = group;
         EnvironmentFile = [ configFile ] ++ optional (cfg.environmentFile != null) cfg.environmentFile;
-        ExecStart = "${bitwarden_rs}/bin/bitwarden_rs";
+        ExecStart = "${vaultwarden}/bin/vaultwarden";
         LimitNOFILE = "1048576";
         PrivateTmp = "true";
         PrivateDevices = "true";
@@ -131,15 +136,16 @@ in {
       wantedBy = [ "multi-user.target" ];
     };
 
-    systemd.services.backup-bitwarden_rs = mkIf (cfg.backupDir != null) {
-      description = "Backup bitwarden_rs";
+    systemd.services.backup-vaultwarden = mkIf (cfg.backupDir != null) {
+      aliases = [ "backup-bitwarden_rs" ];
+      description = "Backup vaultwarden";
       environment = {
         DATA_FOLDER = "/var/lib/bitwarden_rs";
         BACKUP_FOLDER = cfg.backupDir;
       };
       path = with pkgs; [ sqlite ];
       serviceConfig = {
-        SyslogIdentifier = "backup-bitwarden_rs";
+        SyslogIdentifier = "backup-vaultwarden";
         Type = "oneshot";
         User = mkDefault user;
         Group = mkDefault group;
@@ -148,12 +154,13 @@ in {
       wantedBy = [ "multi-user.target" ];
     };
 
-    systemd.timers.backup-bitwarden_rs = mkIf (cfg.backupDir != null) {
-      description = "Backup bitwarden_rs on time";
+    systemd.timers.backup-vaultwarden = mkIf (cfg.backupDir != null) {
+      aliases = [ "backup-bitwarden_rs" ];
+      description = "Backup vaultwarden on time";
       timerConfig = {
         OnCalendar = mkDefault "23:00";
         Persistent = "true";
-        Unit = "backup-bitwarden_rs.service";
+        Unit = "backup-vaultwarden.service";
       };
       wantedBy = [ "multi-user.target" ];
     };
diff --git a/nixpkgs/nixos/modules/services/web-apps/discourse.nix b/nixpkgs/nixos/modules/services/web-apps/discourse.nix
index 9c7166f381a3..d3ae072f86a8 100644
--- a/nixpkgs/nixos/modules/services/web-apps/discourse.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/discourse.nix
@@ -30,6 +30,9 @@ in
       package = lib.mkOption {
         type = lib.types.package;
         default = pkgs.discourse;
+        apply = p: p.override {
+          plugins = lib.unique (p.enabledPlugins ++ cfg.plugins);
+        };
         defaultText = "pkgs.discourse";
         description = ''
           The discourse package to use.
@@ -731,8 +734,6 @@ in
 
           cp -r ${cfg.package}/share/discourse/config.dist/* /run/discourse/config/
           cp -r ${cfg.package}/share/discourse/public.dist/* /run/discourse/public/
-          cp -r ${cfg.package}/share/discourse/plugins.dist/* /run/discourse/plugins/
-          ${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} /run/discourse/plugins/") cfg.plugins}
           ln -sf /var/lib/discourse/uploads /run/discourse/public/uploads
           ln -sf /var/lib/discourse/backups /run/discourse/public/backups
 
diff --git a/nixpkgs/nixos/modules/services/web-servers/minio.nix b/nixpkgs/nixos/modules/services/web-servers/minio.nix
index 381a55faff16..d075449012f7 100644
--- a/nixpkgs/nixos/modules/services/web-servers/minio.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/minio.nix
@@ -4,6 +4,11 @@ with lib;
 
 let
   cfg = config.services.minio;
+
+  legacyCredentials = cfg: pkgs.writeText "minio-legacy-credentials" ''
+    MINIO_ROOT_USER=${cfg.accessKey}
+    MINIO_ROOT_PASSWORD=${cfg.secretKey}
+  '';
 in
 {
   meta.maintainers = [ maintainers.bachp ];
@@ -49,6 +54,17 @@ in
       '';
     };
 
+    rootCredentialsFile = mkOption  {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        File containing the MINIO_ROOT_USER, default is "minioadmin", and
+        MINIO_ROOT_PASSWORD (length >= 8), default is "minioadmin"; in the format of
+        an EnvironmentFile=, as described by systemd.exec(5).
+      '';
+      example = "/etc/nixos/minio-root-credentials";
+    };
+
     region = mkOption {
       default = "us-east-1";
       type = types.str;
@@ -72,6 +88,8 @@ in
   };
 
   config = mkIf cfg.enable {
+    warnings = optional ((cfg.accessKey != "") || (cfg.secretKey != "")) "services.minio.`accessKey` and services.minio.`secretKey` are deprecated, please use services.minio.`rootCredentialsFile` instead.";
+
     systemd.tmpfiles.rules = [
       "d '${cfg.configDir}' - minio minio - -"
     ] ++ (map (x:  "d '" + x + "' - minio minio - - ") cfg.dataDir);
@@ -86,14 +104,13 @@ in
         User = "minio";
         Group = "minio";
         LimitNOFILE = 65536;
+        EnvironmentFile = if (cfg.rootCredentialsFile != null) then cfg.rootCredentialsFile
+                          else if ((cfg.accessKey != "") || (cfg.secretKey != "")) then (legacyCredentials cfg)
+                          else null;
       };
       environment = {
         MINIO_REGION = "${cfg.region}";
         MINIO_BROWSER = "${if cfg.browser then "on" else "off"}";
-      } // optionalAttrs (cfg.accessKey != "") {
-        MINIO_ACCESS_KEY = "${cfg.accessKey}";
-      } // optionalAttrs (cfg.secretKey != "") {
-        MINIO_SECRET_KEY = "${cfg.secretKey}";
       };
     };
 
diff --git a/nixpkgs/nixos/modules/services/web-servers/ttyd.nix b/nixpkgs/nixos/modules/services/web-servers/ttyd.nix
index 01a01d97a234..68d55ee6ffd2 100644
--- a/nixpkgs/nixos/modules/services/web-servers/ttyd.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/ttyd.nix
@@ -33,7 +33,7 @@ in
       enable = mkEnableOption "ttyd daemon";
 
       port = mkOption {
-        type = types.int;
+        type = types.port;
         default = 7681;
         description = "Port to listen on (use 0 for random port)";
       };
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
index e1b9a21eb9f0..ef9ec438cc1c 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
@@ -99,7 +99,8 @@ in
       autoSuspend = mkOption {
         default = true;
         description = ''
-          Suspend the machine after inactivity.
+          On the GNOME Display Manager login screen, suspend the machine after inactivity.
+          (Does not affect automatic suspend while logged in, or at lock screen.)
         '';
         type = types.bool;
       };
diff --git a/nixpkgs/nixos/modules/services/x11/window-managers/fvwm.nix b/nixpkgs/nixos/modules/services/x11/window-managers/fvwm.nix
index 9a51b9cd6602..e283886ecc40 100644
--- a/nixpkgs/nixos/modules/services/x11/window-managers/fvwm.nix
+++ b/nixpkgs/nixos/modules/services/x11/window-managers/fvwm.nix
@@ -4,7 +4,7 @@ with lib;
 
 let
   cfg = config.services.xserver.windowManager.fvwm;
-  fvwm = pkgs.fvwm.override { gestures = cfg.gestures; };
+  fvwm = pkgs.fvwm.override { enableGestures = cfg.gestures; };
 in
 
 {
diff --git a/nixpkgs/nixos/modules/system/activation/top-level.nix b/nixpkgs/nixos/modules/system/activation/top-level.nix
index 6751ca3f2ee7..4e2f25cd27fc 100644
--- a/nixpkgs/nixos/modules/system/activation/top-level.nix
+++ b/nixpkgs/nixos/modules/system/activation/top-level.nix
@@ -13,7 +13,7 @@ let
   # !!! fix this
   children = mapAttrs (childName: childConfig:
       (import ../../../lib/eval-config.nix {
-        inherit baseModules specialArgs;
+        inherit lib baseModules specialArgs;
         system = config.nixpkgs.initialSystem;
         modules =
            (optionals childConfig.inheritParentConfig modules)
diff --git a/nixpkgs/nixos/modules/system/boot/kernel.nix b/nixpkgs/nixos/modules/system/boot/kernel.nix
index 363d8e47a0ff..1a6a9d99d5bb 100644
--- a/nixpkgs/nixos/modules/system/boot/kernel.nix
+++ b/nixpkgs/nixos/modules/system/boot/kernel.nix
@@ -38,11 +38,11 @@ in
       default = pkgs.linuxPackages;
       type = types.unspecified // { merge = mergeEqualOption; };
       apply = kernelPackages: kernelPackages.extend (self: super: {
-        kernel = super.kernel.override {
+        kernel = super.kernel.override (originalArgs: {
           inherit randstructSeed;
-          kernelPatches = super.kernel.kernelPatches ++ kernelPatches;
+          kernelPatches = (originalArgs.kernelPatches or []) ++ kernelPatches;
           features = lib.recursiveUpdate super.kernel.features features;
-        };
+        });
       });
       # We don't want to evaluate all of linuxPackages for the manual
       # - some of it might not even evaluate correctly.
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index 63e01dd054a5..7134b4321630 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -61,7 +61,7 @@ def write_loader_conf(profile: Optional[str], generation: int) -> None:
 
 
 def profile_path(profile: Optional[str], generation: int, name: str) -> str:
-    return os.readlink("%s/%s" % (system_dir(profile, generation), name))
+    return os.path.realpath("%s/%s" % (system_dir(profile, generation), name))
 
 
 def copy_from_profile(profile: Optional[str], generation: int, name: str, dry_run: bool = False) -> str:
diff --git a/nixpkgs/nixos/modules/system/boot/luksroot.nix b/nixpkgs/nixos/modules/system/boot/luksroot.nix
index 8c82b4bcf5db..f87d3b07a360 100644
--- a/nixpkgs/nixos/modules/system/boot/luksroot.nix
+++ b/nixpkgs/nixos/modules/system/boot/luksroot.nix
@@ -621,6 +621,8 @@ in
               Whether to allow TRIM requests to the underlying device. This option
               has security implications; please read the LUKS documentation before
               activating it.
+              This option is incompatible with authenticated encryption (dm-crypt
+              stacked over dm-integrity).
             '';
           };
 
diff --git a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
index c0ff28039b16..ae1dab5b8d8d 100644
--- a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
+++ b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix
@@ -55,7 +55,16 @@ in
     (mkIf enableBtrfs {
       system.fsPackages = [ pkgs.btrfs-progs ];
 
-      boot.initrd.kernelModules = mkIf inInitrd [ "btrfs" "crc32c" ];
+      boot.initrd.kernelModules = mkIf inInitrd [ "btrfs" ];
+      boot.initrd.availableKernelModules = mkIf inInitrd (
+        [ "crc32c" ]
+        ++ optionals (config.boot.kernelPackages.kernel.kernelAtLeast "5.5") [
+          # Needed for mounting filesystems with new checksums
+          "xxhash_generic"
+          "blake2b_generic"
+          "sha256_generic" # Should be baked into our kernel, just to be sure
+        ]
+      );
 
       boot.initrd.extraUtilsCommands = mkIf inInitrd
       ''
diff --git a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
index ad436ed30146..65b63cebc79c 100644
--- a/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
+++ b/nixpkgs/nixos/modules/virtualisation/oci-containers.nix
@@ -262,9 +262,6 @@ let
     postStop = "${cfg.backend} rm -f ${name} || true";
 
     serviceConfig = {
-      StandardOutput = "null";
-      StandardError = "null";
-
       ### There is no generalized way of supporting `reload` for docker
       ### containers. Some containers may respond well to SIGHUP sent to their
       ### init process, but it is not guaranteed; some apps have other reload
diff --git a/nixpkgs/nixos/tests/acme.nix b/nixpkgs/nixos/tests/acme.nix
index fe8c4af3ea21..6532fc4ac1d4 100644
--- a/nixpkgs/nixos/tests/acme.nix
+++ b/nixpkgs/nixos/tests/acme.nix
@@ -330,30 +330,38 @@ in import ./make-test-python.nix ({ lib, ... }: {
 
       with subtest("Can request certificate with HTTPS-01 challenge"):
           webserver.wait_for_unit("acme-finished-a.example.test.target")
-          check_fullchain(webserver, "a.example.test")
-          check_issuer(webserver, "a.example.test", "pebble")
-          check_connection(client, "a.example.test")
 
       with subtest("Certificates and accounts have safe + valid permissions"):
           group = "${nodes.webserver.config.security.acme.certs."a.example.test".group}"
           webserver.succeed(
-              f"test $(stat -L -c \"%a %U %G\" /var/lib/acme/a.example.test/* | tee /dev/stderr | grep '640 acme {group}' | wc -l) -eq 5"
+              f"test $(stat -L -c '%a %U %G' /var/lib/acme/a.example.test/*.pem | tee /dev/stderr | grep '640 acme {group}' | wc -l) -eq 5"
           )
           webserver.succeed(
-              f"test $(stat -L -c \"%a %U %G\" /var/lib/acme/.lego/a.example.test/**/* | tee /dev/stderr | grep '640 acme {group}' | wc -l) -eq 5"
+              f"test $(stat -L -c '%a %U %G' /var/lib/acme/.lego/a.example.test/**/a.example.test* | tee /dev/stderr | grep '600 acme {group}' | wc -l) -eq 4"
           )
           webserver.succeed(
-              f"test $(stat -L -c \"%a %U %G\" /var/lib/acme/a.example.test | tee /dev/stderr | grep '750 acme {group}' | wc -l) -eq 1"
+              f"test $(stat -L -c '%a %U %G' /var/lib/acme/a.example.test | tee /dev/stderr | grep '750 acme {group}' | wc -l) -eq 1"
           )
           webserver.succeed(
-              f"test $(find /var/lib/acme/accounts -type f -exec stat -L -c \"%a %U %G\" {{}} \\; | tee /dev/stderr | grep -v '600 acme {group}' | wc -l) -eq 0"
+              f"test $(find /var/lib/acme/accounts -type f -exec stat -L -c '%a %U %G' {{}} \\; | tee /dev/stderr | grep -v '600 acme {group}' | wc -l) -eq 0"
           )
 
+      with subtest("Certs are accepted by web server"):
+          webserver.succeed("systemctl start nginx.service")
+          check_fullchain(webserver, "a.example.test")
+          check_issuer(webserver, "a.example.test", "pebble")
+          check_connection(client, "a.example.test")
+
+      # Selfsigned certs tests happen late so we aren't fighting the system init triggering cert renewal
       with subtest("Can generate valid selfsigned certs"):
           webserver.succeed("systemctl clean acme-a.example.test.service --what=state")
           webserver.succeed("systemctl start acme-selfsigned-a.example.test.service")
           check_fullchain(webserver, "a.example.test")
           check_issuer(webserver, "a.example.test", "minica")
+          # Check selfsigned permissions
+          webserver.succeed(
+              f"test $(stat -L -c '%a %U %G' /var/lib/acme/a.example.test/*.pem | tee /dev/stderr | grep '640 acme {group}' | wc -l) -eq 5"
+          )
           # Will succeed if nginx can load the certs
           webserver.succeed("systemctl start nginx-config-reload.service")
 
@@ -376,6 +384,8 @@ in import ./make-test-python.nix ({ lib, ... }: {
           webserver.wait_for_unit("acme-finished-a.example.test.target")
           check_connection_key_bits(client, "a.example.test", "384")
           webserver.succeed("grep testing /var/lib/acme/a.example.test/test")
+          # Clean to remove the testing file (and anything else messy we did)
+          webserver.succeed("systemctl clean acme-a.example.test.service --what=state")
 
       with subtest("Correctly implements OCSP stapling"):
           switch_to(webserver, "ocsp-stapling")
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index b5126be8af7a..741606732144 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -42,12 +42,12 @@ in
   bind = handleTest ./bind.nix {};
   bitcoind = handleTest ./bitcoind.nix {};
   bittorrent = handleTest ./bittorrent.nix {};
-  bitwarden = handleTest ./bitwarden.nix {};
   blockbook-frontend = handleTest ./blockbook-frontend.nix {};
   boot = handleTestOn ["x86_64-linux"] ./boot.nix {}; # syslinux is unsupported on aarch64
   boot-stage1 = handleTest ./boot-stage1.nix {};
   borgbackup = handleTest ./borgbackup.nix {};
   botamusique = handleTest ./botamusique.nix {};
+  btrbk = handleTest ./btrbk.nix {};
   buildbot = handleTest ./buildbot.nix {};
   buildkite-agents = handleTest ./buildkite-agents.nix {};
   caddy = handleTest ./caddy.nix {};
@@ -88,6 +88,7 @@ in
   containers-tmpfs = handleTest ./containers-tmpfs.nix {};
   convos = handleTest ./convos.nix {};
   corerad = handleTest ./corerad.nix {};
+  coturn = handleTest ./coturn.nix {};
   couchdb = handleTest ./couchdb.nix {};
   cri-o = handleTestOn ["x86_64-linux"] ./cri-o.nix {};
   custom-ca = handleTest ./custom-ca.nix {};
@@ -446,6 +447,7 @@ in
   v2ray = handleTest ./v2ray.nix {};
   vault = handleTest ./vault.nix {};
   vault-postgresql = handleTest ./vault-postgresql.nix {};
+  vaultwarden = handleTest ./vaultwarden.nix {};
   vector = handleTest ./vector.nix {};
   victoriametrics = handleTest ./victoriametrics.nix {};
   virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
diff --git a/nixpkgs/nixos/tests/btrbk.nix b/nixpkgs/nixos/tests/btrbk.nix
new file mode 100644
index 000000000000..2689bb66c63a
--- /dev/null
+++ b/nixpkgs/nixos/tests/btrbk.nix
@@ -0,0 +1,110 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+
+  let
+    privateKey = ''
+      -----BEGIN OPENSSH PRIVATE KEY-----
+      b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+      QyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrwAAAJB+cF5HfnBe
+      RwAAAAtzc2gtZWQyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrw
+      AAAEBN75NsJZSpt63faCuaD75Unko0JjlSDxMhYHAPJk2/xXHxQHThDpD9/AMWNqQer3Tg
+      9gXMb2lTZMn0pelo8xyvAAAADXJzY2h1ZXR6QGt1cnQ=
+      -----END OPENSSH PRIVATE KEY-----
+    '';
+    publicKey = ''
+      ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHHxQHThDpD9/AMWNqQer3Tg9gXMb2lTZMn0pelo8xyv
+    '';
+  in
+  {
+    name = "btrbk";
+    meta = with pkgs.lib; {
+      maintainers = with maintainers; [ symphorien ];
+    };
+
+    nodes = {
+      archive = { ... }: {
+        environment.systemPackages = with pkgs; [ btrfs-progs ];
+        # note: this makes the privateKey world readable.
+        # don't do it with real ssh keys.
+        environment.etc."btrbk_key".text = privateKey;
+        services.btrbk = {
+          extraPackages = [ pkgs.lz4 ];
+          instances = {
+            remote = {
+              onCalendar = "minutely";
+              settings = {
+                ssh_identity = "/etc/btrbk_key";
+                ssh_user = "btrbk";
+                stream_compress = "lz4";
+                volume = {
+                  "ssh://main/mnt" = {
+                    target = "/mnt";
+                    snapshot_dir = "btrbk/remote";
+                    subvolume = "to_backup";
+                  };
+                };
+              };
+            };
+          };
+        };
+      };
+
+      main = { ... }: {
+        environment.systemPackages = with pkgs; [ btrfs-progs ];
+        services.openssh = {
+          enable = true;
+          passwordAuthentication = false;
+          challengeResponseAuthentication = false;
+        };
+        services.btrbk = {
+          extraPackages = [ pkgs.lz4 ];
+          sshAccess = [
+            {
+              key = publicKey;
+              roles = [ "source" "send" "info" "delete" ];
+            }
+          ];
+          instances = {
+            local = {
+              onCalendar = "minutely";
+              settings = {
+                volume = {
+                  "/mnt" = {
+                    snapshot_dir = "btrbk/local";
+                    subvolume = "to_backup";
+                  };
+                };
+              };
+            };
+          };
+        };
+      };
+    };
+
+    testScript = ''
+      start_all()
+
+      # create btrfs partition at /mnt
+      for machine in (archive, main):
+        machine.succeed("dd if=/dev/zero of=/data_fs bs=120M count=1")
+        machine.succeed("mkfs.btrfs /data_fs")
+        machine.succeed("mkdir /mnt")
+        machine.succeed("mount /data_fs /mnt")
+
+      # what to backup and where
+      main.succeed("btrfs subvolume create /mnt/to_backup")
+      main.succeed("mkdir -p /mnt/btrbk/{local,remote}")
+
+      # check that local snapshots work
+      with subtest("local"):
+          main.succeed("echo foo > /mnt/to_backup/bar")
+          main.wait_until_succeeds("cat /mnt/btrbk/local/*/bar | grep foo")
+          main.succeed("echo bar > /mnt/to_backup/bar")
+          main.succeed("cat /mnt/btrbk/local/*/bar | grep foo")
+
+      # check that btrfs send/receive works and ssh access works
+      with subtest("remote"):
+          archive.wait_until_succeeds("cat /mnt/*/bar | grep bar")
+          main.succeed("echo baz > /mnt/to_backup/bar")
+          archive.succeed("cat /mnt/*/bar | grep bar")
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/coturn.nix b/nixpkgs/nixos/tests/coturn.nix
new file mode 100644
index 000000000000..dff832281c7c
--- /dev/null
+++ b/nixpkgs/nixos/tests/coturn.nix
@@ -0,0 +1,29 @@
+import ./make-test-python.nix ({ ... }: {
+  name = "coturn";
+  nodes = {
+    default = {
+      services.coturn.enable = true;
+    };
+    secretsfile = {
+      boot.postBootCommands = ''
+        echo "some-very-secret-string" > /run/coturn-secret
+      '';
+      services.coturn = {
+        enable = true;
+        static-auth-secret-file = "/run/coturn-secret";
+      };
+    };
+  };
+
+  testScript =
+    ''
+      start_all()
+
+      with subtest("by default works without configuration"):
+          default.wait_for_unit("coturn.service")
+
+      with subtest("works with static-auth-secret-file"):
+          secretsfile.wait_for_unit("coturn.service")
+          secretsfile.succeed("grep 'some-very-secret-string' /run/coturn/turnserver.cfg")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/jenkins-cli.nix b/nixpkgs/nixos/tests/jenkins-cli.nix
new file mode 100644
index 000000000000..f25e1604da33
--- /dev/null
+++ b/nixpkgs/nixos/tests/jenkins-cli.nix
@@ -0,0 +1,30 @@
+import ./make-test-python.nix ({ pkgs, ...} : rec {
+  name = "jenkins-cli";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ pamplemousse ];
+  };
+
+  nodes = {
+    machine =
+      { ... }:
+      {
+        services.jenkins = {
+          enable = true;
+          withCLI = true;
+        };
+      };
+  };
+
+  testScript = ''
+    start_all()
+
+    machine.wait_for_unit("jenkins")
+
+    assert "JENKINS_URL" in machine.succeed("env")
+    assert "http://0.0.0.0:8080" in machine.succeed("echo $JENKINS_URL")
+
+    machine.succeed(
+        "jenkins-cli -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword)"
+    )
+  '';
+})
diff --git a/nixpkgs/nixos/tests/kubernetes/base.nix b/nixpkgs/nixos/tests/kubernetes/base.nix
index 8cfac10b6dc4..1f23ca55fb23 100644
--- a/nixpkgs/nixos/tests/kubernetes/base.nix
+++ b/nixpkgs/nixos/tests/kubernetes/base.nix
@@ -40,7 +40,7 @@ let
                   allowedTCPPorts = [
                     10250 # kubelet
                   ];
-                  trustedInterfaces = ["docker0"];
+                  trustedInterfaces = ["mynet"];
 
                   extraCommands = concatMapStrings  (node: ''
                     iptables -A INPUT -s ${node.config.networking.primaryIPAddress} -j ACCEPT
@@ -61,6 +61,13 @@ let
                   advertiseAddress = master.ip;
                 };
                 masterAddress = "${masterName}.${config.networking.domain}";
+                # workaround for:
+                #   https://github.com/kubernetes/kubernetes/issues/102676
+                #   (workaround from) https://github.com/kubernetes/kubernetes/issues/95488
+                kubelet.extraOpts = ''\
+                  --cgroups-per-qos=false \
+                  --enforce-node-allocatable="" \
+                '';
               };
             }
             (optionalAttrs (any (role: role == "master") machine.roles) {
diff --git a/nixpkgs/nixos/tests/mysql/mysql.nix b/nixpkgs/nixos/tests/mysql/mysql.nix
index c21136416d47..2ec9c3d50a3c 100644
--- a/nixpkgs/nixos/tests/mysql/mysql.nix
+++ b/nixpkgs/nixos/tests/mysql/mysql.nix
@@ -98,7 +98,7 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
         }];
         services.mysql.settings = {
           mysqld = {
-            plugin-load-add = [ "ha_rocksdb.so" ];
+            plugin-load-add = [ "ha_mroonga.so" "ha_rocksdb.so" ];
           };
         };
         services.mysql.package = pkgs.mariadb;
@@ -172,6 +172,20 @@ import ./../make-test-python.nix ({ pkgs, ...} : {
         "echo 'use testdb; select test_id from tests;' | sudo -u testuser mysql -u testuser -N | grep 42"
     )
 
+    # Check if Mroonga plugin works
+    mariadb.succeed(
+        "echo 'use testdb; create table mroongadb (test_id INT, PRIMARY KEY (test_id)) ENGINE = Mroonga;' | sudo -u testuser mysql -u testuser"
+    )
+    mariadb.succeed(
+        "echo 'use testdb; insert into mroongadb values (25);' | sudo -u testuser mysql -u testuser"
+    )
+    mariadb.succeed(
+        "echo 'use testdb; select test_id from mroongadb;' | sudo -u testuser mysql -u testuser -N | grep 25"
+    )
+    mariadb.succeed(
+        "echo 'use testdb; drop table mroongadb;' | sudo -u testuser mysql -u testuser"
+    )
+
     # Check if RocksDB plugin works
     mariadb.succeed(
         "echo 'use testdb; create table rocksdb (test_id INT, PRIMARY KEY (test_id)) ENGINE = RocksDB;' | sudo -u testuser mysql -u testuser"
diff --git a/nixpkgs/nixos/tests/sanoid.nix b/nixpkgs/nixos/tests/sanoid.nix
index c691bfc08ef7..1983945915fe 100644
--- a/nixpkgs/nixos/tests/sanoid.nix
+++ b/nixpkgs/nixos/tests/sanoid.nix
@@ -33,7 +33,7 @@ in {
 
           autosnap = true;
         };
-        datasets."pool/sanoid".useTemplate = [ "test" ];
+        datasets."pool/sanoid".use_template = [ "test" ];
         extraArgs = [ "--verbose" ];
       };
 
diff --git a/nixpkgs/nixos/tests/trafficserver.nix b/nixpkgs/nixos/tests/trafficserver.nix
index 3979a1b4a482..983ded4f172e 100644
--- a/nixpkgs/nixos/tests/trafficserver.nix
+++ b/nixpkgs/nixos/tests/trafficserver.nix
@@ -104,6 +104,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     ats.wait_for_open_port(80)
     httpbin.wait_for_unit("httpbin")
     httpbin.wait_for_open_port(80)
+    client.wait_for_unit("network-online.target")
 
     with subtest("Traffic Server is running"):
         out = ats.succeed("traffic_ctl server status")
diff --git a/nixpkgs/nixos/tests/vault.nix b/nixpkgs/nixos/tests/vault.nix
index 59bccbe25959..c3b28b62695a 100644
--- a/nixpkgs/nixos/tests/vault.nix
+++ b/nixpkgs/nixos/tests/vault.nix
@@ -19,6 +19,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
       machine.wait_for_unit("vault.service")
       machine.wait_for_open_port(8200)
       machine.succeed("vault operator init")
-      machine.succeed("vault status | grep Sealed | grep true")
+      # vault now returns exit code 2 for sealed vaults
+      machine.fail("vault status")
+      machine.succeed("vault status || test $? -eq 2")
     '';
 })
diff --git a/nixpkgs/nixos/tests/bitwarden.nix b/nixpkgs/nixos/tests/vaultwarden.nix
index f64cf171f01f..b5343f5cad2d 100644
--- a/nixpkgs/nixos/tests/bitwarden.nix
+++ b/nixpkgs/nixos/tests/vaultwarden.nix
@@ -4,7 +4,7 @@
 }:
 
 # These tests will:
-#  * Set up a bitwarden-rs server
+#  * Set up a vaultwarden server
 #  * Have Firefox use the web vault to create an account, log in, and save a password to the valut
 #  * Have the bw cli log in and read that password from the vault
 #
@@ -24,8 +24,8 @@ let
 
   storedPassword = "seeeecret";
 
-  makeBitwardenTest = backend: makeTest {
-    name = "bitwarden_rs-${backend}";
+  makeVaultwardenTest = backend: makeTest {
+    name = "vaultwarden-${backend}";
     meta = {
       maintainers = with pkgs.lib.maintainers; [ jjjollyjim ];
     };
@@ -45,9 +45,9 @@ let
               package = pkgs.mariadb;
             };
 
-            services.bitwarden_rs.config.databaseUrl = "mysql://bitwardenuser:${dbPassword}@localhost/bitwarden";
+            services.vaultwarden.config.databaseUrl = "mysql://bitwardenuser:${dbPassword}@localhost/bitwarden";
 
-            systemd.services.bitwarden_rs.after = [ "mysql.service" ];
+            systemd.services.vaultwarden.after = [ "mysql.service" ];
           };
 
           postgresql = {
@@ -60,9 +60,9 @@ let
               '';
             };
 
-            services.bitwarden_rs.config.databaseUrl = "postgresql://bitwardenuser:${dbPassword}@localhost/bitwarden";
+            services.vaultwarden.config.databaseUrl = "postgresql://bitwardenuser:${dbPassword}@localhost/bitwarden";
 
-            systemd.services.bitwarden_rs.after = [ "postgresql.service" ];
+            systemd.services.vaultwarden.after = [ "postgresql.service" ];
           };
 
           sqlite = { };
@@ -71,7 +71,7 @@ let
         mkMerge [
           backendConfig.${backend}
           {
-            services.bitwarden_rs = {
+            services.vaultwarden = {
               enable = true;
               dbBackend = backend;
               config.rocketPort = 80;
@@ -152,7 +152,7 @@ let
 
     testScript = ''
       start_all()
-      server.wait_for_unit("bitwarden_rs.service")
+      server.wait_for_unit("vaultwarden.service")
       server.wait_for_open_port(80)
 
       with subtest("configure the cli"):
@@ -184,6 +184,6 @@ let
 in
 builtins.listToAttrs (
   map
-    (backend: { name = backend; value = makeBitwardenTest backend; })
+    (backend: { name = backend; value = makeVaultwardenTest backend; })
     backends
 )
diff --git a/nixpkgs/nixos/tests/yggdrasil.nix b/nixpkgs/nixos/tests/yggdrasil.nix
index 0e75ed54db28..b409d9ed7853 100644
--- a/nixpkgs/nixos/tests/yggdrasil.nix
+++ b/nixpkgs/nixos/tests/yggdrasil.nix
@@ -1,23 +1,19 @@
 let
-  aliceIp6 = "200:3b91:b2d8:e708:fbf3:f06:fdd5:90d0";
+  aliceIp6 = "202:b70:9b0b:cf34:f93c:8f18:bbfd:7034";
   aliceKeys = {
-    EncryptionPublicKey = "13e23986fe76bc3966b42453f479bc563348b7ff76633b7efcb76e185ec7652f";
-    EncryptionPrivateKey = "9f86947b15e86f9badac095517a1982e39a2db37ca726357f95987b898d82208";
-    SigningPublicKey = "e2c43349083bc1e998e4ec4535b4c6a8f44ca9a5a8e07336561267253b2be5f4";
-    SigningPrivateKey = "fe3add8da35316c05f6d90d3ca79bd2801e6ccab6d37e5339fef4152589398abe2c43349083bc1e998e4ec4535b4c6a8f44ca9a5a8e07336561267253b2be5f4";
+    PublicKey = "3e91ec9e861960d86e1ce88051f97c435bdf2859640ab681dfa906eb45ad5182";
+    PrivateKey = "a867f9e078e4ce58d310cf5acd4622d759e2a21df07e1d6fc380a2a26489480d3e91ec9e861960d86e1ce88051f97c435bdf2859640ab681dfa906eb45ad5182";
   };
-  bobIp6 = "201:ebbd:bde9:f138:c302:4afa:1fb6:a19a";
-  bobPrefix = "301:ebbd:bde9:f138";
+  bobIp6 = "202:a483:73a4:9f2d:a559:4a19:bc9:8458";
+  bobPrefix = "302:a483:73a4:9f2d";
   bobConfig = {
     InterfacePeers = {
       eth1 = [ "tcp://192.168.1.200:12345" ];
     };
     MulticastInterfaces = [ "eth1" ];
     LinkLocalTCPPort = 54321;
-    EncryptionPublicKey = "c99d6830111e12d1b004c52fe9e5a2eef0f6aefca167aca14589a370b7373279";
-    EncryptionPrivateKey = "2e698a53d3fdce5962d2ff37de0fe77742a5c8b56cd8259f5da6aa792f6e8ba3";
-    SigningPublicKey = "de111da0ec781e45bf6c63ecb45a78c24d7d4655abfaeea83b26c36eb5c0fd5b";
-    SigningPrivateKey = "2a6c21550f3fca0331df50668ffab66b6dce8237bcd5728e571e8033b363e247de111da0ec781e45bf6c63ecb45a78c24d7d4655abfaeea83b26c36eb5c0fd5b";
+    PublicKey = "2b6f918b6c1a4b54d6bcde86cf74e074fb32ead4ee439b7930df2aa60c825186";
+    PrivateKey = "0c4a24acd3402722ce9277ed179f4a04b895b49586493c25fbaed60653d857d62b6f918b6c1a4b54d6bcde86cf74e074fb32ead4ee439b7930df2aa60c825186";
   };
   danIp6 = bobPrefix + "::2";
 
diff --git a/nixpkgs/nixos/tests/zsh-history.nix b/nixpkgs/nixos/tests/zsh-history.nix
index 3109c3f65081..355687798406 100644
--- a/nixpkgs/nixos/tests/zsh-history.nix
+++ b/nixpkgs/nixos/tests/zsh-history.nix
@@ -23,7 +23,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     # Login
     default.wait_until_tty_matches(1, "login: ")
     default.send_chars("root\n")
-    default.wait_until_tty_matches(1, "root@default>")
+    default.wait_until_tty_matches(1, r"\nroot@default\b")
 
     # Generate some history
     default.send_chars("echo foobar\n")