···556556- `teleport` has been upgraded from major version 12 to major version 14. Please see upstream [upgrade instructions](https://goteleport.com/docs/management/operations/upgrading/) and release notes for versions [13](https://goteleport.com/docs/changelog/#1300-050823) and [14](https://goteleport.com/docs/changelog/#1400-092023). Note that Teleport does not officially support upgrades across more than one major version at a time. If you're running Teleport server components, it is recommended to first upgrade to an intermediate 13.x version by setting `services.teleport.package = pkgs.teleport_13`. Afterwards, this option can be removed to upgrade to the default version (14).
557557558558- The Linux kernel module `msr` (see [`msr(4)`](https://man7.org/linux/man-pages/man4/msr.4.html)), which provides an interface to read and write the model-specific registers (MSRs) of an x86 CPU, can now be configured via `hardware.cpu.x86.msr`.
559559+560560+- There is a new NixOS option when writing NixOS tests `testing.initrdBackdoor`, that enables `backdoor.service` in initrd. Requires `boot.initrd.systemd.enable` to be enabled. Boot will pause in stage 1 at `initrd.target`, and will listen for commands from the `Machine` python interface, just like stage 2 normally does. This enables commands to be sent to test and debug stage 1. Use `machine.switch_root()` to leave stage 1 and proceed to stage 2.
+16
nixos/lib/test-driver/test_driver/machine.py
···12781278 def run_callbacks(self) -> None:
12791279 for callback in self.callbacks:
12801280 callback()
12811281+12821282+ def switch_root(self) -> None:
12831283+ """
12841284+ Transition from stage 1 to stage 2. This requires the
12851285+ machine to be configured with `testing.initrdBackdoor = true`
12861286+ and `boot.initrd.systemd.enable = true`.
12871287+ """
12881288+ self.wait_for_unit("initrd.target")
12891289+ self.execute(
12901290+ "systemctl isolate --no-block initrd-switch-root.target 2>/dev/null >/dev/null",
12911291+ check_return=False,
12921292+ check_output=False,
12931293+ )
12941294+ self.wait_for_console_text(r"systemd\[1\]:.*Switching root\.")
12951295+ self.connected = False
12961296+ self.connect()
+93-41
nixos/modules/testing/test-instrumentation.nix
···66with lib;
7788let
99+ cfg = config.testing;
1010+911 qemu-common = import ../../lib/qemu-common.nix { inherit lib pkgs; };
1212+1313+ backdoorService = {
1414+ wantedBy = [ "sysinit.target" ];
1515+ unitConfig.DefaultDependencies = false;
1616+ conflicts = [ "shutdown.target" "initrd-switch-root.target" ];
1717+ before = [ "shutdown.target" "initrd-switch-root.target" ];
1818+ requires = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
1919+ after = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
2020+ script =
2121+ ''
2222+ export USER=root
2323+ export HOME=/root
2424+ export DISPLAY=:0.0
2525+2626+ if [[ -e /etc/profile ]]; then
2727+ source /etc/profile
2828+ fi
2929+3030+ # Don't use a pager when executing backdoor
3131+ # actions. Because we use a tty, commands like systemctl
3232+ # or nix-store get confused into thinking they're running
3333+ # interactively.
3434+ export PAGER=
3535+3636+ cd /tmp
3737+ exec < /dev/hvc0 > /dev/hvc0
3838+ while ! exec 2> /dev/${qemu-common.qemuSerialDevice}; do sleep 0.1; done
3939+ echo "connecting to host..." >&2
4040+ stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion
4141+ # The following line is essential since it signals to
4242+ # the test driver that the shell is ready.
4343+ # See: the connect method in the Machine class.
4444+ echo "Spawning backdoor root shell..."
4545+ # Passing the terminal device makes bash run non-interactively.
4646+ # Otherwise we get errors on the terminal because bash tries to
4747+ # setup things like job control.
4848+ # Note: calling bash explicitly here instead of sh makes sure that
4949+ # we can also run non-NixOS guests during tests.
5050+ PS1= exec /usr/bin/env bash --norc /dev/hvc0
5151+ '';
5252+ serviceConfig.KillSignal = "SIGHUP";
5353+ };
5454+1055in
11561257{
13585959+ options.testing = {
6060+6161+ initrdBackdoor = lib.mkEnableOption (lib.mdDoc ''
6262+ enable backdoor.service in initrd. Requires
6363+ boot.initrd.systemd.enable to be enabled. Boot will pause in
6464+ stage 1 at initrd.target, and will listen for commands from the
6565+ Machine python interface, just like stage 2 normally does. This
6666+ enables commands to be sent to test and debug stage 1. Use
6767+ machine.switch_root() to leave stage 1 and proceed to stage 2.
6868+ '');
6969+7070+ };
7171+1472 config = {
15731616- systemd.services.backdoor =
1717- { wantedBy = [ "multi-user.target" ];
1818- requires = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
1919- after = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
2020- script =
2121- ''
2222- export USER=root
2323- export HOME=/root
2424- export DISPLAY=:0.0
7474+ assertions = [
7575+ {
7676+ assertion = cfg.initrdBackdoor -> config.boot.initrd.systemd.enable;
7777+ message = ''
7878+ testing.initrdBackdoor requires boot.initrd.systemd.enable to be enabled.
7979+ '';
8080+ }
8181+ ];
25822626- source /etc/profile
8383+ systemd.services.backdoor = backdoorService;
8484+8585+ boot.initrd.systemd = lib.mkMerge [
8686+ {
8787+ contents."/etc/systemd/journald.conf".text = ''
8888+ [Journal]
8989+ ForwardToConsole=yes
9090+ MaxLevelConsole=debug
9191+ '';
9292+9393+ extraConfig = config.systemd.extraConfig;
9494+ }
9595+9696+ (lib.mkIf cfg.initrdBackdoor {
9797+ # Implemented in machine.switch_root(). Suppress the unit by
9898+ # making it a noop without removing it, which would break
9999+ # initrd-parse-etc.service
100100+ services.initrd-cleanup.serviceConfig.ExecStart = [
101101+ # Reset
102102+ ""
103103+ # noop
104104+ "/bin/true"
105105+ ];
271062828- # Don't use a pager when executing backdoor
2929- # actions. Because we use a tty, commands like systemctl
3030- # or nix-store get confused into thinking they're running
3131- # interactively.
3232- export PAGER=
107107+ services.backdoor = backdoorService;
331083434- cd /tmp
3535- exec < /dev/hvc0 > /dev/hvc0
3636- while ! exec 2> /dev/${qemu-common.qemuSerialDevice}; do sleep 0.1; done
3737- echo "connecting to host..." >&2
3838- stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion
3939- # The following line is essential since it signals to
4040- # the test driver that the shell is ready.
4141- # See: the connect method in the Machine class.
4242- echo "Spawning backdoor root shell..."
4343- # Passing the terminal device makes bash run non-interactively.
4444- # Otherwise we get errors on the terminal because bash tries to
4545- # setup things like job control.
4646- # Note: calling bash explicitly here instead of sh makes sure that
4747- # we can also run non-NixOS guests during tests.
4848- PS1= exec /usr/bin/env bash --norc /dev/hvc0
4949- '';
5050- serviceConfig.KillSignal = "SIGHUP";
5151- };
109109+ contents."/usr/bin/env".source = "${pkgs.coreutils}/bin/env";
110110+ })
111111+ ];
5211253113 # Prevent agetty from being instantiated on the serial device, since it
54114 # interferes with the backdoor (writes to it will randomly fail
···104164 MaxLevelConsole=debug
105165 '';
106166107107- boot.initrd.systemd.contents."/etc/systemd/journald.conf".text = ''
108108- [Journal]
109109- ForwardToConsole=yes
110110- MaxLevelConsole=debug
111111- '';
112112-113167 systemd.extraConfig = ''
114168 # Don't clobber the console with duplicate systemd messages.
115169 ShowStatus=no
···122176 DefaultTimeoutStartSec=300
123177 DefaultDeviceTimeoutSec=300
124178 '';
125125-126126- boot.initrd.systemd.extraConfig = config.systemd.extraConfig;
127179128180 boot.consoleLogLevel = 7;
129181
+7
nixos/tests/systemd-initrd-modprobe.nix
···22 name = "systemd-initrd-modprobe";
3344 nodes.machine = { pkgs, ... }: {
55+ testing.initrdBackdoor = true;
56 boot.initrd.systemd.enable = true;
67 boot.initrd.kernelModules = [ "loop" ]; # Load module in initrd.
78 boot.extraModprobeConfig = ''
···1011 };
11121213 testScript = ''
1414+ machine.wait_for_unit("initrd.target")
1515+ max_loop = machine.succeed("cat /sys/module/loop/parameters/max_loop")
1616+ assert int(max_loop) == 42, "Parameter should be respected for initrd kernel modules"
1717+1818+ # Make sure it sticks in stage 2
1919+ machine.switch_root()
1320 machine.wait_for_unit("multi-user.target")
1421 max_loop = machine.succeed("cat /sys/module/loop/parameters/max_loop")
1522 assert int(max_loop) == 42, "Parameter should be respected for initrd kernel modules"