1# This runs to two scenarios but in one tests:
2# - A post-sysinit service needs to be restarted AFTER tmpfiles was restarted.
3# - A service needs to be restarted BEFORE tmpfiles is restarted
4
5{ lib, ... }:
6
7let
8 makeGeneration = generation: {
9 "${generation}".configuration = {
10 systemd.services.pre-sysinit-before-tmpfiles.environment.USER =
11 lib.mkForce "${generation}-tmpfiles-user";
12
13 systemd.services.pre-sysinit-after-tmpfiles.environment = {
14 NEEDED_PATH = lib.mkForce "/run/${generation}-needed-by-pre-sysinit-after-tmpfiles";
15 PATH_TO_CREATE = lib.mkForce "/run/${generation}-needed-by-post-sysinit";
16 };
17
18 systemd.services.post-sysinit.environment = {
19 NEEDED_PATH = lib.mkForce "/run/${generation}-needed-by-post-sysinit";
20 PATH_TO_CREATE = lib.mkForce "/run/${generation}-created-by-post-sysinit";
21 };
22
23 systemd.tmpfiles.settings.test = lib.mkForce {
24 "/run/${generation}-needed-by-pre-sysinit-after-tmpfiles".f.user = "${generation}-tmpfiles-user";
25 };
26 };
27 };
28in
29
30{
31
32 name = "sysinit-reactivation";
33
34 meta.maintainers = with lib.maintainers; [ nikstur ];
35
36 nodes.machine =
37 {
38 config,
39 lib,
40 pkgs,
41 ...
42 }:
43 {
44 systemd.services.pre-sysinit-before-tmpfiles = {
45 wantedBy = [ "sysinit.target" ];
46 requiredBy = [ "sysinit-reactivation.target" ];
47 before = [
48 "systemd-tmpfiles-setup.service"
49 "systemd-tmpfiles-resetup.service"
50 ];
51 unitConfig.DefaultDependencies = false;
52 serviceConfig.Type = "oneshot";
53 serviceConfig.RemainAfterExit = true;
54 environment.USER = "tmpfiles-user";
55 script = "${pkgs.shadow}/bin/useradd $USER";
56 };
57
58 systemd.services.pre-sysinit-after-tmpfiles = {
59 wantedBy = [ "sysinit.target" ];
60 requiredBy = [ "sysinit-reactivation.target" ];
61 after = [
62 "systemd-tmpfiles-setup.service"
63 "systemd-tmpfiles-resetup.service"
64 ];
65 unitConfig.DefaultDependencies = false;
66 serviceConfig.Type = "oneshot";
67 serviceConfig.RemainAfterExit = true;
68 environment = {
69 NEEDED_PATH = "/run/needed-by-pre-sysinit-after-tmpfiles";
70 PATH_TO_CREATE = "/run/needed-by-post-sysinit";
71 };
72 script = ''
73 if [[ -e $NEEDED_PATH ]]; then
74 touch $PATH_TO_CREATE
75 fi
76 '';
77 };
78
79 systemd.services.post-sysinit = {
80 wantedBy = [ "default.target" ];
81 serviceConfig.Type = "oneshot";
82 serviceConfig.RemainAfterExit = true;
83 environment = {
84 NEEDED_PATH = "/run/needed-by-post-sysinit";
85 PATH_TO_CREATE = "/run/created-by-post-sysinit";
86 };
87 script = ''
88 if [[ -e $NEEDED_PATH ]]; then
89 touch $PATH_TO_CREATE
90 fi
91 '';
92 };
93
94 systemd.tmpfiles.settings.test = {
95 "/run/needed-by-pre-sysinit-after-tmpfiles".f.user = "tmpfiles-user";
96 };
97
98 specialisation = lib.mkMerge [
99 (makeGeneration "second")
100 (makeGeneration "third")
101 ];
102 };
103
104 testScript =
105 { nodes, ... }:
106 ''
107 def switch(generation):
108 toplevel = "${nodes.machine.system.build.toplevel}";
109 machine.succeed(f"{toplevel}/specialisation/{generation}/bin/switch-to-configuration switch")
110
111 machine.wait_for_unit("default.target")
112 machine.succeed("test -e /run/created-by-post-sysinit")
113
114 switch("second")
115 machine.succeed("test -e /run/second-created-by-post-sysinit")
116
117 switch("third")
118 machine.succeed("test -e /run/third-created-by-post-sysinit")
119 '';
120}