summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorWill Fancher <elvishjerricco@gmail.com>2023-05-22 09:13:00 -0400
committerGitHub <noreply@github.com>2023-05-22 09:13:00 -0400
commit636e03bef34e2cc9c19becc28a5aff39cf8aeaa1 (patch)
treea68f7b213b26ed20eb4dbf4b8028736a203f8c2a /nixos
parentc7eb65213bd7d95eafb8c5e2e181f04da103d054 (diff)
parentef80e11032c66d9e978eff9472687c983361fe08 (diff)
Merge pull request #232533 from nikstur/systemd-repart-create-root
nixos/systemd-repart: enable creating root partition
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/system/boot/systemd/repart.nix90
-rw-r--r--nixos/tests/systemd-repart.nix62
2 files changed, 118 insertions, 34 deletions
diff --git a/nixos/modules/system/boot/systemd/repart.nix b/nixos/modules/system/boot/systemd/repart.nix
index 251c7e2361231..e81b3e4ff2a1b 100644
--- a/nixos/modules/system/boot/systemd/repart.nix
+++ b/nixos/modules/system/boot/systemd/repart.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, lib, ... }:
+{ config, pkgs, lib, utils, ... }:
 
 let
   cfg = config.systemd.repart;
@@ -26,14 +26,29 @@ let
 in
 {
   options = {
-    boot.initrd.systemd.repart.enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
-      description = lib.mdDoc ''
-        Grow and add partitions to a partition table at boot time in the initrd.
-        systemd-repart only works with GPT partition tables.
-
-        To run systemd-repart after the initrd, see
-        `options.systemd.repart.enable`.
-      '';
+    boot.initrd.systemd.repart = {
+      enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
+        description = lib.mdDoc ''
+          Grow and add partitions to a partition table at boot time in the initrd.
+          systemd-repart only works with GPT partition tables.
+
+          To run systemd-repart after the initrd, see
+          `options.systemd.repart.enable`.
+        '';
+      };
+
+      device = lib.mkOption {
+        type = with lib.types; nullOr str;
+        description = lib.mdDoc ''
+          The device to operate on.
+
+          If `device == null`, systemd-repart will operate on the device
+          backing the root partition. So in order to dynamically *create* the
+          root partition in the initrd you need to set a device.
+        '';
+        default = null;
+        example = "/dev/vda";
+      };
     };
 
     systemd.repart = {
@@ -84,31 +99,42 @@ in
       contents."/etc/repart.d".source = definitionsDirectory;
 
       # Override defaults in upstream unit.
-      services.systemd-repart = {
-        # systemd-repart tries to create directories in /var/tmp by default to
-        # store large temporary files that benefit from persistence on disk. In
-        # the initrd, however, /var/tmp does not provide more persistence than
-        # /tmp, so we re-use it here.
-        environment."TMPDIR" = "/tmp";
-        serviceConfig = {
-          ExecStart = [
-            " " # required to unset the previous value.
-            # When running in the initrd, systemd-repart by default searches
-            # for definition files in /sysroot or /sysusr. We tell it to look
-            # in the initrd itself.
-            ''${config.boot.initrd.systemd.package}/bin/systemd-repart \
+      services.systemd-repart =
+        let
+          deviceUnit = "${utils.escapeSystemdPath initrdCfg.device}.device";
+        in
+        {
+          # systemd-repart tries to create directories in /var/tmp by default to
+          # store large temporary files that benefit from persistence on disk. In
+          # the initrd, however, /var/tmp does not provide more persistence than
+          # /tmp, so we re-use it here.
+          environment."TMPDIR" = "/tmp";
+          serviceConfig = {
+            ExecStart = [
+              " " # required to unset the previous value.
+              # When running in the initrd, systemd-repart by default searches
+              # for definition files in /sysroot or /sysusr. We tell it to look
+              # in the initrd itself.
+              ''${config.boot.initrd.systemd.package}/bin/systemd-repart \
                   --definitions=/etc/repart.d \
-                  --dry-run=no
-            ''
-          ];
+                  --dry-run=no ${lib.optionalString (initrdCfg.device != null) initrdCfg.device}
+              ''
+            ];
+          };
+          # systemd-repart needs to run after /sysroot (or /sysuser, but we
+          # don't have it) has been mounted because otherwise it cannot
+          # determine the device (i.e disk) to operate on. If you want to run
+          # systemd-repart without /sysroot (i.e. to create the root
+          # partition), you have to explicitly tell it which device to operate
+          # on. The service then needs to be ordered to run after this device
+          # is available.
+          requires = lib.mkIf (initrdCfg.device != null) [ deviceUnit ];
+          after =
+            if initrdCfg.device == null then
+              [ "sysroot.mount" ]
+            else
+              [ deviceUnit ];
         };
-        # systemd-repart needs to run after /sysroot (or /sysuser, but we don't
-        # have it) has been mounted because otherwise it cannot determine the
-        # device (i.e disk) to operate on. If you want to run systemd-repart
-        # without /sysroot, you have to explicitly tell it which device to
-        # operate on.
-        after = [ "sysroot.mount" ];
-      };
     };
 
     environment.etc = lib.mkIf cfg.enable {
diff --git a/nixos/tests/systemd-repart.nix b/nixos/tests/systemd-repart.nix
index 5d579ae3371d1..22ea8fbd22711 100644
--- a/nixos/tests/systemd-repart.nix
+++ b/nixos/tests/systemd-repart.nix
@@ -56,8 +56,8 @@ let
     # however, creates separate filesystem images without a partition table, so
     # we have to create a disk image manually.
     #
-    # This creates two partitions, an ESP mounted on /dev/vda1 and the root
-    # partition mounted on /dev/vda2
+    # This creates two partitions, an ESP available as /dev/vda1 and the root
+    # partition available as /dev/vda2.
     system.build.diskImage = import ../lib/make-disk-image.nix {
       inherit config pkgs lib;
       # Use a raw format disk so that it can be resized before starting the
@@ -131,4 +131,62 @@ in
       assert "Growing existing partition 1." in systemd_repart_logs
     '';
   };
+
+  create-root = makeTest {
+    name = "systemd-repart-create-root";
+    meta.maintainers = with maintainers; [ nikstur ];
+
+    nodes.machine = { config, lib, pkgs, ... }: {
+      virtualisation.useDefaultFilesystems = false;
+      virtualisation.fileSystems = {
+        "/" = {
+          device = "/dev/disk/by-partlabel/created-root";
+          fsType = "ext4";
+        };
+        "/nix/store" = {
+          device = "/dev/vda2";
+          fsType = "ext4";
+        };
+      };
+
+      # Create an image containing only the Nix store. This enables creating
+      # the root partition with systemd-repart and then successfully booting
+      # into a working system.
+      #
+      # This creates two partitions, an ESP available as /dev/vda1 and the Nix
+      # store available as /dev/vda2.
+      system.build.diskImage = import ../lib/make-disk-image.nix {
+        inherit config pkgs lib;
+        onlyNixStore = true;
+        format = "raw";
+        bootSize = "32M";
+        additionalSpace = "0M";
+        partitionTableType = "efi";
+        installBootLoader = false;
+        copyChannel = false;
+      };
+
+      boot.initrd.systemd.enable = true;
+
+      boot.initrd.systemd.repart.enable = true;
+      boot.initrd.systemd.repart.device = "/dev/vda";
+      systemd.repart.partitions = {
+        "10-root" = {
+          Type = "root";
+          Label = "created-root";
+          Format = "ext4";
+        };
+      };
+    };
+
+    testScript = { nodes, ... }: ''
+      ${useDiskImage nodes.machine}
+
+      machine.start()
+      machine.wait_for_unit("multi-user.target")
+
+      systemd_repart_logs = machine.succeed("journalctl --boot --unit systemd-repart.service")
+      assert "Adding new partition 2 to partition table." in systemd_repart_logs
+    '';
+  };
 }