Unverified Commit cc55ef9d authored by Janne Heß's avatar Janne Heß Committed by GitHub
Browse files

Merge pull request #254993 from helsinki-systems/feat/stc-mount-improvements

nixos/switch-to-configuration: Mount improvements and a lot more test cases
parents 805fee6f 358347e8
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -21,8 +21,9 @@ If the action is `switch` or `test`, the currently running system is inspected
and the actions to switch to the new system are calculated. This process takes
two data sources into account: `/etc/fstab` and the current systemd status.
Mounts and swaps are read from `/etc/fstab` and the corresponding actions are
generated. If a new mount is added, for example, the proper `.mount` unit is
marked to be started. The current systemd state is inspected, the difference
generated. If the options of a mount are modified, for example, the proper `.mount`
unit is reloaded (or restarted if anything else changed and it's neither the root
mount or the nix store). The current systemd state is inspected, the difference
between the current system and the desired configuration is calculated and
actions are generated to get to this state. There are a lot of nuances that can
be controlled by the units which are explained here.
+15 −5
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ if ("@localeArchive@" ne "") {

if (!defined($action) || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) {
    print STDERR <<"EOF";
Usage: $0 [switch|boot|test]
Usage: $0 [switch|boot|test|dry-activate]

switch:       make the configuration the boot default and activate now
boot:         make the configuration the boot default
@@ -661,10 +661,20 @@ foreach my $mount_point (keys(%{$cur_fss})) {
        # Filesystem entry disappeared, so unmount it.
        $units_to_stop{$unit} = 1;
    } elsif ($cur->{fsType} ne $new->{fsType} || $cur->{device} ne $new->{device}) {
        if ($mount_point eq '/' or $mount_point eq '/nix') {
            if ($cur->{options} ne $new->{options}) {
                # Mount options changed, so remount it.
                $units_to_reload{$unit} = 1;
                record_unit($reload_list_file, $unit);
            } else {
                # Don't unmount / or /nix if the device changed
                $units_to_skip{$unit} = 1;
            }
        } else {
            # Filesystem type or device changed, so unmount and mount it.
        $units_to_stop{$unit} = 1;
        $units_to_start{$unit} = 1;
        record_unit($start_list_file, $unit);
            $units_to_restart{$unit} = 1;
            record_unit($restart_list_file, $unit);
        }
    } elsif ($cur->{options} ne $new->{options}) {
        # Mount options changes, so remount it.
        $units_to_reload{$unit} = 1;
+122 −0
Original line number Diff line number Diff line
@@ -58,6 +58,37 @@ in {
      '');

      specialisation = rec {
        brokenInitInterface.configuration.config.system.extraSystemBuilderCmds = ''
          echo "systemd 0" > $out/init-interface-version
        '';

        modifiedSystemConf.configuration.systemd.extraConfig = ''
          # Hello world!
        '';

        addedMount.configuration.virtualisation.fileSystems."/test" = {
          device = "tmpfs";
          fsType = "tmpfs";
        };

        addedMountOptsModified.configuration = {
          imports = [ addedMount.configuration ];
          virtualisation.fileSystems."/test".options = [ "x-test" ];
        };

        addedMountDevModified.configuration = {
          imports = [ addedMountOptsModified.configuration ];
          virtualisation.fileSystems."/test".device = lib.mkForce "ramfs";
        };

        storeMountModified.configuration = {
          virtualisation.fileSystems."/".device = lib.mkForce "auto";
        };

        swap.configuration.swapDevices = lib.mkVMOverride [
          { device = "/swapfile"; size = 1; }
        ];

        simpleService.configuration = {
          systemd.services.test = {
            wantedBy = [ "multi-user.target" ];
@@ -643,6 +674,97 @@ in {

        # test and dry-activate actions are tested further down below

        # invalid action fails the script
        switch_to_specialisation("${machine}", "", action="broken-action", fail=True)
        # no action fails the script
        assert "Usage:" in machine.fail("${machine}/bin/switch-to-configuration 2>&1")

    with subtest("init interface version"):
        # Do not try to switch to an invalid init interface version
        assert "incompatible" in switch_to_specialisation("${machine}", "brokenInitInterface", fail=True)

    with subtest("systemd restarts"):
        # systemd is restarted when its system.conf changes
        out = switch_to_specialisation("${machine}", "modifiedSystemConf")
        assert_contains(out, "restarting systemd...")

    with subtest("continuing from an aborted switch"):
        # An aborted switch will write into a file what it tried to start
        # and a second switch should continue from this
        machine.succeed("echo dbus.service > /run/nixos/start-list")
        out = switch_to_specialisation("${machine}", "modifiedSystemConf")
        assert_contains(out, "starting the following units: dbus.service\n")

    with subtest("fstab mounts"):
        switch_to_specialisation("${machine}", "")
        # add a mountpoint
        out = switch_to_specialisation("${machine}", "addedMount")
        assert_lacks(out, "stopping the following units:")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_lacks(out, "\nrestarting the following units:")
        assert_lacks(out, "\nstarting the following units:")
        assert_contains(out, "the following new units were started: test.mount\n")
        # modify the mountpoint's options
        out = switch_to_specialisation("${machine}", "addedMountOptsModified")
        assert_lacks(out, "stopping the following units:")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_contains(out, "reloading the following units: test.mount\n")
        assert_lacks(out, "\nrestarting the following units:")
        assert_lacks(out, "\nstarting the following units:")
        assert_lacks(out, "the following new units were started:")
        # modify the device
        out = switch_to_specialisation("${machine}", "addedMountDevModified")
        assert_lacks(out, "stopping the following units:")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_lacks(out, "reloading the following units:")
        assert_contains(out, "\nrestarting the following units: test.mount\n")
        assert_lacks(out, "\nstarting the following units:")
        assert_lacks(out, "the following new units were started:")
        # modify both
        out = switch_to_specialisation("${machine}", "addedMount")
        assert_lacks(out, "stopping the following units:")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_lacks(out, "reloading the following units:")
        assert_contains(out, "\nrestarting the following units: test.mount\n")
        assert_lacks(out, "\nstarting the following units:")
        assert_lacks(out, "the following new units were started:")
        # remove the mount
        out = switch_to_specialisation("${machine}", "")
        assert_contains(out, "stopping the following units: test.mount\n")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_contains(out, "reloading the following units: dbus.service\n")
        assert_lacks(out, "\nrestarting the following units:")
        assert_lacks(out, "\nstarting the following units:")
        assert_lacks(out, "the following new units were started:")
        # change something about the / mount
        out = switch_to_specialisation("${machine}", "storeMountModified")
        assert_lacks(out, "stopping the following units:")
        assert_contains(out, "NOT restarting the following changed units: -.mount")
        assert_contains(out, "reloading the following units: dbus.service\n")
        assert_lacks(out, "\nrestarting the following units:")
        assert_lacks(out, "\nstarting the following units:")
        assert_lacks(out, "the following new units were started:")

    with subtest("swaps"):
        switch_to_specialisation("${machine}", "")
        # add a swap
        out = switch_to_specialisation("${machine}", "swap")
        assert_lacks(out, "stopping the following units:")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_contains(out, "reloading the following units: dbus.service\n")
        assert_lacks(out, "\nrestarting the following units:")
        assert_lacks(out, "\nstarting the following units:")
        assert_contains(out, "the following new units were started: swapfile.swap")
        # remove it
        out = switch_to_specialisation("${machine}", "")
        assert_contains(out, "stopping swap device: /swapfile")
        assert_lacks(out, "stopping the following units:")
        assert_lacks(out, "NOT restarting the following changed units:")
        assert_contains(out, "reloading the following units: dbus.service\n")
        assert_lacks(out, "\nrestarting the following units:")
        assert_lacks(out, "\nstarting the following units:")
        assert_lacks(out, "the following new units were started:")

    with subtest("services"):
        switch_to_specialisation("${machine}", "")
        # Nothing happens when nothing is changed