1{ config, lib }:
2
3with lib;
4with import ./systemd-lib.nix { inherit config lib pkgs; };
5
6let
7 checkService = checkUnitConfig "Service" [
8 (assertValueOneOf "Type" [
9 "simple" "forking" "oneshot" "dbus" "notify" "idle"
10 ])
11 (assertValueOneOf "Restart" [
12 "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always"
13 ])
14 ];
15
16in rec {
17
18 unitOption = mkOptionType {
19 name = "systemd option";
20 merge = loc: defs:
21 let
22 defs' = filterOverrides defs;
23 defs'' = getValues defs';
24 in
25 if isList (head defs'')
26 then concatLists defs''
27 else mergeOneOption loc defs';
28 };
29
30 sharedOptions = {
31
32 enable = mkOption {
33 default = true;
34 type = types.bool;
35 description = ''
36 If set to false, this unit will be a symlink to
37 /dev/null. This is primarily useful to prevent specific
38 template instances (e.g. <literal>serial-getty@ttyS0</literal>)
39 from being started.
40 '';
41 };
42
43 requiredBy = mkOption {
44 default = [];
45 type = types.listOf types.str;
46 description = "Units that require (i.e. depend on and need to go down with) this unit.";
47 };
48
49 wantedBy = mkOption {
50 default = [];
51 type = types.listOf types.str;
52 description = "Units that want (i.e. depend on) this unit.";
53 };
54
55 aliases = mkOption {
56 default = [];
57 type = types.listOf types.str;
58 description = "Aliases of that unit.";
59 };
60
61 };
62
63 concreteUnitOptions = sharedOptions // {
64
65 text = mkOption {
66 type = types.nullOr types.str;
67 default = null;
68 description = "Text of this systemd unit.";
69 };
70
71 unit = mkOption {
72 internal = true;
73 description = "The generated unit.";
74 };
75
76 };
77
78 commonUnitOptions = sharedOptions // {
79
80 description = mkOption {
81 default = "";
82 type = types.str;
83 description = "Description of this unit used in systemd messages and progress indicators.";
84 };
85
86 documentation = mkOption {
87 default = [];
88 type = types.listOf types.str;
89 description = "A list of URIs referencing documentation for this unit or its configuration.";
90 };
91
92 requires = mkOption {
93 default = [];
94 type = types.listOf types.str;
95 description = ''
96 Start the specified units when this unit is started, and stop
97 this unit when the specified units are stopped or fail.
98 '';
99 };
100
101 wants = mkOption {
102 default = [];
103 type = types.listOf types.str;
104 description = ''
105 Start the specified units when this unit is started.
106 '';
107 };
108
109 after = mkOption {
110 default = [];
111 type = types.listOf types.str;
112 description = ''
113 If the specified units are started at the same time as
114 this unit, delay this unit until they have started.
115 '';
116 };
117
118 before = mkOption {
119 default = [];
120 type = types.listOf types.str;
121 description = ''
122 If the specified units are started at the same time as
123 this unit, delay them until this unit has started.
124 '';
125 };
126
127 bindsTo = mkOption {
128 default = [];
129 type = types.listOf types.str;
130 description = ''
131 Like ‘requires’, but in addition, if the specified units
132 unexpectedly disappear, this unit will be stopped as well.
133 '';
134 };
135
136 partOf = mkOption {
137 default = [];
138 type = types.listOf types.str;
139 description = ''
140 If the specified units are stopped or restarted, then this
141 unit is stopped or restarted as well.
142 '';
143 };
144
145 conflicts = mkOption {
146 default = [];
147 type = types.listOf types.str;
148 description = ''
149 If the specified units are started, then this unit is stopped
150 and vice versa.
151 '';
152 };
153
154 requisite = mkOption {
155 default = [];
156 type = types.listOf types.str;
157 description = ''
158 Similar to requires. However if the units listed are not started,
159 they will not be started and the transaction will fail.
160 '';
161 };
162
163 unitConfig = mkOption {
164 default = {};
165 example = { RequiresMountsFor = "/data"; };
166 type = types.attrsOf unitOption;
167 description = ''
168 Each attribute in this set specifies an option in the
169 <literal>[Unit]</literal> section of the unit. See
170 <citerefentry><refentrytitle>systemd.unit</refentrytitle>
171 <manvolnum>5</manvolnum></citerefentry> for details.
172 '';
173 };
174
175 restartTriggers = mkOption {
176 default = [];
177 type = types.listOf types.unspecified;
178 description = ''
179 An arbitrary list of items such as derivations. If any item
180 in the list changes between reconfigurations, the service will
181 be restarted.
182 '';
183 };
184
185 onFailure = mkOption {
186 default = [];
187 type = types.listOf types.str;
188 description = ''
189 A list of one or more units that are activated when
190 this unit enters the "failed" state.
191 '';
192 };
193
194 };
195
196
197 serviceOptions = commonUnitOptions // {
198
199 environment = mkOption {
200 default = {};
201 type = types.attrs; # FIXME
202 example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
203 description = "Environment variables passed to the service's processes.";
204 };
205
206 path = mkOption {
207 default = [];
208 apply = ps: "${makeBinPath ps}:${makeSearchPathOutput "bin" "sbin" ps}";
209 description = ''
210 Packages added to the service's <envar>PATH</envar>
211 environment variable. Both the <filename>bin</filename>
212 and <filename>sbin</filename> subdirectories of each
213 package are added.
214 '';
215 };
216
217 serviceConfig = mkOption {
218 default = {};
219 example =
220 { StartLimitInterval = 10;
221 RestartSec = 5;
222 };
223 type = types.addCheck (types.attrsOf unitOption) checkService;
224 description = ''
225 Each attribute in this set specifies an option in the
226 <literal>[Service]</literal> section of the unit. See
227 <citerefentry><refentrytitle>systemd.service</refentrytitle>
228 <manvolnum>5</manvolnum></citerefentry> for details.
229 '';
230 };
231
232 script = mkOption {
233 type = types.lines;
234 default = "";
235 description = "Shell commands executed as the service's main process.";
236 };
237
238 scriptArgs = mkOption {
239 type = types.str;
240 default = "";
241 description = "Arguments passed to the main process script.";
242 };
243
244 preStart = mkOption {
245 type = types.lines;
246 default = "";
247 description = ''
248 Shell commands executed before the service's main process
249 is started.
250 '';
251 };
252
253 postStart = mkOption {
254 type = types.lines;
255 default = "";
256 description = ''
257 Shell commands executed after the service's main process
258 is started.
259 '';
260 };
261
262 reload = mkOption {
263 type = types.lines;
264 default = "";
265 description = ''
266 Shell commands executed when the service's main process
267 is reloaded.
268 '';
269 };
270
271 preStop = mkOption {
272 type = types.lines;
273 default = "";
274 description = ''
275 Shell commands executed to stop the service.
276 '';
277 };
278
279 postStop = mkOption {
280 type = types.lines;
281 default = "";
282 description = ''
283 Shell commands executed after the service's main process
284 has exited.
285 '';
286 };
287
288 restartIfChanged = mkOption {
289 type = types.bool;
290 default = true;
291 description = ''
292 Whether the service should be restarted during a NixOS
293 configuration switch if its definition has changed.
294 '';
295 };
296
297 reloadIfChanged = mkOption {
298 type = types.bool;
299 default = false;
300 description = ''
301 Whether the service should be reloaded during a NixOS
302 configuration switch if its definition has changed. If
303 enabled, the value of <option>restartIfChanged</option> is
304 ignored.
305 '';
306 };
307
308 stopIfChanged = mkOption {
309 type = types.bool;
310 default = true;
311 description = ''
312 If set, a changed unit is restarted by calling
313 <command>systemctl stop</command> in the old configuration,
314 then <command>systemctl start</command> in the new one.
315 Otherwise, it is restarted in a single step using
316 <command>systemctl restart</command> in the new configuration.
317 The latter is less correct because it runs the
318 <literal>ExecStop</literal> commands from the new
319 configuration.
320 '';
321 };
322
323 startAt = mkOption {
324 type = with types; either str (listOf str);
325 default = [];
326 example = "Sun 14:00:00";
327 description = ''
328 Automatically start this unit at the given date/time, which
329 must be in the format described in
330 <citerefentry><refentrytitle>systemd.time</refentrytitle>
331 <manvolnum>7</manvolnum></citerefentry>. This is equivalent
332 to adding a corresponding timer unit with
333 <option>OnCalendar</option> set to the value given here.
334 '';
335 apply = v: if isList v then v else [ v ];
336 };
337
338 };
339
340
341 socketOptions = commonUnitOptions // {
342
343 listenStreams = mkOption {
344 default = [];
345 type = types.listOf types.str;
346 example = [ "0.0.0.0:993" "/run/my-socket" ];
347 description = ''
348 For each item in this list, a <literal>ListenStream</literal>
349 option in the <literal>[Socket]</literal> section will be created.
350 '';
351 };
352
353 socketConfig = mkOption {
354 default = {};
355 example = { ListenStream = "/run/my-socket"; };
356 type = types.attrsOf unitOption;
357 description = ''
358 Each attribute in this set specifies an option in the
359 <literal>[Socket]</literal> section of the unit. See
360 <citerefentry><refentrytitle>systemd.socket</refentrytitle>
361 <manvolnum>5</manvolnum></citerefentry> for details.
362 '';
363 };
364
365 };
366
367
368 timerOptions = commonUnitOptions // {
369
370 timerConfig = mkOption {
371 default = {};
372 example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; };
373 type = types.attrsOf unitOption;
374 description = ''
375 Each attribute in this set specifies an option in the
376 <literal>[Timer]</literal> section of the unit. See
377 <citerefentry><refentrytitle>systemd.timer</refentrytitle>
378 <manvolnum>7</manvolnum></citerefentry> and
379 <citerefentry><refentrytitle>systemd.time</refentrytitle>
380 <manvolnum>7</manvolnum></citerefentry> for details.
381 '';
382 };
383
384 };
385
386
387 pathOptions = commonUnitOptions // {
388
389 pathConfig = mkOption {
390 default = {};
391 example = { PathChanged = "/some/path"; Unit = "changedpath.service"; };
392 type = types.attrsOf unitOption;
393 description = ''
394 Each attribute in this set specifies an option in the
395 <literal>[Path]</literal> section of the unit. See
396 <citerefentry><refentrytitle>systemd.path</refentrytitle>
397 <manvolnum>5</manvolnum></citerefentry> for details.
398 '';
399 };
400
401 };
402
403
404 mountOptions = commonUnitOptions // {
405
406 what = mkOption {
407 example = "/dev/sda1";
408 type = types.str;
409 description = "Absolute path of device node, file or other resource. (Mandatory)";
410 };
411
412 where = mkOption {
413 example = "/mnt";
414 type = types.str;
415 description = ''
416 Absolute path of a directory of the mount point.
417 Will be created if it doesn't exist. (Mandatory)
418 '';
419 };
420
421 type = mkOption {
422 default = "";
423 example = "ext4";
424 type = types.str;
425 description = "File system type.";
426 };
427
428 options = mkOption {
429 default = "";
430 example = "noatime";
431 type = types.commas;
432 description = "Options used to mount the file system.";
433 };
434
435 mountConfig = mkOption {
436 default = {};
437 example = { DirectoryMode = "0775"; };
438 type = types.attrsOf unitOption;
439 description = ''
440 Each attribute in this set specifies an option in the
441 <literal>[Mount]</literal> section of the unit. See
442 <citerefentry><refentrytitle>systemd.mount</refentrytitle>
443 <manvolnum>5</manvolnum></citerefentry> for details.
444 '';
445 };
446 };
447
448 automountOptions = commonUnitOptions // {
449
450 where = mkOption {
451 example = "/mnt";
452 type = types.str;
453 description = ''
454 Absolute path of a directory of the mount point.
455 Will be created if it doesn't exist. (Mandatory)
456 '';
457 };
458
459 automountConfig = mkOption {
460 default = {};
461 example = { DirectoryMode = "0775"; };
462 type = types.attrsOf unitOption;
463 description = ''
464 Each attribute in this set specifies an option in the
465 <literal>[Automount]</literal> section of the unit. See
466 <citerefentry><refentrytitle>systemd.automount</refentrytitle>
467 <manvolnum>5</manvolnum></citerefentry> for details.
468 '';
469 };
470 };
471
472 targetOptions = commonUnitOptions;
473
474 sliceOptions = commonUnitOptions // {
475
476 sliceConfig = mkOption {
477 default = {};
478 example = { MemoryMax = "2G"; };
479 type = types.attrsOf unitOption;
480 description = ''
481 Each attribute in this set specifies an option in the
482 <literal>[Slice]</literal> section of the unit. See
483 <citerefentry><refentrytitle>systemd.slice</refentrytitle>
484 <manvolnum>5</manvolnum></citerefentry> for details.
485 '';
486 };
487
488 };
489
490}