1import ./make-test-python.nix ({ pkgs, ... }: {
2 name = "systemd";
3
4 machine = { lib, ... }: {
5 imports = [ common/user-account.nix common/x11.nix ];
6
7 virtualisation.emptyDiskImages = [ 512 512 ];
8
9 environment.systemPackages = [ pkgs.cryptsetup ];
10
11 virtualisation.fileSystems = {
12 "/test-x-initrd-mount" = {
13 device = "/dev/vdb";
14 fsType = "ext2";
15 autoFormat = true;
16 noCheck = true;
17 options = [ "x-initrd.mount" ];
18 };
19 };
20
21 systemd.extraConfig = "DefaultEnvironment=\"XXX_SYSTEM=foo\"";
22 systemd.user.extraConfig = "DefaultEnvironment=\"XXX_USER=bar\"";
23 services.journald.extraConfig = "Storage=volatile";
24 test-support.displayManager.auto.user = "alice";
25
26 systemd.shutdown.test = pkgs.writeScript "test.shutdown" ''
27 #!${pkgs.runtimeShell}
28 PATH=${lib.makeBinPath (with pkgs; [ util-linux coreutils ])}
29 mount -t 9p shared -o trans=virtio,version=9p2000.L /tmp/shared
30 touch /tmp/shared/shutdown-test
31 umount /tmp/shared
32 '';
33
34 systemd.services.testservice1 = {
35 description = "Test Service 1";
36 wantedBy = [ "multi-user.target" ];
37 serviceConfig.Type = "oneshot";
38 script = ''
39 if [ "$XXX_SYSTEM" = foo ]; then
40 touch /system_conf_read
41 fi
42 '';
43 };
44
45 systemd.user.services.testservice2 = {
46 description = "Test Service 2";
47 wantedBy = [ "default.target" ];
48 serviceConfig.Type = "oneshot";
49 script = ''
50 if [ "$XXX_USER" = bar ]; then
51 touch "$HOME/user_conf_read"
52 fi
53 '';
54 };
55
56 systemd.watchdog = {
57 device = "/dev/watchdog";
58 runtimeTime = "30s";
59 rebootTime = "10min";
60 kexecTime = "5min";
61 };
62 };
63
64 testScript = ''
65 import re
66 import subprocess
67
68 machine.wait_for_x()
69 # wait for user services
70 machine.wait_for_unit("default.target", "alice")
71
72 # Regression test for https://github.com/NixOS/nixpkgs/issues/35415
73 with subtest("configuration files are recognized by systemd"):
74 machine.succeed("test -e /system_conf_read")
75 machine.succeed("test -e /home/alice/user_conf_read")
76 machine.succeed("test -z $(ls -1 /var/log/journal)")
77
78 # Regression test for https://github.com/NixOS/nixpkgs/issues/50273
79 with subtest("DynamicUser actually allocates a user"):
80 assert "iamatest" in machine.succeed(
81 "systemd-run --pty --property=Type=oneshot --property=DynamicUser=yes --property=User=iamatest whoami"
82 )
83
84 with subtest("regression test for https://bugs.freedesktop.org/show_bug.cgi?id=77507"):
85 retcode, output = machine.execute("systemctl status testservice1.service")
86 assert retcode in [0, 3] # https://bugs.freedesktop.org/show_bug.cgi?id=77507
87
88 # Regression test for https://github.com/NixOS/nixpkgs/issues/35268
89 with subtest("file system with x-initrd.mount is not unmounted"):
90 machine.succeed("mountpoint -q /test-x-initrd-mount")
91 machine.shutdown()
92
93 subprocess.check_call(
94 [
95 "qemu-img",
96 "convert",
97 "-O",
98 "raw",
99 "vm-state-machine/empty0.qcow2",
100 "x-initrd-mount.raw",
101 ]
102 )
103 extinfo = subprocess.check_output(
104 [
105 "${pkgs.e2fsprogs}/bin/dumpe2fs",
106 "x-initrd-mount.raw",
107 ]
108 ).decode("utf-8")
109 assert (
110 re.search(r"^Filesystem state: *clean$", extinfo, re.MULTILINE) is not None
111 ), ("File system was not cleanly unmounted: " + extinfo)
112
113 # Regression test for https://github.com/NixOS/nixpkgs/pull/91232
114 with subtest("setting transient hostnames works"):
115 machine.succeed("hostnamectl set-hostname --transient machine-transient")
116 machine.fail("hostnamectl set-hostname machine-all")
117
118 with subtest("systemd-shutdown works"):
119 machine.shutdown()
120 machine.wait_for_unit("multi-user.target")
121 machine.succeed("test -e /tmp/shared/shutdown-test")
122
123 # Test settings from /etc/sysctl.d/50-default.conf are applied
124 with subtest("systemd sysctl settings are applied"):
125 machine.wait_for_unit("multi-user.target")
126 assert "fq_codel" in machine.succeed("sysctl net.core.default_qdisc")
127
128 # Test systemd is configured to manage a watchdog
129 with subtest("systemd manages hardware watchdog"):
130 machine.wait_for_unit("multi-user.target")
131
132 # It seems that the device's path doesn't appear in 'systemctl show' so
133 # check it separately.
134 assert "WatchdogDevice=/dev/watchdog" in machine.succeed(
135 "cat /etc/systemd/system.conf"
136 )
137
138 output = machine.succeed("systemctl show | grep Watchdog")
139 # assert "RuntimeWatchdogUSec=30s" in output
140 # for some reason RuntimeWatchdogUSec, doesn't seem to be updated in here.
141 assert "RebootWatchdogUSec=10min" in output
142 assert "KExecWatchdogUSec=5min" in output
143
144 # Test systemd cryptsetup support
145 with subtest("systemd successfully reads /etc/crypttab and unlocks volumes"):
146 # create a luks volume and put a filesystem on it
147 machine.succeed(
148 "echo -n supersecret | cryptsetup luksFormat -q /dev/vdc -",
149 "echo -n supersecret | cryptsetup luksOpen --key-file - /dev/vdc foo",
150 "mkfs.ext3 /dev/mapper/foo",
151 )
152
153 # create a keyfile and /etc/crypttab
154 machine.succeed("echo -n supersecret > /var/lib/luks-keyfile")
155 machine.succeed("chmod 600 /var/lib/luks-keyfile")
156 machine.succeed("echo 'luks1 /dev/vdc /var/lib/luks-keyfile luks' > /etc/crypttab")
157
158 # after a reboot, systemd should unlock the volume and we should be able to mount it
159 machine.shutdown()
160 machine.succeed("systemctl status systemd-cryptsetup@luks1.service")
161 machine.succeed("mkdir -p /tmp/luks1")
162 machine.succeed("mount /dev/mapper/luks1 /tmp/luks1")
163
164 # Do some IP traffic
165 output_ping = machine.succeed(
166 "systemd-run --wait -- /run/wrappers/bin/ping -c 1 127.0.0.1 2>&1"
167 )
168
169 with subtest("systemd reports accounting data on system.slice"):
170 output = machine.succeed("systemctl status system.slice")
171 assert "CPU:" in output
172 assert "Memory:" in output
173
174 assert "IP:" in output
175 assert "0B in, 0B out" not in output
176
177 assert "IO:" in output
178 assert "0B read, 0B written" not in output
179
180 with subtest("systemd per-unit accounting works"):
181 assert "IP traffic received: 84B" in output_ping
182 assert "IP traffic sent: 84B" in output_ping
183 '';
184})