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

nixos/systemd-repart: enable creating root partition

Changed files
+117 -33
nixos
modules
system
boot
systemd
tests
+57 -31
nixos/modules/system/boot/systemd/repart.nix
···
-
{ config, pkgs, lib, ... }:
+
{ config, pkgs, lib, utils, ... }:
let
cfg = config.systemd.repart;
···
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.
+
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`.
-
'';
+
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 = {
···
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 {
+60 -2
nixos/tests/systemd-repart.nix
···
# 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
···
systemd_repart_logs = machine.succeed("journalctl --unit systemd-repart.service")
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
'';
};
}