summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-11-10 15:18:19 +0100
committerAlyssa Ross <hi@alyssa.is>2023-11-10 15:18:19 +0100
commitafabc4a15d5ba6631bd4d865b8be37fc67d52809 (patch)
tree2342d9e8bd8b4cfbfee2b9a98c088df9f1c809ca /nixos
parent9a0c85ffc5aedc46b4d81f3b9fc22d7f488e3ff9 (diff)
parent714e527a726c9613fca8e13586a1b19198d68d9b (diff)
downloadnixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.tar
nixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.tar.gz
nixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.tar.bz2
nixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.tar.lz
nixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.tar.xz
nixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.tar.zst
nixpkgs-afabc4a15d5ba6631bd4d865b8be37fc67d52809.zip
Merge remote-tracking branch 'origin/master' into HEAD
Conflicts:
	pkgs/development/libraries/SDL2/default.nix
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-2311.section.md2
-rw-r--r--nixos/lib/test-driver/test_driver/machine.py16
-rw-r--r--nixos/modules/installer/tools/nixos-option/default.nix1
-rw-r--r--nixos/modules/services/backup/restic.nix8
-rw-r--r--nixos/modules/testing/test-instrumentation.nix138
-rw-r--r--nixos/tests/restic.nix1
-rw-r--r--nixos/tests/systemd-initrd-modprobe.nix7
-rw-r--r--nixos/tests/systemd-initrd-networkd-ssh.nix52
-rw-r--r--nixos/tests/systemd-initrd-networkd.nix130
-rw-r--r--nixos/tests/systemd-initrd-simple.nix12
10 files changed, 221 insertions, 146 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md
index e04c63029f9..03bd201246c 100644
--- a/nixos/doc/manual/release-notes/rl-2311.section.md
+++ b/nixos/doc/manual/release-notes/rl-2311.section.md
@@ -568,3 +568,5 @@ The module update takes care of the new config syntax and the data itself (user
 - `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).
 
 - 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`.
+
+- 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.
diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py
index 529de41d892..f430321bb60 100644
--- a/nixos/lib/test-driver/test_driver/machine.py
+++ b/nixos/lib/test-driver/test_driver/machine.py
@@ -1278,3 +1278,19 @@ class Machine:
     def run_callbacks(self) -> None:
         for callback in self.callbacks:
             callback()
+
+    def switch_root(self) -> None:
+        """
+        Transition from stage 1 to stage 2. This requires the
+        machine to be configured with `testing.initrdBackdoor = true`
+        and `boot.initrd.systemd.enable = true`.
+        """
+        self.wait_for_unit("initrd.target")
+        self.execute(
+            "systemctl isolate --no-block initrd-switch-root.target 2>/dev/null >/dev/null",
+            check_return=False,
+            check_output=False,
+        )
+        self.wait_for_console_text(r"systemd\[1\]:.*Switching root\.")
+        self.connected = False
+        self.connect()
diff --git a/nixos/modules/installer/tools/nixos-option/default.nix b/nixos/modules/installer/tools/nixos-option/default.nix
deleted file mode 100644
index 061460f38a3..00000000000
--- a/nixos/modules/installer/tools/nixos-option/default.nix
+++ /dev/null
@@ -1 +0,0 @@
-{ pkgs, ... }: pkgs.nixos-option
diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix
index fcdd3082f5a..87595f39796 100644
--- a/nixos/modules/services/backup/restic.nix
+++ b/nixos/modules/services/backup/restic.nix
@@ -133,13 +133,15 @@ in
         };
 
         timerConfig = mkOption {
-          type = types.attrsOf unitOption;
+          type = types.nullOr (types.attrsOf unitOption);
           default = {
             OnCalendar = "daily";
             Persistent = true;
           };
           description = lib.mdDoc ''
-            When to run the backup. See {manpage}`systemd.timer(5)` for details.
+            When to run the backup. See {manpage}`systemd.timer(5)` for
+            details. If null no timer is created and the backup will only
+            run when explicitly started.
           '';
           example = {
             OnCalendar = "00:05";
@@ -378,7 +380,7 @@ in
           wantedBy = [ "timers.target" ];
           timerConfig = backup.timerConfig;
         })
-        config.services.restic.backups;
+        (filterAttrs (_: backup: backup.timerConfig != null) config.services.restic.backups);
 
     # generate wrapper scripts, as described in the createWrapper option
     environment.systemPackages = lib.mapAttrsToList (name: backup: let
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index c91e54f5a4d..abe68dd6eae 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -6,49 +6,109 @@
 with lib;
 
 let
+  cfg = config.testing;
+
   qemu-common = import ../../lib/qemu-common.nix { inherit lib pkgs; };
+
+  backdoorService = {
+    wantedBy = [ "sysinit.target" ];
+    unitConfig.DefaultDependencies = false;
+    conflicts = [ "shutdown.target" "initrd-switch-root.target" ];
+    before = [ "shutdown.target" "initrd-switch-root.target" ];
+    requires = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
+    after = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
+    script =
+      ''
+        export USER=root
+        export HOME=/root
+        export DISPLAY=:0.0
+
+        if [[ -e /etc/profile ]]; then
+            source /etc/profile
+        fi
+
+        # Don't use a pager when executing backdoor
+        # actions. Because we use a tty, commands like systemctl
+        # or nix-store get confused into thinking they're running
+        # interactively.
+        export PAGER=
+
+        cd /tmp
+        exec < /dev/hvc0 > /dev/hvc0
+        while ! exec 2> /dev/${qemu-common.qemuSerialDevice}; do sleep 0.1; done
+        echo "connecting to host..." >&2
+        stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion
+        # The following line is essential since it signals to
+        # the test driver that the shell is ready.
+        # See: the connect method in the Machine class.
+        echo "Spawning backdoor root shell..."
+        # Passing the terminal device makes bash run non-interactively.
+        # Otherwise we get errors on the terminal because bash tries to
+        # setup things like job control.
+        # Note: calling bash explicitly here instead of sh makes sure that
+        # we can also run non-NixOS guests during tests.
+        PS1= exec /usr/bin/env bash --norc /dev/hvc0
+      '';
+      serviceConfig.KillSignal = "SIGHUP";
+  };
+
 in
 
 {
 
-  config = {
+  options.testing = {
 
-    systemd.services.backdoor =
-      { wantedBy = [ "multi-user.target" ];
-        requires = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
-        after = [ "dev-hvc0.device" "dev-${qemu-common.qemuSerialDevice}.device" ];
-        script =
-          ''
-            export USER=root
-            export HOME=/root
-            export DISPLAY=:0.0
+    initrdBackdoor = lib.mkEnableOption (lib.mdDoc ''
+      enable 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.
+    '');
 
-            source /etc/profile
+  };
 
-            # Don't use a pager when executing backdoor
-            # actions. Because we use a tty, commands like systemctl
-            # or nix-store get confused into thinking they're running
-            # interactively.
-            export PAGER=
-
-            cd /tmp
-            exec < /dev/hvc0 > /dev/hvc0
-            while ! exec 2> /dev/${qemu-common.qemuSerialDevice}; do sleep 0.1; done
-            echo "connecting to host..." >&2
-            stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion
-            # The following line is essential since it signals to
-            # the test driver that the shell is ready.
-            # See: the connect method in the Machine class.
-            echo "Spawning backdoor root shell..."
-            # Passing the terminal device makes bash run non-interactively.
-            # Otherwise we get errors on the terminal because bash tries to
-            # setup things like job control.
-            # Note: calling bash explicitly here instead of sh makes sure that
-            # we can also run non-NixOS guests during tests.
-            PS1= exec /usr/bin/env bash --norc /dev/hvc0
-          '';
-        serviceConfig.KillSignal = "SIGHUP";
-      };
+  config = {
+
+    assertions = [
+      {
+        assertion = cfg.initrdBackdoor -> config.boot.initrd.systemd.enable;
+        message = ''
+          testing.initrdBackdoor requires boot.initrd.systemd.enable to be enabled.
+        '';
+      }
+    ];
+
+    systemd.services.backdoor = backdoorService;
+
+    boot.initrd.systemd = lib.mkMerge [
+      {
+        contents."/etc/systemd/journald.conf".text = ''
+          [Journal]
+          ForwardToConsole=yes
+          MaxLevelConsole=debug
+        '';
+
+        extraConfig = config.systemd.extraConfig;
+      }
+
+      (lib.mkIf cfg.initrdBackdoor {
+        # Implemented in machine.switch_root(). Suppress the unit by
+        # making it a noop without removing it, which would break
+        # initrd-parse-etc.service
+        services.initrd-cleanup.serviceConfig.ExecStart = [
+          # Reset
+          ""
+          # noop
+          "/bin/true"
+        ];
+
+        services.backdoor = backdoorService;
+
+        contents."/usr/bin/env".source = "${pkgs.coreutils}/bin/env";
+      })
+    ];
 
     # Prevent agetty from being instantiated on the serial device, since it
     # interferes with the backdoor (writes to it will randomly fail
@@ -104,12 +164,6 @@ in
         MaxLevelConsole=debug
       '';
 
-    boot.initrd.systemd.contents."/etc/systemd/journald.conf".text = ''
-      [Journal]
-      ForwardToConsole=yes
-      MaxLevelConsole=debug
-    '';
-
     systemd.extraConfig = ''
       # Don't clobber the console with duplicate systemd messages.
       ShowStatus=no
@@ -123,8 +177,6 @@ in
       DefaultDeviceTimeoutSec=300
     '';
 
-    boot.initrd.systemd.extraConfig = config.systemd.extraConfig;
-
     boot.consoleLogLevel = 7;
 
     # Prevent tests from accessing the Internet.
diff --git a/nixos/tests/restic.nix b/nixos/tests/restic.nix
index 868ccb7efd7..4111720cf6b 100644
--- a/nixos/tests/restic.nix
+++ b/nixos/tests/restic.nix
@@ -55,6 +55,7 @@ import ./make-test-python.nix (
               inherit passwordFile paths exclude pruneOpts backupPrepareCommand backupCleanupCommand;
               repository = remoteRepository;
               initialize = true;
+              timerConfig = null; # has no effect here, just checking that it doesn't break the service
             };
             remote-from-file-backup = {
               inherit passwordFile exclude pruneOpts;
diff --git a/nixos/tests/systemd-initrd-modprobe.nix b/nixos/tests/systemd-initrd-modprobe.nix
index bf635a10d0e..0f93492176b 100644
--- a/nixos/tests/systemd-initrd-modprobe.nix
+++ b/nixos/tests/systemd-initrd-modprobe.nix
@@ -2,6 +2,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   name = "systemd-initrd-modprobe";
 
   nodes.machine = { pkgs, ... }: {
+    testing.initrdBackdoor = true;
     boot.initrd.systemd.enable = true;
     boot.initrd.kernelModules = [ "loop" ]; # Load module in initrd.
     boot.extraModprobeConfig = ''
@@ -10,6 +11,12 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   };
 
   testScript = ''
+    machine.wait_for_unit("initrd.target")
+    max_loop = machine.succeed("cat /sys/module/loop/parameters/max_loop")
+    assert int(max_loop) == 42, "Parameter should be respected for initrd kernel modules"
+
+    # Make sure it sticks in stage 2
+    machine.switch_root()
     machine.wait_for_unit("multi-user.target")
     max_loop = machine.succeed("cat /sys/module/loop/parameters/max_loop")
     assert int(max_loop) == 42, "Parameter should be respected for initrd kernel modules"
diff --git a/nixos/tests/systemd-initrd-networkd-ssh.nix b/nixos/tests/systemd-initrd-networkd-ssh.nix
index 6aaa6c828f7..d4c168f40e2 100644
--- a/nixos/tests/systemd-initrd-networkd-ssh.nix
+++ b/nixos/tests/systemd-initrd-networkd-ssh.nix
@@ -4,34 +4,16 @@ import ./make-test-python.nix ({ lib, ... }: {
 
   nodes = {
     server = { config, pkgs, ... }: {
-      environment.systemPackages = [ pkgs.cryptsetup ];
-      boot.loader.systemd-boot.enable = true;
-      boot.loader.timeout = 0;
-      virtualisation = {
-        emptyDiskImages = [ 4096 ];
-        useBootLoader = true;
-        # Booting off the encrypted disk requires an available init script from
-        # the Nix store
-        mountHostNixStore = true;
-        useEFIBoot = true;
-      };
-
-      specialisation.encrypted-root.configuration = {
-        virtualisation.rootDevice = "/dev/mapper/root";
-        virtualisation.fileSystems."/".autoFormat = true;
-        boot.initrd.luks.devices = lib.mkVMOverride {
-          root.device = "/dev/vdb";
-        };
-        boot.initrd.systemd.enable = true;
-        boot.initrd.network = {
+      testing.initrdBackdoor = true;
+      boot.initrd.systemd.enable = true;
+      boot.initrd.systemd.contents."/etc/msg".text = "foo";
+      boot.initrd.network = {
+        enable = true;
+        ssh = {
           enable = true;
-          ssh = {
-            enable = true;
-            authorizedKeys = [ (lib.readFile ./initrd-network-ssh/id_ed25519.pub) ];
-            port = 22;
-            # Terrible hack so it works with useBootLoader
-            hostKeys = [ { outPath = "${./initrd-network-ssh/ssh_host_ed25519_key}"; } ];
-          };
+          authorizedKeys = [ (lib.readFile ./initrd-network-ssh/id_ed25519.pub) ];
+          port = 22;
+          hostKeys = [ ./initrd-network-ssh/ssh_host_ed25519_key ];
         };
       };
     };
@@ -63,24 +45,16 @@ import ./make-test-python.nix ({ lib, ... }: {
         status, _ = client.execute("nc -z server 22")
         return status == 0
 
-    server.wait_for_unit("multi-user.target")
-    server.succeed(
-        "echo somepass | cryptsetup luksFormat --type=luks2 /dev/vdb",
-        "bootctl set-default nixos-generation-1-specialisation-encrypted-root.conf",
-        "sync",
-    )
-    server.shutdown()
-    server.start()
-
     client.wait_for_unit("network.target")
     with client.nested("waiting for SSH server to come up"):
         retry(ssh_is_up)
 
-    client.succeed(
-        "echo somepass | ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'systemd-tty-ask-password-agent' & exit"
+    msg = client.succeed(
+        "ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'cat /etc/msg'"
     )
+    assert "foo" in msg
 
+    server.switch_root()
     server.wait_for_unit("multi-user.target")
-    server.succeed("mount | grep '/dev/mapper/root on /'")
   '';
 })
diff --git a/nixos/tests/systemd-initrd-networkd.nix b/nixos/tests/systemd-initrd-networkd.nix
index 8376276d8f6..9c4ddb6e4b3 100644
--- a/nixos/tests/systemd-initrd-networkd.nix
+++ b/nixos/tests/systemd-initrd-networkd.nix
@@ -1,14 +1,36 @@
-import ./make-test-python.nix ({ pkgs, lib, ... }: {
-  name = "systemd-initrd-network";
-  meta.maintainers = [ lib.maintainers.elvishjerricco ];
+{ system ? builtins.currentSystem
+, config ? {}
+, pkgs ? import ../.. { inherit system config; }
+, lib ? pkgs.lib
+}:
 
-  nodes = let
-    mkFlushTest = flush: script: { ... }: {
-      boot.initrd.systemd.enable = true;
-      boot.initrd.network = {
-        enable = true;
-        flushBeforeStage2 = flush;
-      };
+with import ../lib/testing-python.nix { inherit system pkgs; };
+
+let
+  inherit (lib.maintainers) elvishjerricco;
+
+  common = {
+    boot.initrd.systemd = {
+      enable = true;
+      network.wait-online.timeout = 10;
+      network.wait-online.anyInterface = true;
+      targets.network-online.requiredBy = [ "initrd.target" ];
+      services.systemd-networkd-wait-online.requiredBy =
+        [ "network-online.target" ];
+      initrdBin = [ pkgs.iproute2 pkgs.iputils pkgs.gnugrep ];
+    };
+    testing.initrdBackdoor = true;
+    boot.initrd.network.enable = true;
+  };
+
+  mkFlushTest = flush: script: makeTest {
+    name = "systemd-initrd-network-${lib.optionalString (!flush) "no-"}flush";
+    meta.maintainers = [ elvishjerricco ];
+
+    nodes.machine = {
+      imports = [ common ];
+
+      boot.initrd.network.flushBeforeStage2 = flush;
       systemd.services.check-flush = {
         requiredBy = ["multi-user.target"];
         before = ["network-pre.target" "multi-user.target"];
@@ -19,57 +41,53 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
         inherit script;
       };
     };
-  in {
-    basic = { ... }: {
-      boot.initrd.network.enable = true;
 
-      boot.initrd.systemd = {
-        enable = true;
-        # Enable network-online to fail the test in case of timeout
-        network.wait-online.timeout = 10;
-        network.wait-online.anyInterface = true;
-        targets.network-online.requiredBy = [ "initrd.target" ];
-        services.systemd-networkd-wait-online.requiredBy =
-          [ "network-online.target" ];
+    testScript = ''
+      machine.wait_for_unit("network-online.target")
+      machine.succeed(
+          "ip addr | grep 10.0.2.15",
+          "ping -c1 10.0.2.2",
+      )
+      machine.switch_root()
 
-          initrdBin = [ pkgs.iproute2 pkgs.iputils pkgs.gnugrep ];
-          services.check = {
-            requiredBy = [ "initrd.target" ];
-            before = [ "initrd.target" ];
-            after = [ "network-online.target" ];
-            serviceConfig.Type = "oneshot";
-            path = [ pkgs.iproute2 pkgs.iputils pkgs.gnugrep ];
-            script = ''
-              ip addr | grep 10.0.2.15 || exit 1
-              ping -c1 10.0.2.2 || exit 1
-            '';
-          };
-      };
-    };
-
-    doFlush = mkFlushTest true ''
-      if ip addr | grep 10.0.2.15; then
-        echo "Network configuration survived switch-root; flushBeforeStage2 failed"
-        exit 1
-      fi
+      machine.wait_for_unit("multi-user.target")
     '';
+  };
+
+in {
+  basic = makeTest {
+    name = "systemd-initrd-network";
+    meta.maintainers = [ elvishjerricco ];
 
-    dontFlush = mkFlushTest false ''
-      if ! (ip addr | grep 10.0.2.15); then
-        echo "Network configuration didn't survive switch-root"
-        exit 1
-      fi
+    nodes.machine = common;
+
+    testScript = ''
+      machine.wait_for_unit("network-online.target")
+      machine.succeed(
+          "ip addr | grep 10.0.2.15",
+          "ping -c1 10.0.2.2",
+      )
+      machine.switch_root()
+
+      # Make sure the systemd-network user was set correctly in initrd
+      machine.wait_for_unit("multi-user.target")
+      machine.succeed("[ $(stat -c '%U,%G' /run/systemd/netif/links) = systemd-network,systemd-network ]")
+      machine.succeed("ip addr show >&2")
+      machine.succeed("ip route show >&2")
     '';
   };
 
-  testScript = ''
-    start_all()
-    basic.wait_for_unit("multi-user.target")
-    doFlush.wait_for_unit("multi-user.target")
-    dontFlush.wait_for_unit("multi-user.target")
-    # Make sure the systemd-network user was set correctly in initrd
-    basic.succeed("[ $(stat -c '%U,%G' /run/systemd/netif/links) = systemd-network,systemd-network ]")
-    basic.succeed("ip addr show >&2")
-    basic.succeed("ip route show >&2")
+  doFlush = mkFlushTest true ''
+    if ip addr | grep 10.0.2.15; then
+      echo "Network configuration survived switch-root; flushBeforeStage2 failed"
+      exit 1
+    fi
+  '';
+
+  dontFlush = mkFlushTest false ''
+    if ! (ip addr | grep 10.0.2.15); then
+      echo "Network configuration didn't survive switch-root"
+      exit 1
+    fi
   '';
-})
+}
diff --git a/nixos/tests/systemd-initrd-simple.nix b/nixos/tests/systemd-initrd-simple.nix
index a6a22e9d48e..2b7283a8219 100644
--- a/nixos/tests/systemd-initrd-simple.nix
+++ b/nixos/tests/systemd-initrd-simple.nix
@@ -2,16 +2,19 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   name = "systemd-initrd-simple";
 
   nodes.machine = { pkgs, ... }: {
-    boot.initrd.systemd = {
-      enable = true;
-      emergencyAccess = true;
-    };
+    testing.initrdBackdoor = true;
+    boot.initrd.systemd.enable = true;
     virtualisation.fileSystems."/".autoResize = true;
   };
 
   testScript = ''
     import subprocess
 
+    with subtest("testing initrd backdoor"):
+        machine.wait_for_unit("initrd.target")
+        machine.succeed("systemctl status initrd-fs.target")
+        machine.switch_root()
+
     with subtest("handover to stage-2 systemd works"):
         machine.wait_for_unit("multi-user.target")
         machine.succeed("systemd-analyze | grep -q '(initrd)'")  # direct handover
@@ -37,6 +40,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
         subprocess.check_call(["qemu-img", "resize", "vm-state-machine/machine.qcow2", "+1G"])
 
         machine.start()
+        machine.switch_root()
         newAvail = machine.succeed("df --output=avail / | sed 1d")
 
         assert int(oldAvail) < int(newAvail), "File system did not grow"