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 =
25 "${generation}-tmpfiles-user";
26 };
27 };
28 };
29in
30
31{
32
33 name = "sysinit-reactivation";
34
35 meta.maintainers = with lib.maintainers; [ nikstur ];
36
37 nodes.machine = { config, lib, pkgs, ... }: {
38 systemd.services.pre-sysinit-before-tmpfiles = {
39 wantedBy = [ "sysinit.target" ];
40 requiredBy = [ "sysinit-reactivation.target" ];
41 before = [ "systemd-tmpfiles-setup.service" "systemd-tmpfiles-resetup.service" ];
42 unitConfig.DefaultDependencies = false;
43 serviceConfig.Type = "oneshot";
44 serviceConfig.RemainAfterExit = true;
45 environment.USER = "tmpfiles-user";
46 script = "${pkgs.shadow}/bin/useradd $USER";
47 };
48
49 systemd.services.pre-sysinit-after-tmpfiles = {
50 wantedBy = [ "sysinit.target" ];
51 requiredBy = [ "sysinit-reactivation.target" ];
52 after = [ "systemd-tmpfiles-setup.service" "systemd-tmpfiles-resetup.service" ];
53 unitConfig.DefaultDependencies = false;
54 serviceConfig.Type = "oneshot";
55 serviceConfig.RemainAfterExit = true;
56 environment = {
57 NEEDED_PATH = "/run/needed-by-pre-sysinit-after-tmpfiles";
58 PATH_TO_CREATE = "/run/needed-by-post-sysinit";
59 };
60 script = ''
61 if [[ -e $NEEDED_PATH ]]; then
62 touch $PATH_TO_CREATE
63 fi
64 '';
65 };
66
67 systemd.services.post-sysinit = {
68 wantedBy = [ "default.target" ];
69 serviceConfig.Type = "oneshot";
70 serviceConfig.RemainAfterExit = true;
71 environment = {
72 NEEDED_PATH = "/run/needed-by-post-sysinit";
73 PATH_TO_CREATE = "/run/created-by-post-sysinit";
74 };
75 script = ''
76 if [[ -e $NEEDED_PATH ]]; then
77 touch $PATH_TO_CREATE
78 fi
79 '';
80 };
81
82 systemd.tmpfiles.settings.test = {
83 "/run/needed-by-pre-sysinit-after-tmpfiles".f.user =
84 "tmpfiles-user";
85 };
86
87 specialisation = lib.mkMerge [
88 (makeGeneration "second")
89 (makeGeneration "third")
90 ];
91 };
92
93 testScript = { nodes, ... }: ''
94 def switch(generation):
95 toplevel = "${nodes.machine.system.build.toplevel}";
96 machine.succeed(f"{toplevel}/specialisation/{generation}/bin/switch-to-configuration switch")
97
98 machine.wait_for_unit("default.target")
99 machine.succeed("test -e /run/created-by-post-sysinit")
100
101 switch("second")
102 machine.succeed("test -e /run/second-created-by-post-sysinit")
103
104 switch("third")
105 machine.succeed("test -e /run/third-created-by-post-sysinit")
106 '';
107}