diff options
author | Julien Malka <julien@malka.sh> | 2024-01-06 00:30:23 +0000 |
---|---|---|
committer | Julien Malka <julien@malka.sh> | 2024-01-07 11:34:09 +0000 |
commit | eb435897a6de9c1924b0fc45147470bb557ae105 (patch) | |
tree | 24711ab5a70fead677042c6eeac2e79bda957d1c /nixos/tests/systemd-boot.nix | |
parent | 67ebfe5a801ec6b0f2fafac2f3a42939e9804f80 (diff) |
nixos/systemd-boot: init boot counting
Diffstat (limited to 'nixos/tests/systemd-boot.nix')
-rw-r--r-- | nixos/tests/systemd-boot.nix | 157 |
1 files changed, 152 insertions, 5 deletions
diff --git a/nixos/tests/systemd-boot.nix b/nixos/tests/systemd-boot.nix index c0b37a230df0f..6e956ab74fbe0 100644 --- a/nixos/tests/systemd-boot.nix +++ b/nixos/tests/systemd-boot.nix @@ -13,9 +13,11 @@ let boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; environment.systemPackages = [ pkgs.efibootmgr ]; + # Needed for machine-id to be persisted between reboots + environment.etc."machine-id".text = "00000000000000000000000000000000"; }; in -{ +rec { basic = makeTest { name = "systemd-boot"; meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ]; @@ -252,15 +254,15 @@ in ''; }; - garbage-collect-entry = makeTest { - name = "systemd-boot-garbage-collect-entry"; + garbage-collect-entry = { withBootCounting ? false, ... }: makeTest { + name = "systemd-boot-garbage-collect-entry" + optionalString withBootCounting "-with-boot-counting"; meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ]; nodes = { inherit common; machine = { pkgs, nodes, ... }: { imports = [ common ]; - + boot.loader.systemd-boot.bootCounting.enable = withBootCounting; # These are configs for different nodes, but we'll use them here in `machine` system.extraDependencies = [ nodes.common.system.build.toplevel @@ -275,8 +277,12 @@ in '' machine.succeed("nix-env -p /nix/var/nix/profiles/system --set ${baseSystem}") machine.succeed("nix-env -p /nix/var/nix/profiles/system --delete-generations 1") + # At this point generation 1 has already been marked as good so we reintroduce counters artificially + ${optionalString withBootCounting '' + machine.succeed("mv /boot/loader/entries/nixos-generation-1.conf /boot/loader/entries/nixos-generation-1+3.conf") + ''} machine.succeed("${baseSystem}/bin/switch-to-configuration boot") - machine.fail("test -e /boot/loader/entries/nixos-generation-1.conf") + machine.fail("test -e /boot/loader/entries/nixos-generation-1*") machine.succeed("test -e /boot/loader/entries/nixos-generation-2.conf") ''; }; @@ -322,4 +328,145 @@ in machine.wait_for_unit("multi-user.target") ''; }; + + # Check that we are booting the default entry and not the generation with largest version number + defaultEntry = { withBootCounting ? false, ... }: makeTest { + name = "systemd-boot-default-entry" + optionalString withBootCounting "-with-boot-counting"; + meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ]; + + nodes = { + machine = { pkgs, lib, nodes, ... }: { + imports = [ common ]; + system.extraDependencies = [ nodes.other_machine.system.build.toplevel ]; + boot.loader.systemd-boot.bootCounting.enable = withBootCounting; + }; + + other_machine = { pkgs, lib, ... }: { + imports = [ common ]; + boot.loader.systemd-boot.bootCounting.enable = withBootCounting; + environment.systemPackages = [ pkgs.hello ]; + }; + }; + testScript = { nodes, ... }: + let + orig = nodes.machine.system.build.toplevel; + other = nodes.other_machine.system.build.toplevel; + in + '' + orig = "${orig}" + other = "${other}" + + def check_current_system(system_path): + machine.succeed(f'test $(readlink -f /run/current-system) = "{system_path}"') + + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + check_current_system(orig) + + # Switch to other configuration + machine.succeed("nix-env -p /nix/var/nix/profiles/system --set ${other}") + machine.succeed(f"{other}/bin/switch-to-configuration boot") + # Rollback, default entry is now generation 1 + machine.succeed("nix-env -p /nix/var/nix/profiles/system --rollback") + machine.succeed(f"{orig}/bin/switch-to-configuration boot") + + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + ${if withBootCounting + then ''machine.succeed("test -e /boot/loader/entries/nixos-generation-2+3.conf")'' + else ''machine.succeed("test -e /boot/loader/entries/nixos-generation-2.conf")''} + machine.shutdown() + + machine.start() + machine.wait_for_unit("multi-user.target") + # Check that we booted generation 1 (default) + # even though generation 2 comes first in alphabetical order + check_current_system(orig) + ''; + }; + + + bootCounting = + let + baseConfig = { pkgs, lib, ... }: { + imports = [ common ]; + boot.loader.systemd-boot.bootCounting.enable = true; + boot.loader.systemd-boot.bootCounting.trials = 2; + }; + in + makeTest { + name = "systemd-boot-counting"; + meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ]; + + nodes = { + machine = { pkgs, lib, nodes, ... }: { + imports = [ baseConfig ]; + system.extraDependencies = [ nodes.bad_machine.system.build.toplevel ]; + }; + + bad_machine = { pkgs, lib, ... }: { + imports = [ baseConfig ]; + + systemd.services."failing" = { + script = "exit 1"; + requiredBy = [ "boot-complete.target" ]; + before = [ "boot-complete.target" ]; + serviceConfig.Type = "oneshot"; + }; + }; + }; + testScript = { nodes, ... }: + let + orig = nodes.machine.system.build.toplevel; + bad = nodes.bad_machine.system.build.toplevel; + in + '' + orig = "${orig}" + bad = "${bad}" + + def check_current_system(system_path): + machine.succeed(f'test $(readlink -f /run/current-system) = "{system_path}"') + + # Ensure we booted using an entry with counters enabled + machine.succeed( + "test -e /sys/firmware/efi/efivars/LoaderBootCountPath-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f" + ) + + # systemd-bless-boot should have already removed the "+2" suffix from the boot entry + machine.wait_for_unit("systemd-bless-boot.service") + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + check_current_system(orig) + + # Switch to bad configuration + machine.succeed("nix-env -p /nix/var/nix/profiles/system --set ${bad}") + machine.succeed(f"{bad}/bin/switch-to-configuration boot") + + # Ensure new bootloader entry has initialized counter + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + machine.succeed("test -e /boot/loader/entries/nixos-generation-2+2.conf") + machine.shutdown() + + machine.start() + machine.wait_for_unit("multi-user.target") + check_current_system(bad) + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + machine.succeed("test -e /boot/loader/entries/nixos-generation-2+1-1.conf") + machine.shutdown() + + machine.start() + machine.wait_for_unit("multi-user.target") + check_current_system(bad) + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + machine.succeed("test -e /boot/loader/entries/nixos-generation-2+0-2.conf") + machine.shutdown() + + # Should boot back into original configuration + machine.start() + check_current_system(orig) + machine.wait_for_unit("multi-user.target") + machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf") + machine.succeed("test -e /boot/loader/entries/nixos-generation-2+0-2.conf") + machine.shutdown() + ''; + }; + defaultEntryWithBootCounting = defaultEntry { withBootCounting = true; }; + garbageCollectEntryWithBootCounting = garbage-collect-entry { withBootCounting = true; }; } |