at master 4.0 kB view raw
1{ 2 lib, 3 config, 4 systemdPackage, 5 ... 6}: 7let 8 inherit (lib) 9 concatMapStringsSep 10 isDerivation 11 isInt 12 isFloat 13 isPath 14 isString 15 mkOption 16 replaceStrings 17 types 18 ; 19 inherit (builtins) toJSON; 20 21 # Local copy of systemd exec argument escaping function. 22 # TODO: This could perhaps be deduplicated, but it is unclear where it should go. 23 # Preferably, we don't create a hard dependency on NixOS here, so that this 24 # module can be reused in a non-NixOS context, such as mutaable services 25 # in /run/systemd/system. 26 27 # Quotes an argument for use in Exec* service lines. 28 # systemd accepts "-quoted strings with escape sequences, toJSON produces 29 # a subset of these. 30 # Additionally we escape % to disallow expansion of % specifiers. Any lone ; 31 # in the input will be turned it ";" and thus lose its special meaning. 32 # Every $ is escaped to $$, this makes it unnecessary to disable environment 33 # substitution for the directive. 34 escapeSystemdExecArg = 35 arg: 36 let 37 s = 38 if isPath arg then 39 "${arg}" 40 else if isString arg then 41 arg 42 else if isInt arg || isFloat arg || isDerivation arg then 43 toString arg 44 else 45 throw "escapeSystemdExecArg only allows strings, paths, numbers and derivations"; 46 in 47 replaceStrings [ "%" "$" ] [ "%%" "$$" ] (toJSON s); 48 49 # Quotes a list of arguments into a single string for use in a Exec* 50 # line. 51 escapeSystemdExecArgs = concatMapStringsSep " " escapeSystemdExecArg; 52 53in 54{ 55 _class = "service"; 56 imports = [ 57 (lib.mkAliasOptionModule [ "systemd" "service" ] [ "systemd" "services" "" ]) 58 (lib.mkAliasOptionModule [ "systemd" "socket" ] [ "systemd" "sockets" "" ]) 59 ]; 60 options = { 61 systemd.services = mkOption { 62 description = '' 63 This module configures systemd services, with the notable difference that their unit names will be prefixed with the abstract service name. 64 65 This option's value is not suitable for reading, but you can define a module here that interacts with just the unit configuration in the host system configuration. 66 67 Note that this option contains _deferred_ modules. 68 This means that the module has not been combined with the system configuration yet, no values can be read from this option. 69 What you can do instead is define a module that reads from the module arguments (such as `config`) that are available when the module is merged into the system configuration. 70 ''; 71 type = types.lazyAttrsOf ( 72 types.deferredModuleWith { 73 staticModules = [ 74 # TODO: Add modules for the purpose of generating documentation? 75 ]; 76 } 77 ); 78 default = { }; 79 }; 80 systemd.sockets = mkOption { 81 description = '' 82 Declares systemd socket units. Names will be prefixed by the service name / path. 83 84 See {option}`systemd.services`. 85 ''; 86 type = types.lazyAttrsOf types.deferredModule; 87 default = { }; 88 }; 89 90 # Also import systemd logic into sub-services 91 # extends the portable `services` option 92 services = mkOption { 93 type = types.attrsOf ( 94 types.submoduleWith { 95 class = "service"; 96 modules = [ 97 ./service.nix 98 ]; 99 specialArgs = { 100 inherit systemdPackage; 101 }; 102 } 103 ); 104 # Rendered by the portable docs instead. 105 visible = false; 106 }; 107 }; 108 config = { 109 # Note that this is the systemd.services option above, not the system one. 110 systemd.services."" = { 111 # TODO description; 112 wantedBy = lib.mkDefault [ "multi-user.target" ]; 113 serviceConfig = { 114 Type = lib.mkDefault "simple"; 115 Restart = lib.mkDefault "always"; 116 RestartSec = lib.mkDefault "5"; 117 ExecStart = [ 118 (escapeSystemdExecArgs config.process.argv) 119 ]; 120 }; 121 }; 122 }; 123}