Unverified Commit 636e03be authored by Will Fancher's avatar Will Fancher Committed by GitHub
Browse files

Merge pull request #232533 from nikstur/systemd-repart-create-root

nixos/systemd-repart: enable creating root partition
parents c7eb6521 ef80e110
Loading
Loading
Loading
Loading
+58 −32
Original line number Diff line number Diff line
{ config, pkgs, lib, ... }:
{ config, pkgs, lib, utils, ... }:

let
  cfg = config.systemd.repart;
@@ -26,7 +26,8 @@ let
in
{
  options = {
    boot.initrd.systemd.repart.enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
    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.
@@ -36,6 +37,20 @@ in
        '';
      };

      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 = {
      enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
        description = lib.mdDoc ''
@@ -84,7 +99,11 @@ in
      contents."/etc/repart.d".source = definitionsDirectory;

      # Override defaults in upstream unit.
      services.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
@@ -98,16 +117,23 @@ in
              # 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, you have to explicitly tell it which device to
        # operate on.
        after = [ "sysroot.mount" ];
          # 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 ];
        };
    };

+60 −2
Original line number Diff line number Diff line
@@ -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
    '';
  };
}