nixos/preload: init
[NixPkgs.git] / nixos / lib / systemd-unit-options.nix
blob9c69bda471bb756d66d2fa4001520bbc52cd3440
1 { lib, systemdUtils }:
3 with systemdUtils.lib;
4 with lib;
6 let
7   checkService = checkUnitConfig "Service" [
8     (assertValueOneOf "Type" [
9       "exec" "simple" "forking" "oneshot" "dbus" "notify" "idle"
10     ])
11     (assertValueOneOf "Restart" [
12       "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always"
13     ])
14   ];
16 in rec {
18   unitOption = mkOptionType {
19     name = "systemd option";
20     merge = loc: defs:
21       let
22         defs' = filterOverrides defs;
23       in
24         if isList (head defs').value
25         then concatMap (def:
26           if builtins.typeOf def.value == "list"
27           then def.value
28           else
29             throw "The definitions for systemd unit options should be either all lists, representing repeatable options, or all non-lists, but for the option ${showOption loc}, the definitions are a mix of list and non-list ${lib.options.showDefs defs'}"
30         ) defs'
32         else mergeEqualOption loc defs';
33   };
35   sharedOptions = {
37     enable = mkOption {
38       default = true;
39       type = types.bool;
40       description = lib.mdDoc ''
41         If set to false, this unit will be a symlink to
42         /dev/null. This is primarily useful to prevent specific
43         template instances
44         (e.g. `serial-getty@ttyS0`) from being
45         started. Note that `enable=true` does not
46         make a unit start by default at boot; if you want that, see
47         `wantedBy`.
48       '';
49     };
51     overrideStrategy = mkOption {
52       default = "asDropinIfExists";
53       type = types.enum [ "asDropinIfExists" "asDropin" ];
54       description = lib.mdDoc ''
55         Defines how unit configuration is provided for systemd:
57         `asDropinIfExists` creates a unit file when no unit file is provided by the package
58         otherwise a drop-in file name `overrides.conf`.
60         `asDropin` creates a drop-in file named `overrides.conf`.
61         Mainly needed to define instances for systemd template units (e.g. `systemd-nspawn@mycontainer.service`).
63         See also {manpage}`systemd.unit(5)`.
64       '';
65     };
67     requiredBy = mkOption {
68       default = [];
69       type = types.listOf unitNameType;
70       description = lib.mdDoc ''
71         Units that require (i.e. depend on and need to go down with) this unit.
72         As discussed in the `wantedBy` option description this also creates
73         `.requires` symlinks automatically.
74       '';
75     };
77     wantedBy = mkOption {
78       default = [];
79       type = types.listOf unitNameType;
80       description = lib.mdDoc ''
81         Units that want (i.e. depend on) this unit. The default method for
82         starting a unit by default at boot time is to set this option to
83         `["multi-user.target"]` for system services. Likewise for user units
84         (`systemd.user.<name>.*`) set it to `["default.target"]` to make a unit
85         start by default when the user `<name>` logs on.
87         This option creates a `.wants` symlink in the given target that exists
88         statelessly without the need for running `systemctl enable`.
89         The `[Install]` section described in {manpage}`systemd.unit(5)` however is
90         not supported because it is a stateful process that does not fit well
91         into the NixOS design.
92       '';
93     };
95     aliases = mkOption {
96       default = [];
97       type = types.listOf unitNameType;
98       description = lib.mdDoc "Aliases of that unit.";
99     };
101   };
103   concreteUnitOptions = sharedOptions // {
105     text = mkOption {
106       type = types.nullOr types.str;
107       default = null;
108       description = lib.mdDoc "Text of this systemd unit.";
109     };
111     unit = mkOption {
112       internal = true;
113       description = lib.mdDoc "The generated unit.";
114     };
116   };
118   commonUnitOptions = {
119     options = sharedOptions // {
121       description = mkOption {
122         default = "";
123         type = types.singleLineStr;
124         description = lib.mdDoc "Description of this unit used in systemd messages and progress indicators.";
125       };
127       documentation = mkOption {
128         default = [];
129         type = types.listOf types.str;
130         description = lib.mdDoc "A list of URIs referencing documentation for this unit or its configuration.";
131       };
133       requires = mkOption {
134         default = [];
135         type = types.listOf unitNameType;
136         description = lib.mdDoc ''
137           Start the specified units when this unit is started, and stop
138           this unit when the specified units are stopped or fail.
139         '';
140       };
142       wants = mkOption {
143         default = [];
144         type = types.listOf unitNameType;
145         description = lib.mdDoc ''
146           Start the specified units when this unit is started.
147         '';
148       };
150       after = mkOption {
151         default = [];
152         type = types.listOf unitNameType;
153         description = lib.mdDoc ''
154           If the specified units are started at the same time as
155           this unit, delay this unit until they have started.
156         '';
157       };
159       before = mkOption {
160         default = [];
161         type = types.listOf unitNameType;
162         description = lib.mdDoc ''
163           If the specified units are started at the same time as
164           this unit, delay them until this unit has started.
165         '';
166       };
168       bindsTo = mkOption {
169         default = [];
170         type = types.listOf unitNameType;
171         description = lib.mdDoc ''
172           Like ‘requires’, but in addition, if the specified units
173           unexpectedly disappear, this unit will be stopped as well.
174         '';
175       };
177       partOf = mkOption {
178         default = [];
179         type = types.listOf unitNameType;
180         description = lib.mdDoc ''
181           If the specified units are stopped or restarted, then this
182           unit is stopped or restarted as well.
183         '';
184       };
186       conflicts = mkOption {
187         default = [];
188         type = types.listOf unitNameType;
189         description = lib.mdDoc ''
190           If the specified units are started, then this unit is stopped
191           and vice versa.
192         '';
193       };
195       requisite = mkOption {
196         default = [];
197         type = types.listOf unitNameType;
198         description = lib.mdDoc ''
199           Similar to requires. However if the units listed are not started,
200           they will not be started and the transaction will fail.
201         '';
202       };
204       unitConfig = mkOption {
205         default = {};
206         example = { RequiresMountsFor = "/data"; };
207         type = types.attrsOf unitOption;
208         description = lib.mdDoc ''
209           Each attribute in this set specifies an option in the
210           `[Unit]` section of the unit.  See
211           {manpage}`systemd.unit(5)` for details.
212         '';
213       };
215       onFailure = mkOption {
216         default = [];
217         type = types.listOf unitNameType;
218         description = lib.mdDoc ''
219           A list of one or more units that are activated when
220           this unit enters the "failed" state.
221         '';
222       };
224       onSuccess = mkOption {
225         default = [];
226         type = types.listOf unitNameType;
227         description = lib.mdDoc ''
228           A list of one or more units that are activated when
229           this unit enters the "inactive" state.
230         '';
231       };
233       startLimitBurst = mkOption {
234          type = types.int;
235          description = lib.mdDoc ''
236            Configure unit start rate limiting. Units which are started
237            more than startLimitBurst times within an interval time
238            interval are not permitted to start any more.
239          '';
240       };
242       startLimitIntervalSec = mkOption {
243          type = types.int;
244          description = lib.mdDoc ''
245            Configure unit start rate limiting. Units which are started
246            more than startLimitBurst times within an interval time
247            interval are not permitted to start any more.
248          '';
249       };
251     };
252   };
254   stage2CommonUnitOptions = {
255     imports = [
256       commonUnitOptions
257     ];
259     options = {
260       restartTriggers = mkOption {
261         default = [];
262         type = types.listOf types.unspecified;
263         description = lib.mdDoc ''
264           An arbitrary list of items such as derivations.  If any item
265           in the list changes between reconfigurations, the service will
266           be restarted.
267         '';
268       };
270       reloadTriggers = mkOption {
271         default = [];
272         type = types.listOf unitOption;
273         description = lib.mdDoc ''
274           An arbitrary list of items such as derivations.  If any item
275           in the list changes between reconfigurations, the service will
276           be reloaded.  If anything but a reload trigger changes in the
277           unit file, the unit will be restarted instead.
278         '';
279       };
280     };
281   };
282   stage1CommonUnitOptions = commonUnitOptions;
284   serviceOptions = { name, config, ... }: {
285     options = {
287       environment = mkOption {
288         default = {};
289         type = with types; attrsOf (nullOr (oneOf [ str path package ]));
290         example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
291         description = lib.mdDoc "Environment variables passed to the service's processes.";
292       };
294       path = mkOption {
295         default = [];
296         type = with types; listOf (oneOf [ package str ]);
297         description = lib.mdDoc ''
298           Packages added to the service's {env}`PATH`
299           environment variable.  Both the {file}`bin`
300           and {file}`sbin` subdirectories of each
301           package are added.
302         '';
303       };
305       serviceConfig = mkOption {
306         default = {};
307         example =
308           { RestartSec = 5;
309           };
310         type = types.addCheck (types.attrsOf unitOption) checkService;
311         description = lib.mdDoc ''
312           Each attribute in this set specifies an option in the
313           `[Service]` section of the unit.  See
314           {manpage}`systemd.service(5)` for details.
315         '';
316       };
318       script = mkOption {
319         type = types.lines;
320         default = "";
321         description = lib.mdDoc "Shell commands executed as the service's main process.";
322       };
324       scriptArgs = mkOption {
325         type = types.str;
326         default = "";
327         example = "%i";
328         description = lib.mdDoc ''
329           Arguments passed to the main process script.
330           Can contain specifiers (`%` placeholders expanded by systemd, see {manpage}`systemd.unit(5)`).
331         '';
332       };
334       preStart = mkOption {
335         type = types.lines;
336         default = "";
337         description = lib.mdDoc ''
338           Shell commands executed before the service's main process
339           is started.
340         '';
341       };
343       postStart = mkOption {
344         type = types.lines;
345         default = "";
346         description = lib.mdDoc ''
347           Shell commands executed after the service's main process
348           is started.
349         '';
350       };
352       reload = mkOption {
353         type = types.lines;
354         default = "";
355         description = lib.mdDoc ''
356           Shell commands executed when the service's main process
357           is reloaded.
358         '';
359       };
361       preStop = mkOption {
362         type = types.lines;
363         default = "";
364         description = lib.mdDoc ''
365           Shell commands executed to stop the service.
366         '';
367       };
369       postStop = mkOption {
370         type = types.lines;
371         default = "";
372         description = lib.mdDoc ''
373           Shell commands executed after the service's main process
374           has exited.
375         '';
376       };
378       jobScripts = mkOption {
379         type = with types; coercedTo path singleton (listOf path);
380         internal = true;
381         description = lib.mdDoc "A list of all job script derivations of this unit.";
382         default = [];
383       };
385     };
387     config = mkMerge [
388       (mkIf (config.preStart != "") rec {
389         jobScripts = makeJobScript "${name}-pre-start" config.preStart;
390         serviceConfig.ExecStartPre = [ jobScripts ];
391       })
392       (mkIf (config.script != "") rec {
393         jobScripts = makeJobScript "${name}-start" config.script;
394         serviceConfig.ExecStart = jobScripts + " " + config.scriptArgs;
395       })
396       (mkIf (config.postStart != "") rec {
397         jobScripts = (makeJobScript "${name}-post-start" config.postStart);
398         serviceConfig.ExecStartPost = [ jobScripts ];
399       })
400       (mkIf (config.reload != "") rec {
401         jobScripts = makeJobScript "${name}-reload" config.reload;
402         serviceConfig.ExecReload = jobScripts;
403       })
404       (mkIf (config.preStop != "") rec {
405         jobScripts = makeJobScript "${name}-pre-stop" config.preStop;
406         serviceConfig.ExecStop = jobScripts;
407       })
408       (mkIf (config.postStop != "") rec {
409         jobScripts = makeJobScript "${name}-post-stop" config.postStop;
410         serviceConfig.ExecStopPost = jobScripts;
411       })
412     ];
414   };
416   stage2ServiceOptions = {
417     imports = [
418       stage2CommonUnitOptions
419       serviceOptions
420     ];
422     options = {
423       restartIfChanged = mkOption {
424         type = types.bool;
425         default = true;
426         description = lib.mdDoc ''
427           Whether the service should be restarted during a NixOS
428           configuration switch if its definition has changed.
429         '';
430       };
432       reloadIfChanged = mkOption {
433         type = types.bool;
434         default = false;
435         description = lib.mdDoc ''
436           Whether the service should be reloaded during a NixOS
437           configuration switch if its definition has changed.  If
438           enabled, the value of {option}`restartIfChanged` is
439           ignored.
441           This option should not be used anymore in favor of
442           {option}`reloadTriggers` which allows more granular
443           control of when a service is reloaded and when a service
444           is restarted.
445         '';
446       };
448       stopIfChanged = mkOption {
449         type = types.bool;
450         default = true;
451         description = lib.mdDoc ''
452           If set, a changed unit is restarted by calling
453           {command}`systemctl stop` in the old configuration,
454           then {command}`systemctl start` in the new one.
455           Otherwise, it is restarted in a single step using
456           {command}`systemctl restart` in the new configuration.
457           The latter is less correct because it runs the
458           `ExecStop` commands from the new
459           configuration.
460         '';
461       };
463       startAt = mkOption {
464         type = with types; either str (listOf str);
465         default = [];
466         example = "Sun 14:00:00";
467         description = lib.mdDoc ''
468           Automatically start this unit at the given date/time, which
469           must be in the format described in
470           {manpage}`systemd.time(7)`.  This is equivalent
471           to adding a corresponding timer unit with
472           {option}`OnCalendar` set to the value given here.
473         '';
474         apply = v: if isList v then v else [ v ];
475       };
476     };
477   };
479   stage1ServiceOptions = {
480     imports = [
481       stage1CommonUnitOptions
482       serviceOptions
483     ];
484   };
487   socketOptions = {
488     options = {
490       listenStreams = mkOption {
491         default = [];
492         type = types.listOf types.str;
493         example = [ "0.0.0.0:993" "/run/my-socket" ];
494         description = lib.mdDoc ''
495           For each item in this list, a `ListenStream`
496           option in the `[Socket]` section will be created.
497         '';
498       };
500       listenDatagrams = mkOption {
501         default = [];
502         type = types.listOf types.str;
503         example = [ "0.0.0.0:993" "/run/my-socket" ];
504         description = lib.mdDoc ''
505           For each item in this list, a `ListenDatagram`
506           option in the `[Socket]` section will be created.
507         '';
508       };
510       socketConfig = mkOption {
511         default = {};
512         example = { ListenStream = "/run/my-socket"; };
513         type = types.attrsOf unitOption;
514         description = lib.mdDoc ''
515           Each attribute in this set specifies an option in the
516           `[Socket]` section of the unit.  See
517           {manpage}`systemd.socket(5)` for details.
518         '';
519       };
520     };
522   };
524   stage2SocketOptions = {
525     imports = [
526       stage2CommonUnitOptions
527       socketOptions
528     ];
529   };
531   stage1SocketOptions = {
532     imports = [
533       stage1CommonUnitOptions
534       socketOptions
535     ];
536   };
539   timerOptions = {
540     options = {
542       timerConfig = mkOption {
543         default = {};
544         example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; };
545         type = types.attrsOf unitOption;
546         description = lib.mdDoc ''
547           Each attribute in this set specifies an option in the
548           `[Timer]` section of the unit.  See
549           {manpage}`systemd.timer(5)` and
550           {manpage}`systemd.time(7)` for details.
551         '';
552       };
554     };
555   };
557   stage2TimerOptions = {
558     imports = [
559       stage2CommonUnitOptions
560       timerOptions
561     ];
562   };
564   stage1TimerOptions = {
565     imports = [
566       stage1CommonUnitOptions
567       timerOptions
568     ];
569   };
572   pathOptions = {
573     options = {
575       pathConfig = mkOption {
576         default = {};
577         example = { PathChanged = "/some/path"; Unit = "changedpath.service"; };
578         type = types.attrsOf unitOption;
579         description = lib.mdDoc ''
580           Each attribute in this set specifies an option in the
581           `[Path]` section of the unit.  See
582           {manpage}`systemd.path(5)` for details.
583         '';
584       };
586     };
587   };
589   stage2PathOptions = {
590     imports = [
591       stage2CommonUnitOptions
592       pathOptions
593     ];
594   };
596   stage1PathOptions = {
597     imports = [
598       stage1CommonUnitOptions
599       pathOptions
600     ];
601   };
604   mountOptions = {
605     options = {
607       what = mkOption {
608         example = "/dev/sda1";
609         type = types.str;
610         description = lib.mdDoc "Absolute path of device node, file or other resource. (Mandatory)";
611       };
613       where = mkOption {
614         example = "/mnt";
615         type = types.str;
616         description = lib.mdDoc ''
617           Absolute path of a directory of the mount point.
618           Will be created if it doesn't exist. (Mandatory)
619         '';
620       };
622       type = mkOption {
623         default = "";
624         example = "ext4";
625         type = types.str;
626         description = lib.mdDoc "File system type.";
627       };
629       options = mkOption {
630         default = "";
631         example = "noatime";
632         type = types.commas;
633         description = lib.mdDoc "Options used to mount the file system.";
634       };
636       mountConfig = mkOption {
637         default = {};
638         example = { DirectoryMode = "0775"; };
639         type = types.attrsOf unitOption;
640         description = lib.mdDoc ''
641           Each attribute in this set specifies an option in the
642           `[Mount]` section of the unit.  See
643           {manpage}`systemd.mount(5)` for details.
644         '';
645       };
647     };
648   };
650   stage2MountOptions = {
651     imports = [
652       stage2CommonUnitOptions
653       mountOptions
654     ];
655   };
657   stage1MountOptions = {
658     imports = [
659       stage1CommonUnitOptions
660       mountOptions
661     ];
662   };
664   automountOptions = {
665     options = {
667       where = mkOption {
668         example = "/mnt";
669         type = types.str;
670         description = lib.mdDoc ''
671           Absolute path of a directory of the mount point.
672           Will be created if it doesn't exist. (Mandatory)
673         '';
674       };
676       automountConfig = mkOption {
677         default = {};
678         example = { DirectoryMode = "0775"; };
679         type = types.attrsOf unitOption;
680         description = lib.mdDoc ''
681           Each attribute in this set specifies an option in the
682           `[Automount]` section of the unit.  See
683           {manpage}`systemd.automount(5)` for details.
684         '';
685       };
687     };
688   };
690   stage2AutomountOptions = {
691     imports = [
692       stage2CommonUnitOptions
693       automountOptions
694     ];
695   };
697   stage1AutomountOptions = {
698     imports = [
699       stage1CommonUnitOptions
700       automountOptions
701     ];
702   };
704   sliceOptions = {
705     options = {
707       sliceConfig = mkOption {
708         default = {};
709         example = { MemoryMax = "2G"; };
710         type = types.attrsOf unitOption;
711         description = lib.mdDoc ''
712           Each attribute in this set specifies an option in the
713           `[Slice]` section of the unit.  See
714           {manpage}`systemd.slice(5)` for details.
715         '';
716       };
718     };
719   };
721   stage2SliceOptions = {
722     imports = [
723       stage2CommonUnitOptions
724       sliceOptions
725     ];
726   };
728   stage1SliceOptions = {
729     imports = [
730       stage1CommonUnitOptions
731       sliceOptions
732     ];
733   };