1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8
9with utils.systemdUtils.unitOptions;
10with utils.systemdUtils.lib;
11with lib;
12
13let
14 cfg = config.systemd.nspawn;
15
16 checkExec = checkUnitConfig "Exec" [
17 (assertOnlyFields [
18 "Boot"
19 "ProcessTwo"
20 "Parameters"
21 "Environment"
22 "User"
23 "WorkingDirectory"
24 "PivotRoot"
25 "Capability"
26 "DropCapability"
27 "NoNewPrivileges"
28 "KillSignal"
29 "Personality"
30 "MachineID"
31 "PrivateUsers"
32 "NotifyReady"
33 "SystemCallFilter"
34 "LimitCPU"
35 "LimitFSIZE"
36 "LimitDATA"
37 "LimitSTACK"
38 "LimitCORE"
39 "LimitRSS"
40 "LimitNOFILE"
41 "LimitAS"
42 "LimitNPROC"
43 "LimitMEMLOCK"
44 "LimitLOCKS"
45 "LimitSIGPENDING"
46 "LimitMSGQUEUE"
47 "LimitNICE"
48 "LimitRTPRIO"
49 "LimitRTTIME"
50 "OOMScoreAdjust"
51 "CPUAffinity"
52 "Hostname"
53 "ResolvConf"
54 "Timezone"
55 "LinkJournal"
56 "Ephemeral"
57 "AmbientCapability"
58 ])
59 (assertValueOneOf "Boot" boolValues)
60 (assertValueOneOf "ProcessTwo" boolValues)
61 (assertValueOneOf "NotifyReady" boolValues)
62 ];
63
64 checkFiles = checkUnitConfig "Files" [
65 (assertOnlyFields [
66 "ReadOnly"
67 "Volatile"
68 "Bind"
69 "BindReadOnly"
70 "TemporaryFileSystem"
71 "Overlay"
72 "OverlayReadOnly"
73 "PrivateUsersChown"
74 "BindUser"
75 "Inaccessible"
76 "PrivateUsersOwnership"
77 ])
78 (assertValueOneOf "ReadOnly" boolValues)
79 (assertValueOneOf "Volatile" (boolValues ++ [ "state" ]))
80 (assertValueOneOf "PrivateUsersChown" boolValues)
81 (assertValueOneOf "PrivateUsersOwnership" [
82 "off"
83 "chown"
84 "map"
85 "auto"
86 ])
87 ];
88
89 checkNetwork = checkUnitConfig "Network" [
90 (assertOnlyFields [
91 "Private"
92 "VirtualEthernet"
93 "VirtualEthernetExtra"
94 "Interface"
95 "MACVLAN"
96 "IPVLAN"
97 "Bridge"
98 "Zone"
99 "Port"
100 ])
101 (assertValueOneOf "Private" boolValues)
102 (assertValueOneOf "VirtualEthernet" boolValues)
103 ];
104
105 instanceOptions = {
106 options = (getAttrs [ "enable" ] sharedOptions) // {
107 execConfig = mkOption {
108 default = { };
109 example = {
110 Parameters = "/bin/sh";
111 };
112 type = types.addCheck (types.attrsOf unitOption) checkExec;
113 description = ''
114 Each attribute in this set specifies an option in the
115 `[Exec]` section of this unit. See
116 {manpage}`systemd.nspawn(5)` for details.
117 '';
118 };
119
120 filesConfig = mkOption {
121 default = { };
122 example = {
123 Bind = [ "/home/alice" ];
124 };
125 type = types.addCheck (types.attrsOf unitOption) checkFiles;
126 description = ''
127 Each attribute in this set specifies an option in the
128 `[Files]` section of this unit. See
129 {manpage}`systemd.nspawn(5)` for details.
130 '';
131 };
132
133 networkConfig = mkOption {
134 default = { };
135 example = {
136 Private = false;
137 };
138 type = types.addCheck (types.attrsOf unitOption) checkNetwork;
139 description = ''
140 Each attribute in this set specifies an option in the
141 `[Network]` section of this unit. See
142 {manpage}`systemd.nspawn(5)` for details.
143 '';
144 };
145 };
146
147 };
148
149 instanceToUnit =
150 name: def:
151 let
152 base = {
153 text = ''
154 [Exec]
155 ${attrsToSection def.execConfig}
156
157 [Files]
158 ${attrsToSection def.filesConfig}
159
160 [Network]
161 ${attrsToSection def.networkConfig}
162 '';
163 }
164 // def;
165 in
166 base // { unit = makeUnit name base; };
167
168in
169{
170
171 options = {
172
173 systemd.nspawn = mkOption {
174 default = { };
175 type = with types; attrsOf (submodule instanceOptions);
176 description = "Definition of systemd-nspawn configurations.";
177 };
178
179 };
180
181 config =
182 let
183 units = mapAttrs' (
184 n: v:
185 let
186 nspawnFile = "${n}.nspawn";
187 in
188 nameValuePair nspawnFile (instanceToUnit nspawnFile v)
189 ) cfg;
190 in
191 mkMerge [
192 (mkIf (cfg != { }) {
193 environment.etc."systemd/nspawn".source = mkIf (cfg != { }) (generateUnits {
194 allowCollisions = false;
195 type = "nspawn";
196 inherit units;
197 upstreamUnits = [ ];
198 upstreamWants = [ ];
199 });
200 })
201 {
202 systemd.targets.multi-user.wants = [ "machines.target" ];
203 systemd.services."systemd-nspawn@".environment = {
204 SYSTEMD_NSPAWN_UNIFIED_HIERARCHY = mkDefault "1";
205 };
206 }
207 ];
208}