vuls: init at 0.27.0
[NixPkgs.git] / nixos / lib / systemd-unit-options.nix
blobb02a11ef33a6ad5fb41bf582c3dc35293421b102
1 { lib, systemdUtils }:
3 let
4   inherit (systemdUtils.lib)
5     assertValueOneOf
6     automountConfig
7     checkUnitConfig
8     makeJobScript
9     mountConfig
10     serviceConfig
11     unitConfig
12     unitNameType
13     ;
15   inherit (lib)
16     any
17     concatMap
18     filterOverrides
19     isList
20     literalExpression
21     mergeEqualOption
22     mkIf
23     mkMerge
24     mkOption
25     mkOptionType
26     singleton
27     toList
28     types
29     ;
31   checkService = checkUnitConfig "Service" [
32     (assertValueOneOf "Type" [
33       "exec" "simple" "forking" "oneshot" "dbus" "notify" "notify-reload" "idle"
34     ])
35     (assertValueOneOf "Restart" [
36       "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always"
37     ])
38   ];
40 in rec {
42   unitOption = mkOptionType {
43     name = "systemd option";
44     merge = loc: defs:
45       let
46         defs' = filterOverrides defs;
47       in
48         if any (def: isList def.value) defs'
49         then concatMap (def: toList def.value) defs'
50         else mergeEqualOption loc defs';
51   };
53   sharedOptions = {
55     enable = mkOption {
56       default = true;
57       type = types.bool;
58       description = ''
59         If set to false, this unit will be a symlink to
60         /dev/null. This is primarily useful to prevent specific
61         template instances
62         (e.g. `serial-getty@ttyS0`) from being
63         started. Note that `enable=true` does not
64         make a unit start by default at boot; if you want that, see
65         `wantedBy`.
66       '';
67     };
69     name = lib.mkOption {
70       type = lib.types.str;
71       description = ''
72         The name of this systemd unit, including its extension.
73         This can be used to refer to this unit from other systemd units.
74       '';
75     };
77     overrideStrategy = mkOption {
78       default = "asDropinIfExists";
79       type = types.enum [ "asDropinIfExists" "asDropin" ];
80       description = ''
81         Defines how unit configuration is provided for systemd:
83         `asDropinIfExists` creates a unit file when no unit file is provided by the package
84         otherwise a drop-in file name `overrides.conf`.
86         `asDropin` creates a drop-in file named `overrides.conf`.
87         Mainly needed to define instances for systemd template units (e.g. `systemd-nspawn@mycontainer.service`).
89         See also {manpage}`systemd.unit(5)`.
90       '';
91     };
93     requiredBy = mkOption {
94       default = [];
95       type = types.listOf unitNameType;
96       description = ''
97         Units that require (i.e. depend on and need to go down with) this unit.
98         As discussed in the `wantedBy` option description this also creates
99         `.requires` symlinks automatically.
100       '';
101     };
103     upheldBy = mkOption {
104       default = [];
105       type = types.listOf unitNameType;
106       description = ''
107         Keep this unit running as long as the listed units are running. This is a continuously
108         enforced version of wantedBy.
109       '';
110     };
112     wantedBy = mkOption {
113       default = [];
114       type = types.listOf unitNameType;
115       description = ''
116         Units that want (i.e. depend on) this unit. The default method for
117         starting a unit by default at boot time is to set this option to
118         `["multi-user.target"]` for system services. Likewise for user units
119         (`systemd.user.<name>.*`) set it to `["default.target"]` to make a unit
120         start by default when the user `<name>` logs on.
122         This option creates a `.wants` symlink in the given target that exists
123         statelessly without the need for running `systemctl enable`.
124         The `[Install]` section described in {manpage}`systemd.unit(5)` however is
125         not supported because it is a stateful process that does not fit well
126         into the NixOS design.
127       '';
128     };
130     aliases = mkOption {
131       default = [];
132       type = types.listOf unitNameType;
133       description = "Aliases of that unit.";
134     };
136   };
138   concreteUnitOptions = sharedOptions // {
140     text = mkOption {
141       type = types.nullOr types.str;
142       default = null;
143       description = "Text of this systemd unit.";
144     };
146     unit = mkOption {
147       internal = true;
148       description = "The generated unit.";
149     };
151   };
153   commonUnitOptions = {
154     options = sharedOptions // {
156       description = mkOption {
157         default = "";
158         type = types.singleLineStr;
159         description = "Description of this unit used in systemd messages and progress indicators.";
160       };
162       documentation = mkOption {
163         default = [];
164         type = types.listOf types.str;
165         description = "A list of URIs referencing documentation for this unit or its configuration.";
166       };
168       requires = mkOption {
169         default = [];
170         type = types.listOf unitNameType;
171         description = ''
172           Start the specified units when this unit is started, and stop
173           this unit when the specified units are stopped or fail.
174         '';
175       };
177       wants = mkOption {
178         default = [];
179         type = types.listOf unitNameType;
180         description = ''
181           Start the specified units when this unit is started.
182         '';
183       };
185       upholds = mkOption {
186         default = [];
187         type = types.listOf unitNameType;
188         description = ''
189           Keeps the specified running while this unit is running. A continuous version of `wants`.
190         '';
191       };
193       after = mkOption {
194         default = [];
195         type = types.listOf unitNameType;
196         description = ''
197           If the specified units are started at the same time as
198           this unit, delay this unit until they have started.
199         '';
200       };
202       before = mkOption {
203         default = [];
204         type = types.listOf unitNameType;
205         description = ''
206           If the specified units are started at the same time as
207           this unit, delay them until this unit has started.
208         '';
209       };
211       bindsTo = mkOption {
212         default = [];
213         type = types.listOf unitNameType;
214         description = ''
215           Like ‘requires’, but in addition, if the specified units
216           unexpectedly disappear, this unit will be stopped as well.
217         '';
218       };
220       partOf = mkOption {
221         default = [];
222         type = types.listOf unitNameType;
223         description = ''
224           If the specified units are stopped or restarted, then this
225           unit is stopped or restarted as well.
226         '';
227       };
229       conflicts = mkOption {
230         default = [];
231         type = types.listOf unitNameType;
232         description = ''
233           If the specified units are started, then this unit is stopped
234           and vice versa.
235         '';
236       };
238       requisite = mkOption {
239         default = [];
240         type = types.listOf unitNameType;
241         description = ''
242           Similar to requires. However if the units listed are not started,
243           they will not be started and the transaction will fail.
244         '';
245       };
247       unitConfig = mkOption {
248         default = {};
249         example = { RequiresMountsFor = "/data"; };
250         type = types.attrsOf unitOption;
251         description = ''
252           Each attribute in this set specifies an option in the
253           `[Unit]` section of the unit.  See
254           {manpage}`systemd.unit(5)` for details.
255         '';
256       };
258       onFailure = mkOption {
259         default = [];
260         type = types.listOf unitNameType;
261         description = ''
262           A list of one or more units that are activated when
263           this unit enters the "failed" state.
264         '';
265       };
267       onSuccess = mkOption {
268         default = [];
269         type = types.listOf unitNameType;
270         description = ''
271           A list of one or more units that are activated when
272           this unit enters the "inactive" state.
273         '';
274       };
276       startLimitBurst = mkOption {
277          type = types.int;
278          description = ''
279            Configure unit start rate limiting. Units which are started
280            more than startLimitBurst times within an interval time
281            interval are not permitted to start any more.
282          '';
283       };
285       startLimitIntervalSec = mkOption {
286          type = types.int;
287          description = ''
288            Configure unit start rate limiting. Units which are started
289            more than startLimitBurst times within an interval time
290            interval are not permitted to start any more.
291          '';
292       };
294     };
295   };
297   stage2CommonUnitOptions = {
298     imports = [
299       commonUnitOptions
300     ];
302     options = {
303       restartTriggers = mkOption {
304         default = [];
305         type = types.listOf types.unspecified;
306         description = ''
307           An arbitrary list of items such as derivations.  If any item
308           in the list changes between reconfigurations, the service will
309           be restarted.
310         '';
311       };
313       reloadTriggers = mkOption {
314         default = [];
315         type = types.listOf unitOption;
316         description = ''
317           An arbitrary list of items such as derivations.  If any item
318           in the list changes between reconfigurations, the service will
319           be reloaded.  If anything but a reload trigger changes in the
320           unit file, the unit will be restarted instead.
321         '';
322       };
323     };
324   };
325   stage1CommonUnitOptions = commonUnitOptions;
327   serviceOptions = { name, config, ... }: {
328     options = {
330       environment = mkOption {
331         default = {};
332         type = with types; attrsOf (nullOr (oneOf [ str path package ]));
333         example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
334         description = "Environment variables passed to the service's processes.";
335       };
337       path = mkOption {
338         default = [];
339         type = with types; listOf (oneOf [ package str ]);
340         description = ''
341           Packages added to the service's {env}`PATH`
342           environment variable.  Both the {file}`bin`
343           and {file}`sbin` subdirectories of each
344           package are added.
345         '';
346       };
348       serviceConfig = mkOption {
349         default = {};
350         example =
351           { RestartSec = 5;
352           };
353         type = types.addCheck (types.attrsOf unitOption) checkService;
354         description = ''
355           Each attribute in this set specifies an option in the
356           `[Service]` section of the unit.  See
357           {manpage}`systemd.service(5)` for details.
358         '';
359       };
361       enableStrictShellChecks = mkOption {
362         type = types.bool;
363         description = "Enable running shellcheck on the generated scripts for this unit.";
364         # The default gets set in systemd-lib.nix because we don't have access to
365         # the full NixOS config here.
366         defaultText = literalExpression "config.systemd.enableStrictShellChecks";
367       };
369       script = mkOption {
370         type = types.lines;
371         default = "";
372         description = "Shell commands executed as the service's main process.";
373       };
375       scriptArgs = mkOption {
376         type = types.str;
377         default = "";
378         example = "%i";
379         description = ''
380           Arguments passed to the main process script.
381           Can contain specifiers (`%` placeholders expanded by systemd, see {manpage}`systemd.unit(5)`).
382         '';
383       };
385       preStart = mkOption {
386         type = types.lines;
387         default = "";
388         description = ''
389           Shell commands executed before the service's main process
390           is started.
391         '';
392       };
394       postStart = mkOption {
395         type = types.lines;
396         default = "";
397         description = ''
398           Shell commands executed after the service's main process
399           is started.
400         '';
401       };
403       reload = mkOption {
404         type = types.lines;
405         default = "";
406         description = ''
407           Shell commands executed when the service's main process
408           is reloaded.
409         '';
410       };
412       preStop = mkOption {
413         type = types.lines;
414         default = "";
415         description = ''
416           Shell commands executed to stop the service.
417         '';
418       };
420       postStop = mkOption {
421         type = types.lines;
422         default = "";
423         description = ''
424           Shell commands executed after the service's main process
425           has exited.
426         '';
427       };
429       jobScripts = mkOption {
430         type = with types; coercedTo path singleton (listOf path);
431         internal = true;
432         description = "A list of all job script derivations of this unit.";
433         default = [];
434       };
436     };
438     config = mkMerge [
439       (mkIf (config.preStart != "") rec {
440         jobScripts = makeJobScript {
441           name = "${name}-pre-start";
442           text = config.preStart;
443           inherit (config) enableStrictShellChecks;
444         };
445         serviceConfig.ExecStartPre = [ jobScripts ];
446       })
447       (mkIf (config.script != "") rec {
448         jobScripts = makeJobScript {
449           name = "${name}-start";
450           text = config.script;
451           inherit (config) enableStrictShellChecks;
452         };
453         serviceConfig.ExecStart = jobScripts + " " + config.scriptArgs;
454       })
455       (mkIf (config.postStart != "") rec {
456         jobScripts = makeJobScript {
457           name = "${name}-post-start";
458           text = config.postStart;
459           inherit (config) enableStrictShellChecks;
460         };
461         serviceConfig.ExecStartPost = [ jobScripts ];
462       })
463       (mkIf (config.reload != "") rec {
464         jobScripts = makeJobScript {
465           name = "${name}-reload";
466           text = config.reload;
467           inherit (config) enableStrictShellChecks;
468         };
469         serviceConfig.ExecReload = jobScripts;
470       })
471       (mkIf (config.preStop != "") rec {
472         jobScripts = makeJobScript {
473           name = "${name}-pre-stop";
474           text = config.preStop;
475           inherit (config) enableStrictShellChecks;
476         };
477         serviceConfig.ExecStop = jobScripts;
478       })
479       (mkIf (config.postStop != "") rec {
480         jobScripts = makeJobScript {
481           name = "${name}-post-stop";
482           text = config.postStop;
483           inherit (config) enableStrictShellChecks;
484         };
485         serviceConfig.ExecStopPost = jobScripts;
486       })
487     ];
489   };
491   stage2ServiceOptions = {
492     imports = [
493       stage2CommonUnitOptions
494       serviceOptions
495     ];
497     options = {
498       restartIfChanged = mkOption {
499         type = types.bool;
500         default = true;
501         description = ''
502           Whether the service should be restarted during a NixOS
503           configuration switch if its definition has changed.
504         '';
505       };
507       reloadIfChanged = mkOption {
508         type = types.bool;
509         default = false;
510         description = ''
511           Whether the service should be reloaded during a NixOS
512           configuration switch if its definition has changed.  If
513           enabled, the value of {option}`restartIfChanged` is
514           ignored.
516           This option should not be used anymore in favor of
517           {option}`reloadTriggers` which allows more granular
518           control of when a service is reloaded and when a service
519           is restarted.
520         '';
521       };
523       stopIfChanged = mkOption {
524         type = types.bool;
525         default = true;
526         description = ''
527           If set, a changed unit is restarted by calling
528           {command}`systemctl stop` in the old configuration,
529           then {command}`systemctl start` in the new one.
530           Otherwise, it is restarted in a single step using
531           {command}`systemctl restart` in the new configuration.
532           The latter is less correct because it runs the
533           `ExecStop` commands from the new
534           configuration.
535         '';
536       };
538       startAt = mkOption {
539         type = with types; either str (listOf str);
540         default = [];
541         example = "Sun 14:00:00";
542         description = ''
543           Automatically start this unit at the given date/time, which
544           must be in the format described in
545           {manpage}`systemd.time(7)`.  This is equivalent
546           to adding a corresponding timer unit with
547           {option}`OnCalendar` set to the value given here.
548         '';
549         apply = v: if isList v then v else [ v ];
550       };
551     };
552   };
554   stage1ServiceOptions = {
555     imports = [
556       stage1CommonUnitOptions
557       serviceOptions
558     ];
559   };
562   socketOptions = {
563     options = {
565       listenStreams = mkOption {
566         default = [];
567         type = types.listOf types.str;
568         example = [ "0.0.0.0:993" "/run/my-socket" ];
569         description = ''
570           For each item in this list, a `ListenStream`
571           option in the `[Socket]` section will be created.
572         '';
573       };
575       listenDatagrams = mkOption {
576         default = [];
577         type = types.listOf types.str;
578         example = [ "0.0.0.0:993" "/run/my-socket" ];
579         description = ''
580           For each item in this list, a `ListenDatagram`
581           option in the `[Socket]` section will be created.
582         '';
583       };
585       socketConfig = mkOption {
586         default = {};
587         example = { ListenStream = "/run/my-socket"; };
588         type = types.attrsOf unitOption;
589         description = ''
590           Each attribute in this set specifies an option in the
591           `[Socket]` section of the unit.  See
592           {manpage}`systemd.socket(5)` for details.
593         '';
594       };
595     };
597   };
599   stage2SocketOptions = {
600     imports = [
601       stage2CommonUnitOptions
602       socketOptions
603     ];
604   };
606   stage1SocketOptions = {
607     imports = [
608       stage1CommonUnitOptions
609       socketOptions
610     ];
611   };
614   timerOptions = {
615     options = {
617       timerConfig = mkOption {
618         default = {};
619         example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; };
620         type = types.attrsOf unitOption;
621         description = ''
622           Each attribute in this set specifies an option in the
623           `[Timer]` section of the unit.  See
624           {manpage}`systemd.timer(5)` and
625           {manpage}`systemd.time(7)` for details.
626         '';
627       };
629     };
630   };
632   stage2TimerOptions = {
633     imports = [
634       stage2CommonUnitOptions
635       timerOptions
636     ];
637   };
639   stage1TimerOptions = {
640     imports = [
641       stage1CommonUnitOptions
642       timerOptions
643     ];
644   };
647   pathOptions = {
648     options = {
650       pathConfig = mkOption {
651         default = {};
652         example = { PathChanged = "/some/path"; Unit = "changedpath.service"; };
653         type = types.attrsOf unitOption;
654         description = ''
655           Each attribute in this set specifies an option in the
656           `[Path]` section of the unit.  See
657           {manpage}`systemd.path(5)` for details.
658         '';
659       };
661     };
662   };
664   stage2PathOptions = {
665     imports = [
666       stage2CommonUnitOptions
667       pathOptions
668     ];
669   };
671   stage1PathOptions = {
672     imports = [
673       stage1CommonUnitOptions
674       pathOptions
675     ];
676   };
679   mountOptions = {
680     options = {
682       what = mkOption {
683         example = "/dev/sda1";
684         type = types.str;
685         description = "Absolute path of device node, file or other resource. (Mandatory)";
686       };
688       where = mkOption {
689         example = "/mnt";
690         type = types.str;
691         description = ''
692           Absolute path of a directory of the mount point.
693           Will be created if it doesn't exist. (Mandatory)
694         '';
695       };
697       type = mkOption {
698         default = "";
699         example = "ext4";
700         type = types.str;
701         description = "File system type.";
702       };
704       options = mkOption {
705         default = "";
706         example = "noatime";
707         type = types.commas;
708         description = "Options used to mount the file system.";
709       };
711       mountConfig = mkOption {
712         default = {};
713         example = { DirectoryMode = "0775"; };
714         type = types.attrsOf unitOption;
715         description = ''
716           Each attribute in this set specifies an option in the
717           `[Mount]` section of the unit.  See
718           {manpage}`systemd.mount(5)` for details.
719         '';
720       };
722     };
723   };
725   stage2MountOptions = {
726     imports = [
727       stage2CommonUnitOptions
728       mountOptions
729     ];
730   };
732   stage1MountOptions = {
733     imports = [
734       stage1CommonUnitOptions
735       mountOptions
736     ];
737   };
739   automountOptions = {
740     options = {
742       where = mkOption {
743         example = "/mnt";
744         type = types.str;
745         description = ''
746           Absolute path of a directory of the mount point.
747           Will be created if it doesn't exist. (Mandatory)
748         '';
749       };
751       automountConfig = mkOption {
752         default = {};
753         example = { DirectoryMode = "0775"; };
754         type = types.attrsOf unitOption;
755         description = ''
756           Each attribute in this set specifies an option in the
757           `[Automount]` section of the unit.  See
758           {manpage}`systemd.automount(5)` for details.
759         '';
760       };
762     };
763   };
765   stage2AutomountOptions = {
766     imports = [
767       stage2CommonUnitOptions
768       automountOptions
769     ];
770   };
772   stage1AutomountOptions = {
773     imports = [
774       stage1CommonUnitOptions
775       automountOptions
776     ];
777   };
779   sliceOptions = {
780     options = {
782       sliceConfig = mkOption {
783         default = {};
784         example = { MemoryMax = "2G"; };
785         type = types.attrsOf unitOption;
786         description = ''
787           Each attribute in this set specifies an option in the
788           `[Slice]` section of the unit.  See
789           {manpage}`systemd.slice(5)` for details.
790         '';
791       };
793     };
794   };
796   stage2SliceOptions = {
797     imports = [
798       stage2CommonUnitOptions
799       sliceOptions
800     ];
801   };
803   stage1SliceOptions = {
804     imports = [
805       stage1CommonUnitOptions
806       sliceOptions
807     ];
808   };