mirror of
https://github.com/SebastianWendel/nixpkgs.git
synced 2024-09-20 04:19:00 +02:00
nixos/systemd-repart: init
This commit is contained in:
parent
8a230e9694
commit
4700198654
|
@ -1301,6 +1301,7 @@
|
||||||
./system/boot/systemd/logind.nix
|
./system/boot/systemd/logind.nix
|
||||||
./system/boot/systemd/nspawn.nix
|
./system/boot/systemd/nspawn.nix
|
||||||
./system/boot/systemd/oomd.nix
|
./system/boot/systemd/oomd.nix
|
||||||
|
./system/boot/systemd/repart.nix
|
||||||
./system/boot/systemd/shutdown.nix
|
./system/boot/systemd/shutdown.nix
|
||||||
./system/boot/systemd/tmpfiles.nix
|
./system/boot/systemd/tmpfiles.nix
|
||||||
./system/boot/systemd/user.nix
|
./system/boot/systemd/user.nix
|
||||||
|
|
101
nixos/modules/system/boot/systemd/repart.nix
Normal file
101
nixos/modules/system/boot/systemd/repart.nix
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.boot.initrd.systemd.repart;
|
||||||
|
|
||||||
|
writeDefinition = name: partitionConfig: pkgs.writeText
|
||||||
|
"${name}.conf"
|
||||||
|
(lib.generators.toINI { } { Partition = partitionConfig; });
|
||||||
|
|
||||||
|
listOfDefinitions = lib.mapAttrsToList
|
||||||
|
writeDefinition
|
||||||
|
(lib.filterAttrs (k: _: !(lib.hasPrefix "_" k)) cfg.partitions);
|
||||||
|
|
||||||
|
# Create a directory in the store that contains a copy of all definition
|
||||||
|
# files. This is then passed to systemd-repart in the initrd so it can access
|
||||||
|
# the definition files after the sysroot has been mounted but before
|
||||||
|
# activation. This needs a hard copy of the files and not just symlinks
|
||||||
|
# because otherwise the files do not show up in the sysroot.
|
||||||
|
definitionsDirectory = pkgs.runCommand "systemd-repart-definitions" { } ''
|
||||||
|
mkdir -p $out
|
||||||
|
${(lib.concatStringsSep "\n"
|
||||||
|
(map (pkg: "cp ${pkg} $out/${pkg.name}") listOfDefinitions)
|
||||||
|
)}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.boot.initrd.systemd.repart = {
|
||||||
|
enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Grow and add partitions to a partition table a boot time in the initrd.
|
||||||
|
systemd-repart only works with GPT partition tables.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
partitions = lib.mkOption {
|
||||||
|
type = with lib.types; attrsOf (attrsOf (oneOf [ str int bool ]));
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
"10-root" = {
|
||||||
|
Type = "root";
|
||||||
|
};
|
||||||
|
"20-home" = {
|
||||||
|
Type = "home";
|
||||||
|
SizeMinBytes = "512M";
|
||||||
|
SizeMaxBytes = "2G";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Specify partitions as a set of the names of the definition files as the
|
||||||
|
key and the partition configuration as its value. The partition
|
||||||
|
configuration can use all upstream options. See <link
|
||||||
|
xlink:href="https://www.freedesktop.org/software/systemd/man/repart.d.html"/>
|
||||||
|
for all available options.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
# Link the definitions into /etc so that they are included in the
|
||||||
|
# /nix/store of the sysroot. This also allows the user to run the
|
||||||
|
# systemd-repart binary after activation manually while automatically
|
||||||
|
# picking up the definition files.
|
||||||
|
environment.etc."repart.d".source = definitionsDirectory;
|
||||||
|
|
||||||
|
boot.initrd.systemd = {
|
||||||
|
additionalUpstreamUnits = [
|
||||||
|
"systemd-repart.service"
|
||||||
|
];
|
||||||
|
|
||||||
|
storePaths = [
|
||||||
|
"${config.boot.initrd.systemd.package}/bin/systemd-repart"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Override defaults in upstream unit.
|
||||||
|
services.systemd-repart = {
|
||||||
|
# Unset the coniditions as they cannot be met before activation because
|
||||||
|
# the definition files are not stored in the expected locations.
|
||||||
|
unitConfig.ConditionDirectoryNotEmpty = [
|
||||||
|
" " # required to unset the previous value.
|
||||||
|
];
|
||||||
|
serviceConfig = {
|
||||||
|
# systemd-repart runs before the activation script. Thus we cannot
|
||||||
|
# rely on them being linked in /etc already. Instead we have to
|
||||||
|
# explicitly pass their location in the sysroot to the binary.
|
||||||
|
ExecStart = [
|
||||||
|
" " # required to unset the previous value.
|
||||||
|
''${config.boot.initrd.systemd.package}/bin/systemd-repart \
|
||||||
|
--definitions=/sysroot${definitionsDirectory} \
|
||||||
|
--dry-run=no
|
||||||
|
''
|
||||||
|
];
|
||||||
|
};
|
||||||
|
# Because the initrd does not have the `initrd-usr-fs.target` the
|
||||||
|
# upestream unit runs too early in the boot process, before the sysroot
|
||||||
|
# is available. However, systemd-repart needs access to the sysroot to
|
||||||
|
# find the definition files.
|
||||||
|
after = [ "sysroot.mount" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -656,6 +656,7 @@ in {
|
||||||
systemd-nspawn = handleTest ./systemd-nspawn.nix {};
|
systemd-nspawn = handleTest ./systemd-nspawn.nix {};
|
||||||
systemd-oomd = handleTest ./systemd-oomd.nix {};
|
systemd-oomd = handleTest ./systemd-oomd.nix {};
|
||||||
systemd-portabled = handleTest ./systemd-portabled.nix {};
|
systemd-portabled = handleTest ./systemd-portabled.nix {};
|
||||||
|
systemd-repart = handleTest ./systemd-repart.nix {};
|
||||||
systemd-shutdown = handleTest ./systemd-shutdown.nix {};
|
systemd-shutdown = handleTest ./systemd-shutdown.nix {};
|
||||||
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
|
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
|
||||||
systemd-user-tmpfiles-rules = handleTest ./systemd-user-tmpfiles-rules.nix {};
|
systemd-user-tmpfiles-rules = handleTest ./systemd-user-tmpfiles-rules.nix {};
|
||||||
|
|
108
nixos/tests/systemd-repart.nix
Normal file
108
nixos/tests/systemd-repart.nix
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
{ system ? builtins.currentSystem
|
||||||
|
, config ? { }
|
||||||
|
, pkgs ? import ../.. { inherit system config; }
|
||||||
|
}:
|
||||||
|
|
||||||
|
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||||
|
with pkgs.lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
# A testScript fragment that prepares a disk with some empty, unpartitioned
|
||||||
|
# space. and uses it to boot the test with. Takes a single argument `machine`
|
||||||
|
# from which the diskImage is extraced.
|
||||||
|
useDiskImage = machine: ''
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
tmp_disk_image = tempfile.NamedTemporaryFile()
|
||||||
|
|
||||||
|
shutil.copyfile("${machine.system.build.diskImage}/nixos.img", tmp_disk_image.name)
|
||||||
|
|
||||||
|
subprocess.run([
|
||||||
|
"${pkgs.qemu}/bin/qemu-img",
|
||||||
|
"resize",
|
||||||
|
"-f",
|
||||||
|
"raw",
|
||||||
|
tmp_disk_image.name,
|
||||||
|
"+32M",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Fix the GPT table by moving the backup table to the end of the enlarged
|
||||||
|
# disk image. This is necessary because we increased the size of the disk
|
||||||
|
# before. The disk needs to be a raw disk because sgdisk can only run on
|
||||||
|
# raw images.
|
||||||
|
subprocess.run([
|
||||||
|
"${pkgs.gptfdisk}/bin/sgdisk",
|
||||||
|
"--move-second-header",
|
||||||
|
tmp_disk_image.name,
|
||||||
|
])
|
||||||
|
|
||||||
|
# Set NIX_DISK_IMAGE so that the qemu script finds the right disk image.
|
||||||
|
os.environ['NIX_DISK_IMAGE'] = tmp_disk_image.name
|
||||||
|
'';
|
||||||
|
|
||||||
|
common = { config, pkgs, lib, ... }: {
|
||||||
|
virtualisation.useDefaultFilesystems = false;
|
||||||
|
virtualisation.fileSystems = {
|
||||||
|
"/" = {
|
||||||
|
device = "/dev/vda2";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.systemd.enable = true;
|
||||||
|
boot.initrd.systemd.repart.enable = true;
|
||||||
|
|
||||||
|
# systemd-repart operates on disks with a partition table. The qemu module,
|
||||||
|
# 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
|
||||||
|
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
|
||||||
|
# test VM.
|
||||||
|
format = "raw";
|
||||||
|
# Keep the image as small as possible but leave some room for changes.
|
||||||
|
bootSize = "32M";
|
||||||
|
additionalSpace = "0M";
|
||||||
|
# GPT with an EFI System Partition is the typical use case for
|
||||||
|
# systemd-repart because it does not support MBR.
|
||||||
|
partitionTableType = "efi";
|
||||||
|
# We do not actually care much about the content of the partitions, so we
|
||||||
|
# do not need a bootloader installed.
|
||||||
|
installBootLoader = false;
|
||||||
|
# Improve determinism by not copying a channel.
|
||||||
|
copyChannel = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
basic = makeTest {
|
||||||
|
name = "systemd-repart";
|
||||||
|
meta.maintainers = with maintainers; [ nikstur ];
|
||||||
|
|
||||||
|
nodes.machine = { config, pkgs, ... }: {
|
||||||
|
imports = [ common ];
|
||||||
|
|
||||||
|
boot.initrd.systemd.repart.partitions = {
|
||||||
|
"10-root" = {
|
||||||
|
Type = "linux-generic";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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 "Growing existing partition 1." in systemd_repart_logs
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue