at 25.11-pre 9.6 kB view raw
1/* 2 Declares what makes the nix-daemon work on systemd. 3 See also 4 - nixos/modules/config/nix.nix: the nix.conf 5 - nixos/modules/config/nix-remote-build.nix: the nix.conf 6*/ 7{ 8 config, 9 lib, 10 pkgs, 11 ... 12}: 13let 14 15 cfg = config.nix; 16 17 nixPackage = cfg.package.out; 18 19 # nixVersion is an attribute which defines the implementation version. 20 # This is useful for Nix implementations which don't follow Nix's versioning. 21 isNixAtLeast = lib.versionAtLeast (nixPackage.nixVersion or (lib.getVersion nixPackage)); 22 23 makeNixBuildUser = nr: { 24 name = "nixbld${toString nr}"; 25 value = { 26 description = "Nix build user ${toString nr}"; 27 28 /* 29 For consistency with the setgid(2), setuid(2), and setgroups(2) 30 calls in `libstore/build.cc', don't add any supplementary group 31 here except "nixbld". 32 */ 33 uid = builtins.add config.ids.uids.nixbld nr; 34 isSystemUser = true; 35 group = "nixbld"; 36 extraGroups = [ "nixbld" ]; 37 }; 38 }; 39 40 nixbldUsers = lib.listToAttrs (map makeNixBuildUser (lib.range 1 cfg.nrBuildUsers)); 41 42in 43 44{ 45 imports = [ 46 (lib.mkRenamedOptionModuleWith { 47 sinceRelease = 2205; 48 from = [ 49 "nix" 50 "daemonIONiceLevel" 51 ]; 52 to = [ 53 "nix" 54 "daemonIOSchedPriority" 55 ]; 56 }) 57 (lib.mkRenamedOptionModuleWith { 58 sinceRelease = 2211; 59 from = [ 60 "nix" 61 "readOnlyStore" 62 ]; 63 to = [ 64 "boot" 65 "readOnlyNixStore" 66 ]; 67 }) 68 (lib.mkRemovedOptionModule [ "nix" "daemonNiceLevel" ] "Consider nix.daemonCPUSchedPolicy instead.") 69 ]; 70 71 ###### interface 72 73 options = { 74 75 nix = { 76 77 enable = lib.mkOption { 78 type = lib.types.bool; 79 default = true; 80 description = '' 81 Whether to enable Nix. 82 Disabling Nix makes the system hard to modify and the Nix programs and configuration will not be made available by NixOS itself. 83 ''; 84 }; 85 86 package = lib.mkOption { 87 type = lib.types.package; 88 default = pkgs.nix; 89 defaultText = lib.literalExpression "pkgs.nix"; 90 description = '' 91 This option specifies the Nix package instance to use throughout the system. 92 ''; 93 }; 94 95 daemonCPUSchedPolicy = lib.mkOption { 96 type = lib.types.enum [ 97 "other" 98 "batch" 99 "idle" 100 ]; 101 default = "other"; 102 example = "batch"; 103 description = '' 104 Nix daemon process CPU scheduling policy. This policy propagates to 105 build processes. `other` is the default scheduling 106 policy for regular tasks. The `batch` policy is 107 similar to `other`, but optimised for 108 non-interactive tasks. `idle` is for extremely 109 low-priority tasks that should only be run when no other task 110 requires CPU time. 111 112 Please note that while using the `idle` policy may 113 greatly improve responsiveness of a system performing expensive 114 builds, it may also slow down and potentially starve crucial 115 configuration updates during load. 116 117 `idle` may therefore be a sensible policy for 118 systems that experience only intermittent phases of high CPU load, 119 such as desktop or portable computers used interactively. Other 120 systems should use the `other` or 121 `batch` policy instead. 122 123 For more fine-grained resource control, please refer to 124 {manpage}`systemd.resource-control(5)` and adjust 125 {option}`systemd.services.nix-daemon` directly. 126 ''; 127 }; 128 129 daemonIOSchedClass = lib.mkOption { 130 type = lib.types.enum [ 131 "best-effort" 132 "idle" 133 ]; 134 default = "best-effort"; 135 example = "idle"; 136 description = '' 137 Nix daemon process I/O scheduling class. This class propagates to 138 build processes. `best-effort` is the default 139 class for regular tasks. The `idle` class is for 140 extremely low-priority tasks that should only perform I/O when no 141 other task does. 142 143 Please note that while using the `idle` scheduling 144 class can improve responsiveness of a system performing expensive 145 builds, it might also slow down or starve crucial configuration 146 updates during load. 147 148 `idle` may therefore be a sensible class for 149 systems that experience only intermittent phases of high I/O load, 150 such as desktop or portable computers used interactively. Other 151 systems should use the `best-effort` class. 152 ''; 153 }; 154 155 daemonIOSchedPriority = lib.mkOption { 156 type = lib.types.int; 157 default = 4; 158 example = 1; 159 description = '' 160 Nix daemon process I/O scheduling priority. This priority propagates 161 to build processes. The supported priorities depend on the 162 scheduling policy: With idle, priorities are not used in scheduling 163 decisions. best-effort supports values in the range 0 (high) to 7 164 (low). 165 ''; 166 }; 167 168 # Environment variables for running Nix. 169 envVars = lib.mkOption { 170 type = lib.types.attrs; 171 internal = true; 172 default = { }; 173 description = "Environment variables used by Nix."; 174 }; 175 176 nrBuildUsers = lib.mkOption { 177 type = lib.types.int; 178 description = '' 179 Number of `nixbld` user accounts created to 180 perform secure concurrent builds. If you receive an error 181 message saying that all build users are currently in use, 182 you should increase this value. 183 ''; 184 }; 185 }; 186 }; 187 188 ###### implementation 189 190 config = lib.mkIf cfg.enable { 191 environment.systemPackages = [ 192 nixPackage 193 pkgs.nix-info 194 ] ++ lib.optional (config.programs.bash.completion.enable) pkgs.nix-bash-completions; 195 196 systemd.packages = [ nixPackage ]; 197 198 systemd.tmpfiles = lib.mkMerge [ 199 (lib.mkIf (isNixAtLeast "2.8") { 200 packages = [ nixPackage ]; 201 }) 202 (lib.mkIf (!isNixAtLeast "2.8") { 203 rules = [ 204 "d /nix/var/nix/daemon-socket 0755 root root - -" 205 ]; 206 }) 207 ]; 208 209 systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ]; 210 211 systemd.services.nix-daemon = { 212 path = [ 213 nixPackage 214 pkgs.util-linux 215 config.programs.ssh.package 216 ] ++ lib.optionals cfg.distributedBuilds [ pkgs.gzip ]; 217 218 environment = 219 cfg.envVars 220 // { 221 CURL_CA_BUNDLE = config.security.pki.caBundle; 222 } 223 // config.networking.proxy.envVars; 224 225 unitConfig.RequiresMountsFor = "/nix/store"; 226 227 serviceConfig = { 228 CPUSchedulingPolicy = cfg.daemonCPUSchedPolicy; 229 IOSchedulingClass = cfg.daemonIOSchedClass; 230 IOSchedulingPriority = cfg.daemonIOSchedPriority; 231 LimitNOFILE = 1048576; 232 Delegate = "yes"; 233 }; 234 235 restartTriggers = [ config.environment.etc."nix/nix.conf".source ]; 236 237 # `stopIfChanged = false` changes to switch behavior 238 # from stop -> update units -> start 239 # to update units -> restart 240 # 241 # The `stopIfChanged` setting therefore controls a trade-off between a 242 # more predictable lifecycle, which runs the correct "version" of 243 # the `ExecStop` line, and on the other hand the availability of 244 # sockets during the switch, as the effectiveness of the stop operation 245 # depends on the socket being stopped as well. 246 # 247 # As `nix-daemon.service` does not make use of `ExecStop`, we prefer 248 # to keep the socket up and available. This is important for machines 249 # that run Nix-based services, such as automated build, test, and deploy 250 # services, that expect the daemon socket to be available at all times. 251 # 252 # Notably, the Nix client does not retry on failure to connect to the 253 # daemon socket, and the in-process RemoteStore instance will disable 254 # itself. This makes retries infeasible even for services that are 255 # aware of the issue. Failure to connect can affect not only new client 256 # processes, but also new RemoteStore instances in existing processes, 257 # as well as existing RemoteStore instances that have not saturated 258 # their connection pool. 259 # 260 # Also note that `stopIfChanged = true` does not kill existing 261 # connection handling daemons, as one might wish to happen before a 262 # breaking Nix upgrade (which is rare). The daemon forks that handle 263 # the individual connections split off into their own sessions, causing 264 # them not to be stopped by systemd. 265 # If a Nix upgrade does require all existing daemon processes to stop, 266 # nix-daemon must do so on its own accord, and only when the new version 267 # starts and detects that Nix's persistent state needs an upgrade. 268 stopIfChanged = false; 269 270 }; 271 272 # Set up the environment variables for running Nix. 273 environment.sessionVariables = cfg.envVars; 274 275 nix.nrBuildUsers = lib.mkDefault ( 276 if cfg.settings.auto-allocate-uids or false then 277 0 278 else 279 lib.max 32 (if cfg.settings.max-jobs == "auto" then 0 else cfg.settings.max-jobs) 280 ); 281 282 users.users = nixbldUsers; 283 284 services.displayManager.hiddenUsers = lib.attrNames nixbldUsers; 285 286 # Legacy configuration conversion. 287 nix.settings = lib.mkMerge [ 288 (lib.mkIf (isNixAtLeast "2.3pre") { sandbox-fallback = false; }) 289 ]; 290 291 }; 292 293}