at 18.09-beta 17 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.nix; 8 9 nix = cfg.package.out; 10 11 isNix20 = versionAtLeast (getVersion nix) "2.0pre"; 12 13 makeNixBuildUser = nr: 14 { name = "nixbld${toString nr}"; 15 description = "Nix build user ${toString nr}"; 16 17 /* For consistency with the setgid(2), setuid(2), and setgroups(2) 18 calls in `libstore/build.cc', don't add any supplementary group 19 here except "nixbld". */ 20 uid = builtins.add config.ids.uids.nixbld nr; 21 group = "nixbld"; 22 extraGroups = [ "nixbld" ]; 23 }; 24 25 nixbldUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers); 26 27 nixConf = 28 let 29 # In Nix < 2.0, If we're using sandbox for builds, then provide 30 # /bin/sh in the sandbox as a bind-mount to bash. This means we 31 # also need to include the entire closure of bash. Nix >= 2.0 32 # provides a /bin/sh by default. 33 sh = pkgs.runtimeShell; 34 binshDeps = pkgs.writeReferencesToFile sh; 35 in 36 pkgs.runCommand "nix.conf" { extraOptions = cfg.extraOptions; } ('' 37 ${optionalString (!isNix20) '' 38 extraPaths=$(for i in $(cat ${binshDeps}); do if test -d $i; then echo $i; fi; done) 39 ''} 40 cat > $out <<END 41 # WARNING: this file is generated from the nix.* options in 42 # your NixOS configuration, typically 43 # /etc/nixos/configuration.nix. Do not edit it! 44 build-users-group = nixbld 45 ${if isNix20 then "max-jobs" else "build-max-jobs"} = ${toString (cfg.maxJobs)} 46 ${if isNix20 then "cores" else "build-cores"} = ${toString (cfg.buildCores)} 47 ${if isNix20 then "sandbox" else "build-use-sandbox"} = ${if (builtins.isBool cfg.useSandbox) then boolToString cfg.useSandbox else cfg.useSandbox} 48 ${if isNix20 then "extra-sandbox-paths" else "build-sandbox-paths"} = ${toString cfg.sandboxPaths} ${optionalString (!isNix20) "/bin/sh=${sh} $(echo $extraPaths)"} 49 ${if isNix20 then "substituters" else "binary-caches"} = ${toString cfg.binaryCaches} 50 ${if isNix20 then "trusted-substituters" else "trusted-binary-caches"} = ${toString cfg.trustedBinaryCaches} 51 ${if isNix20 then "trusted-public-keys" else "binary-cache-public-keys"} = ${toString cfg.binaryCachePublicKeys} 52 auto-optimise-store = ${boolToString cfg.autoOptimiseStore} 53 ${if isNix20 then '' 54 require-sigs = ${if cfg.requireSignedBinaryCaches then "true" else "false"} 55 '' else '' 56 signed-binary-caches = ${if cfg.requireSignedBinaryCaches then "*" else ""} 57 ''} 58 trusted-users = ${toString cfg.trustedUsers} 59 allowed-users = ${toString cfg.allowedUsers} 60 ${optionalString (isNix20 && !cfg.distributedBuilds) '' 61 builders = 62 ''} 63 $extraOptions 64 END 65 '' + optionalString cfg.checkConfig '' 66 echo "Checking that Nix can read nix.conf..." 67 ln -s $out ./nix.conf 68 NIX_CONF_DIR=$PWD ${cfg.package}/bin/nix show-config >/dev/null 69 ''); 70 71in 72 73{ 74 75 ###### interface 76 77 options = { 78 79 nix = { 80 81 package = mkOption { 82 type = types.package; 83 default = pkgs.nix; 84 defaultText = "pkgs.nix"; 85 description = '' 86 This option specifies the Nix package instance to use throughout the system. 87 ''; 88 }; 89 90 maxJobs = mkOption { 91 type = types.either types.int (types.enum ["auto"]); 92 default = 1; 93 example = 64; 94 description = '' 95 This option defines the maximum number of jobs that Nix will try 96 to build in parallel. The default is 1. You should generally 97 set it to the total number of logical cores in your system (e.g., 16 98 for two CPUs with 4 cores each and hyper-threading). 99 ''; 100 }; 101 102 autoOptimiseStore = mkOption { 103 type = types.bool; 104 default = false; 105 example = true; 106 description = '' 107 If set to true, Nix automatically detects files in the store that have 108 identical contents, and replaces them with hard links to a single copy. 109 This saves disk space. If set to false (the default), you can still run 110 nix-store --optimise to get rid of duplicate files. 111 ''; 112 }; 113 114 buildCores = mkOption { 115 type = types.int; 116 default = 1; 117 example = 64; 118 description = '' 119 This option defines the maximum number of concurrent tasks during 120 one build. It affects, e.g., -j option for make. The default is 1. 121 The special value 0 means that the builder should use all 122 available CPU cores in the system. Some builds may become 123 non-deterministic with this option; use with care! Packages will 124 only be affected if enableParallelBuilding is set for them. 125 ''; 126 }; 127 128 useSandbox = mkOption { 129 type = types.either types.bool (types.enum ["relaxed"]); 130 default = true; 131 description = " 132 If set, Nix will perform builds in a sandboxed environment that it 133 will set up automatically for each build. This prevents impurities 134 in builds by disallowing access to dependencies outside of the Nix 135 store by using network and mount namespaces in a chroot environment. 136 This is enabled by default even though it has a possible performance 137 impact due to the initial setup time of a sandbox for each build. It 138 doesn't affect derivation hashes, so changing this option will not 139 trigger a rebuild of packages. 140 "; 141 }; 142 143 sandboxPaths = mkOption { 144 type = types.listOf types.str; 145 default = []; 146 example = [ "/dev" "/proc" ]; 147 description = 148 '' 149 Directories from the host filesystem to be included 150 in the sandbox. 151 ''; 152 }; 153 154 extraOptions = mkOption { 155 type = types.lines; 156 default = ""; 157 example = '' 158 gc-keep-outputs = true 159 gc-keep-derivations = true 160 ''; 161 description = "Additional text appended to <filename>nix.conf</filename>."; 162 }; 163 164 distributedBuilds = mkOption { 165 type = types.bool; 166 default = false; 167 description = '' 168 Whether to distribute builds to the machines listed in 169 <option>nix.buildMachines</option>. 170 ''; 171 }; 172 173 daemonNiceLevel = mkOption { 174 type = types.int; 175 default = 0; 176 description = '' 177 Nix daemon process priority. This priority propagates to build processes. 178 0 is the default Unix process priority, 19 is the lowest. 179 ''; 180 }; 181 182 daemonIONiceLevel = mkOption { 183 type = types.int; 184 default = 0; 185 description = '' 186 Nix daemon process I/O priority. This priority propagates to build processes. 187 0 is the default Unix process I/O priority, 7 is the lowest. 188 ''; 189 }; 190 191 buildMachines = mkOption { 192 type = types.listOf types.attrs; 193 default = []; 194 example = literalExample '' 195 [ { hostName = "voila.labs.cs.uu.nl"; 196 sshUser = "nix"; 197 sshKey = "/root/.ssh/id_buildfarm"; 198 system = "powerpc-darwin"; 199 maxJobs = 1; 200 } 201 { hostName = "linux64.example.org"; 202 sshUser = "buildfarm"; 203 sshKey = "/root/.ssh/id_buildfarm"; 204 system = "x86_64-linux"; 205 maxJobs = 2; 206 speedFactor = 2; 207 supportedFeatures = [ "kvm" ]; 208 mandatoryFeatures = [ "perf" ]; 209 } 210 ] 211 ''; 212 description = '' 213 This option lists the machines to be used if distributed 214 builds are enabled (see 215 <option>nix.distributedBuilds</option>). Nix will perform 216 derivations on those machines via SSH by copying the inputs 217 to the Nix store on the remote machine, starting the build, 218 then copying the output back to the local Nix store. Each 219 element of the list should be an attribute set containing 220 the machine's host name (<varname>hostname</varname>), the 221 user name to be used for the SSH connection 222 (<varname>sshUser</varname>), the Nix system type 223 (<varname>system</varname>, e.g., 224 <literal>"i686-linux"</literal>), the maximum number of 225 jobs to be run in parallel on that machine 226 (<varname>maxJobs</varname>), the path to the SSH private 227 key to be used to connect (<varname>sshKey</varname>), a 228 list of supported features of the machine 229 (<varname>supportedFeatures</varname>) and a list of 230 mandatory features of the machine 231 (<varname>mandatoryFeatures</varname>). The SSH private key 232 should not have a passphrase, and the corresponding public 233 key should be added to 234 <filename>~<replaceable>sshUser</replaceable>/authorized_keys</filename> 235 on the remote machine. 236 ''; 237 }; 238 239 # Environment variables for running Nix. 240 envVars = mkOption { 241 type = types.attrs; 242 internal = true; 243 default = {}; 244 description = "Environment variables used by Nix."; 245 }; 246 247 nrBuildUsers = mkOption { 248 type = types.int; 249 description = '' 250 Number of <literal>nixbld</literal> user accounts created to 251 perform secure concurrent builds. If you receive an error 252 message saying that all build users are currently in use, 253 you should increase this value. 254 ''; 255 }; 256 257 readOnlyStore = mkOption { 258 type = types.bool; 259 default = true; 260 description = '' 261 If set, NixOS will enforce the immutability of the Nix store 262 by making <filename>/nix/store</filename> a read-only bind 263 mount. Nix will automatically make the store writable when 264 needed. 265 ''; 266 }; 267 268 binaryCaches = mkOption { 269 type = types.listOf types.str; 270 default = [ https://cache.nixos.org/ ]; 271 description = '' 272 List of binary cache URLs used to obtain pre-built binaries 273 of Nix packages. 274 ''; 275 }; 276 277 trustedBinaryCaches = mkOption { 278 type = types.listOf types.str; 279 default = [ ]; 280 example = [ http://hydra.nixos.org/ ]; 281 description = '' 282 List of binary cache URLs that non-root users can use (in 283 addition to those specified using 284 <option>nix.binaryCaches</option>) by passing 285 <literal>--option binary-caches</literal> to Nix commands. 286 ''; 287 }; 288 289 requireSignedBinaryCaches = mkOption { 290 type = types.bool; 291 default = true; 292 description = '' 293 If enabled (the default), Nix will only download binaries from binary caches if 294 they are cryptographically signed with any of the keys listed in 295 <option>nix.binaryCachePublicKeys</option>. If disabled, signatures are neither 296 required nor checked, so it's strongly recommended that you use only 297 trustworthy caches and https to prevent man-in-the-middle attacks. 298 ''; 299 }; 300 301 binaryCachePublicKeys = mkOption { 302 type = types.listOf types.str; 303 example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ]; 304 description = '' 305 List of public keys used to sign binary caches. If 306 <option>nix.requireSignedBinaryCaches</option> is enabled, 307 then Nix will use a binary from a binary cache if and only 308 if it is signed by <emphasis>any</emphasis> of the keys 309 listed here. By default, only the key for 310 <uri>cache.nixos.org</uri> is included. 311 ''; 312 }; 313 314 trustedUsers = mkOption { 315 type = types.listOf types.str; 316 default = [ "root" ]; 317 example = [ "root" "alice" "@wheel" ]; 318 description = '' 319 A list of names of users that have additional rights when 320 connecting to the Nix daemon, such as the ability to specify 321 additional binary caches, or to import unsigned NARs. You 322 can also specify groups by prefixing them with 323 <literal>@</literal>; for instance, 324 <literal>@wheel</literal> means all users in the wheel 325 group. 326 ''; 327 }; 328 329 allowedUsers = mkOption { 330 type = types.listOf types.str; 331 default = [ "*" ]; 332 example = [ "@wheel" "@builders" "alice" "bob" ]; 333 description = '' 334 A list of names of users (separated by whitespace) that are 335 allowed to connect to the Nix daemon. As with 336 <option>nix.trustedUsers</option>, you can specify groups by 337 prefixing them with <literal>@</literal>. Also, you can 338 allow all users by specifying <literal>*</literal>. The 339 default is <literal>*</literal>. Note that trusted users are 340 always allowed to connect. 341 ''; 342 }; 343 344 nixPath = mkOption { 345 type = types.listOf types.str; 346 default = 347 [ 348 "$HOME/.nix-defexpr/channels" 349 "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos" 350 "nixos-config=/etc/nixos/configuration.nix" 351 "/nix/var/nix/profiles/per-user/root/channels" 352 ]; 353 description = '' 354 The default Nix expression search path, used by the Nix 355 evaluator to look up paths enclosed in angle brackets 356 (e.g. <literal>&lt;nixpkgs&gt;</literal>). 357 ''; 358 }; 359 360 checkConfig = mkOption { 361 type = types.bool; 362 default = true; 363 description = '' 364 If enabled (the default), checks that Nix can parse the generated nix.conf. 365 ''; 366 }; 367 }; 368 369 }; 370 371 372 ###### implementation 373 374 config = { 375 376 nix.binaryCachePublicKeys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ]; 377 378 environment.etc."nix/nix.conf".source = nixConf; 379 380 # List of machines for distributed Nix builds in the format 381 # expected by build-remote.pl. 382 environment.etc."nix/machines" = 383 { enable = cfg.buildMachines != []; 384 text = 385 concatMapStrings (machine: 386 "${if machine ? sshUser then "${machine.sshUser}@" else ""}${machine.hostName} " 387 + machine.system or (concatStringsSep "," machine.systems) 388 + " ${machine.sshKey or "-"} ${toString machine.maxJobs or 1} " 389 + toString (machine.speedFactor or 1) 390 + " " 391 + concatStringsSep "," (machine.mandatoryFeatures or [] ++ machine.supportedFeatures or []) 392 + " " 393 + concatStringsSep "," machine.mandatoryFeatures or [] 394 + "\n" 395 ) cfg.buildMachines; 396 }; 397 398 systemd.packages = [ nix ]; 399 400 systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ]; 401 402 systemd.services.nix-daemon = 403 { path = [ nix pkgs.utillinux ] 404 ++ optionals cfg.distributedBuilds [ config.programs.ssh.package pkgs.gzip ] 405 ++ optionals (!isNix20) [ pkgs.openssl.bin ]; 406 407 environment = cfg.envVars 408 // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; } 409 // config.networking.proxy.envVars; 410 411 unitConfig.RequiresMountsFor = "/nix/store"; 412 413 serviceConfig = 414 { Nice = cfg.daemonNiceLevel; 415 IOSchedulingPriority = cfg.daemonIONiceLevel; 416 LimitNOFILE = 4096; 417 }; 418 419 restartTriggers = [ nixConf ]; 420 }; 421 422 nix.envVars = 423 optionalAttrs (!isNix20) { 424 NIX_CONF_DIR = "/etc/nix"; 425 426 # Enable the copy-from-other-stores substituter, which allows 427 # builds to be sped up by copying build results from remote 428 # Nix stores. To do this, mount the remote file system on a 429 # subdirectory of /run/nix/remote-stores. 430 NIX_OTHER_STORES = "/run/nix/remote-stores/*/nix"; 431 } 432 433 // optionalAttrs (cfg.distributedBuilds && !isNix20) { 434 NIX_BUILD_HOOK = "${nix}/libexec/nix/build-remote.pl"; 435 }; 436 437 # Set up the environment variables for running Nix. 438 environment.sessionVariables = cfg.envVars // 439 { NIX_PATH = concatStringsSep ":" cfg.nixPath; 440 }; 441 442 environment.extraInit = optionalString (!isNix20) 443 '' 444 # Set up secure multi-user builds: non-root users build through the 445 # Nix daemon. 446 if [ "$USER" != root -o ! -w /nix/var/nix/db ]; then 447 export NIX_REMOTE=daemon 448 fi 449 ''; 450 451 nix.nrBuildUsers = mkDefault (lib.max 32 cfg.maxJobs); 452 453 users.users = nixbldUsers; 454 455 services.xserver.displayManager.hiddenUsers = map ({ name, ... }: name) nixbldUsers; 456 457 # FIXME: use systemd-tmpfiles to create Nix directories. 458 system.activationScripts.nix = stringAfter [ "etc" "users" ] 459 '' 460 # Nix initialisation. 461 install -m 0755 -d \ 462 /nix/var/nix/gcroots \ 463 /nix/var/nix/temproots \ 464 /nix/var/nix/userpool \ 465 /nix/var/nix/profiles \ 466 /nix/var/nix/db \ 467 /nix/var/log/nix/drvs 468 install -m 1777 -d \ 469 /nix/var/nix/gcroots/per-user \ 470 /nix/var/nix/profiles/per-user \ 471 /nix/var/nix/gcroots/tmp 472 ''; 473 474 }; 475 476}