at master 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 ] 195 ++ lib.optional (config.programs.bash.completion.enable) pkgs.nix-bash-completions; 196 197 systemd.packages = [ nixPackage ]; 198 199 systemd.tmpfiles = lib.mkMerge [ 200 (lib.mkIf (isNixAtLeast "2.8") { 201 packages = [ nixPackage ]; 202 }) 203 (lib.mkIf (!isNixAtLeast "2.8") { 204 rules = [ 205 "d /nix/var/nix/daemon-socket 0755 root root - -" 206 ]; 207 }) 208 ]; 209 210 systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ]; 211 212 systemd.services.nix-daemon = { 213 path = [ 214 nixPackage 215 pkgs.util-linux 216 config.programs.ssh.package 217 ] 218 ++ lib.optionals cfg.distributedBuilds [ pkgs.gzip ]; 219 220 environment = 221 cfg.envVars 222 // { 223 CURL_CA_BUNDLE = config.security.pki.caBundle; 224 } 225 // config.networking.proxy.envVars; 226 227 unitConfig.RequiresMountsFor = "/nix/store"; 228 229 serviceConfig = { 230 CPUSchedulingPolicy = cfg.daemonCPUSchedPolicy; 231 IOSchedulingClass = cfg.daemonIOSchedClass; 232 IOSchedulingPriority = cfg.daemonIOSchedPriority; 233 LimitNOFILE = 1048576; 234 Delegate = "yes"; 235 DelegateSubgroup = "supervisor"; 236 }; 237 238 restartTriggers = [ config.environment.etc."nix/nix.conf".source ]; 239 240 # `stopIfChanged = false` changes to switch behavior 241 # from stop -> update units -> start 242 # to update units -> restart 243 # 244 # The `stopIfChanged` setting therefore controls a trade-off between a 245 # more predictable lifecycle, which runs the correct "version" of 246 # the `ExecStop` line, and on the other hand the availability of 247 # sockets during the switch, as the effectiveness of the stop operation 248 # depends on the socket being stopped as well. 249 # 250 # As `nix-daemon.service` does not make use of `ExecStop`, we prefer 251 # to keep the socket up and available. This is important for machines 252 # that run Nix-based services, such as automated build, test, and deploy 253 # services, that expect the daemon socket to be available at all times. 254 # 255 # Notably, the Nix client does not retry on failure to connect to the 256 # daemon socket, and the in-process RemoteStore instance will disable 257 # itself. This makes retries infeasible even for services that are 258 # aware of the issue. Failure to connect can affect not only new client 259 # processes, but also new RemoteStore instances in existing processes, 260 # as well as existing RemoteStore instances that have not saturated 261 # their connection pool. 262 # 263 # Also note that `stopIfChanged = true` does not kill existing 264 # connection handling daemons, as one might wish to happen before a 265 # breaking Nix upgrade (which is rare). The daemon forks that handle 266 # the individual connections split off into their own sessions, causing 267 # them not to be stopped by systemd. 268 # If a Nix upgrade does require all existing daemon processes to stop, 269 # nix-daemon must do so on its own accord, and only when the new version 270 # starts and detects that Nix's persistent state needs an upgrade. 271 stopIfChanged = false; 272 273 }; 274 275 # Set up the environment variables for running Nix. 276 environment.sessionVariables = cfg.envVars; 277 278 nix.nrBuildUsers = lib.mkDefault ( 279 if cfg.settings.auto-allocate-uids or false then 280 0 281 else 282 lib.max 32 (if cfg.settings.max-jobs == "auto" then 0 else cfg.settings.max-jobs) 283 ); 284 285 users.users = nixbldUsers; 286 287 services.displayManager.hiddenUsers = lib.attrNames nixbldUsers; 288 289 # Legacy configuration conversion. 290 nix.settings = lib.mkMerge [ 291 (lib.mkIf (isNixAtLeast "2.3pre") { sandbox-fallback = false; }) 292 ]; 293 294 }; 295 296}