nixos/systemd: expose factory reset functionality and add repart test case (#481696)

This commit is contained in:
nikstur
2026-01-22 10:21:14 +00:00
committed by GitHub
3 changed files with 113 additions and 0 deletions
+7
View File
@@ -213,6 +213,12 @@ let
# Capsule support
"capsule@.service"
"capsule.slice"
# Factory reset
"factory-reset.target"
"systemd-factory-reset-request.service"
"systemd-factory-reset-reboot.service"
"systemd-tpm2-clear.service"
]
++ cfg.additionalUpstreamSystemUnits;
@@ -222,6 +228,7 @@ let
"local-fs.target.wants"
"multi-user.target.wants"
"timers.target.wants"
"factory-reset.target.wants"
];
proxy_env = config.networking.proxy.envVars;
@@ -65,6 +65,8 @@ let
"syslog.socket"
"systemd-ask-password-console.path"
"systemd-ask-password-console.service"
"systemd-factory-reset-complete.service"
"factory-reset-now.target"
"systemd-fsck@.service"
"systemd-halt.service"
"systemd-hibernate-resume.service"
@@ -555,6 +557,7 @@ in
"${cfg.package}/lib/systemd/systemd-sysctl"
"${cfg.package}/lib/systemd/systemd-bsod"
"${cfg.package}/lib/systemd/systemd-sysroot-fstab-check"
"${cfg.package}/lib/systemd/systemd-factory-reset"
# generators
"${cfg.package}/lib/systemd/system-generators/systemd-debug-generator"
@@ -562,6 +565,7 @@ in
"${cfg.package}/lib/systemd/system-generators/systemd-gpt-auto-generator"
"${cfg.package}/lib/systemd/system-generators/systemd-hibernate-resume-generator"
"${cfg.package}/lib/systemd/system-generators/systemd-run-generator"
"${cfg.package}/lib/systemd/system-generators/systemd-factory-reset-generator"
# utilities needed by systemd
"${cfg.package.util-linux}/bin/mount"
+102
View File
@@ -277,4 +277,106 @@ in
assert "Adding new partition 2 to partition table." in systemd_repart_logs
'';
};
factory-reset = makeTest {
name = "systemd-repart-factory-reset";
meta.maintainers = with maintainers; [ willibutz ];
nodes.machine =
{ pkgs, lib, ... }:
{
imports = [ common ];
virtualisation = {
useEFIBoot = true;
tpm.enable = true;
efi.OVMF = pkgs.OVMFFull;
useDefaultFilesystems = false;
fileSystems = {
"/state" = {
device = "/dev/mapper/state";
fsType = "ext4";
};
};
};
boot = {
loader.systemd-boot.enable = true;
initrd = {
systemd = {
enable = true;
# avoids reaching cryptsetup.target before recreation of the
# "state" volume completed, during the factory reset
services.systemd-repart.before = [
"systemd-cryptsetup@state.service"
];
repart = {
enable = true;
extraArgs = [
"--tpm2-pcrs=platform-code"
];
};
};
luks.devices = lib.mkVMOverride {
state = {
device = "/dev/disk/by-partlabel/state";
crypttabExtraOpts = [ "tpm2-device=auto" ];
};
};
};
};
systemd.repart.partitions = {
"10-esp".Type = "esp";
"20-root".Type = "linux-generic";
"30-state" = {
Type = "linux-generic";
Label = "state";
Format = "ext4";
Encrypt = "tpm2";
SizeMinBytes = "64M";
SizeMaxBytes = "64M";
FactoryReset = true;
};
};
# doesn't actually reboot through the service because otherwise the test
# instrumentation becomes very unreliable, instead uses machine.reboot()
systemd.services.systemd-factory-reset-reboot.enable = false;
};
testScript =
{ nodes, ... }:
# python
''
${useDiskImage {
inherit (nodes) machine;
sizeDiff = "+64M";
}}
machine.start(allow_reboot=True)
machine.wait_for_unit("default.target")
first_uuid = machine.succeed("blkid -s UUID -o value /dev/disk/by-label/state")
machine.succeed("mountpoint /state")
machine.succeed("touch /state/foo")
with subtest("factory reset requested through target"):
machine.systemctl("start factory-reset.target")
# reboot manually to keep control over test vm
machine.reboot()
machine.wait_for_unit("default.target")
with subtest("state partition recreated and empty after reset"):
second_uuid = machine.succeed("blkid -s UUID -o value /dev/disk/by-label/state")
t.assertNotEqual(first_uuid, second_uuid)
machine.succeed("mountpoint /state")
machine.fail("test -e /state/foo")
'';
};
}