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