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