at 25.11-pre 6.0 kB view raw
1# This module creates netboot media containing the given NixOS 2# configuration. 3 4{ 5 config, 6 lib, 7 pkgs, 8 modulesPath, 9 ... 10}: 11 12with lib; 13 14{ 15 imports = [ 16 ../../image/file-options.nix 17 ]; 18 19 options = { 20 21 netboot.squashfsCompression = mkOption { 22 default = "zstd -Xcompression-level 19"; 23 description = '' 24 Compression settings to use for the squashfs nix store. 25 ''; 26 example = "zstd -Xcompression-level 6"; 27 type = types.str; 28 }; 29 30 netboot.storeContents = mkOption { 31 example = literalExpression "[ pkgs.stdenv ]"; 32 description = '' 33 This option lists additional derivations to be included in the 34 Nix store in the generated netboot image. 35 ''; 36 }; 37 38 }; 39 40 config = { 41 # Don't build the GRUB menu builder script, since we don't need it 42 # here and it causes a cyclic dependency. 43 boot.loader.grub.enable = false; 44 45 fileSystems."/" = mkImageMediaOverride { 46 fsType = "tmpfs"; 47 options = [ "mode=0755" ]; 48 }; 49 50 # In stage 1, mount a tmpfs on top of /nix/store (the squashfs 51 # image) to make this a live CD. 52 fileSystems."/nix/.ro-store" = mkImageMediaOverride { 53 fsType = "squashfs"; 54 device = "../nix-store.squashfs"; 55 options = [ 56 "loop" 57 ] ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2") "threads=multi"; 58 neededForBoot = true; 59 }; 60 61 fileSystems."/nix/.rw-store" = mkImageMediaOverride { 62 fsType = "tmpfs"; 63 options = [ "mode=0755" ]; 64 neededForBoot = true; 65 }; 66 67 fileSystems."/nix/store" = mkImageMediaOverride { 68 overlay = { 69 lowerdir = [ "/nix/.ro-store" ]; 70 upperdir = "/nix/.rw-store/store"; 71 workdir = "/nix/.rw-store/work"; 72 }; 73 neededForBoot = true; 74 }; 75 76 boot.initrd.availableKernelModules = [ 77 "squashfs" 78 "overlay" 79 ]; 80 81 boot.initrd.kernelModules = [ 82 "loop" 83 "overlay" 84 ]; 85 86 # Closures to be copied to the Nix store, namely the init 87 # script and the top-level system configuration directory. 88 netboot.storeContents = [ config.system.build.toplevel ]; 89 90 # Create the squashfs image that contains the Nix store. 91 system.build.squashfsStore = pkgs.callPackage ../../../lib/make-squashfs.nix { 92 storeContents = config.netboot.storeContents; 93 comp = config.netboot.squashfsCompression; 94 }; 95 96 # Create the initrd 97 system.build.netbootRamdisk = pkgs.makeInitrdNG { 98 inherit (config.boot.initrd) compressor; 99 prepend = [ "${config.system.build.initialRamdisk}/initrd" ]; 100 101 contents = [ 102 { 103 source = config.system.build.squashfsStore; 104 target = "/nix-store.squashfs"; 105 } 106 ]; 107 }; 108 109 system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" '' 110 #!ipxe 111 # Use the cmdline variable to allow the user to specify custom kernel params 112 # when chainloading this script from other iPXE scripts like netboot.xyz 113 kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} ''${cmdline} 114 initrd initrd 115 boot 116 ''; 117 118 # A script invoking kexec on ./bzImage and ./initrd.gz. 119 # Usually used through system.build.kexecTree, but exposed here for composability. 120 system.build.kexecScript = pkgs.writeScript "kexec-boot" '' 121 #!/usr/bin/env bash 122 if ! kexec -v >/dev/null 2>&1; then 123 echo "kexec not found: please install kexec-tools" 2>&1 124 exit 1 125 fi 126 SCRIPT_DIR=$( cd -- "$( dirname -- "''${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 127 kexec --load ''${SCRIPT_DIR}/bzImage \ 128 --initrd=''${SCRIPT_DIR}/initrd.gz \ 129 --command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" 130 kexec -e 131 ''; 132 133 # A tree containing initrd.gz, bzImage and a kexec-boot script. 134 system.build.kexecTree = pkgs.linkFarm "kexec-tree" [ 135 { 136 name = "initrd.gz"; 137 path = "${config.system.build.netbootRamdisk}/initrd"; 138 } 139 { 140 name = "bzImage"; 141 path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}"; 142 } 143 { 144 name = "kexec-boot"; 145 path = config.system.build.kexecScript; 146 } 147 ]; 148 149 image.extension = "tar.xz"; 150 image.filePath = "tarball/${config.image.fileName}"; 151 system.nixos.tags = [ "kexec" ]; 152 system.build.image = config.system.build.kexecTarball; 153 system.build.kexecTarball = 154 pkgs.callPackage "${toString modulesPath}/../lib/make-system-tarball.nix" 155 { 156 fileName = config.image.baseName; 157 storeContents = [ 158 { 159 object = config.system.build.kexecScript; 160 symlink = "/kexec_nixos"; 161 } 162 ]; 163 contents = [ ]; 164 }; 165 166 boot.loader.timeout = 10; 167 168 boot.postBootCommands = '' 169 # After booting, register the contents of the Nix store 170 # in the Nix database in the tmpfs. 171 ${config.nix.package}/bin/nix-store --load-db < /nix/store/nix-path-registration 172 173 # nixos-rebuild also requires a "system" profile and an 174 # /etc/NIXOS tag. 175 touch /etc/NIXOS 176 ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system 177 178 # Set password for user nixos if specified on cmdline 179 # Allows using nixos-anywhere in headless environments 180 for o in $(</proc/cmdline); do 181 case "$o" in 182 live.nixos.passwordHash=*) 183 set -- $(IFS==; echo $o) 184 ${pkgs.gnugrep}/bin/grep -q "root::" /etc/shadow && ${pkgs.shadow}/bin/usermod -p "$2" root 185 ;; 186 live.nixos.password=*) 187 set -- $(IFS==; echo $o) 188 ${pkgs.gnugrep}/bin/grep -q "root::" /etc/shadow && echo "root:$2" | ${pkgs.shadow}/bin/chpasswd 189 ;; 190 esac 191 done 192 ''; 193 }; 194}