at 17.09-beta 5.9 kB view raw
1{ pkgs 2, lib 3 4, # The NixOS configuration to be installed onto the disk image. 5 config 6 7, # The size of the disk, in megabytes. 8 diskSize 9 10 # The files and directories to be placed in the target file system. 11 # This is a list of attribute sets {source, target} where `source' 12 # is the file system object (regular file or directory) to be 13 # grafted in the file system at path `target'. 14, contents ? [] 15 16, # Whether the disk should be partitioned (with a single partition 17 # containing the root filesystem) or contain the root filesystem 18 # directly. 19 partitioned ? true 20 21 # Whether to invoke switch-to-configuration boot during image creation 22, installBootLoader ? true 23 24, # The root file system type. 25 fsType ? "ext4" 26 27, # The initial NixOS configuration file to be copied to 28 # /etc/nixos/configuration.nix. 29 configFile ? null 30 31, # Shell code executed after the VM has finished. 32 postVM ? "" 33 34, name ? "nixos-disk-image" 35 36, format ? "raw" 37}: 38 39with lib; 40 41let 42 extensions = { 43 qcow2 = "qcow2"; 44 vpc = "vhd"; 45 raw = "img"; 46 }; 47 48 nixpkgs = lib.cleanSource pkgs.path; 49 50 channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" {} '' 51 mkdir -p $out 52 cp -prd ${nixpkgs} $out/nixos 53 chmod -R u+w $out/nixos 54 if [ ! -e $out/nixos/nixpkgs ]; then 55 ln -s . $out/nixos/nixpkgs 56 fi 57 rm -rf $out/nixos/.git 58 echo -n ${config.system.nixosVersionSuffix} > $out/nixos/.version-suffix 59 ''; 60 61 metaClosure = pkgs.writeText "meta" '' 62 ${config.system.build.toplevel} 63 ${config.nix.package.out} 64 ${channelSources} 65 ''; 66 67 prepareImageInputs = with pkgs; [ rsync utillinux parted e2fsprogs lkl fakeroot config.system.build.nixos-prepare-root ] ++ stdenv.initialPath; 68 69 # I'm preserving the line below because I'm going to search for it across nixpkgs to consolidate 70 # image building logic. The comment right below this now appears in 4 different places in nixpkgs :) 71 # !!! should use XML. 72 sources = map (x: x.source) contents; 73 targets = map (x: x.target) contents; 74 75 prepareImage = '' 76 export PATH=${pkgs.lib.makeSearchPathOutput "bin" "bin" prepareImageInputs} 77 78 mkdir $out 79 diskImage=nixos.raw 80 truncate -s ${toString diskSize}M $diskImage 81 82 ${if partitioned then '' 83 parted $diskImage -- mklabel msdos mkpart primary ext4 1M -1s 84 offset=$((2048*512)) 85 '' else '' 86 offset=0 87 ''} 88 89 mkfs.${fsType} -F -L nixos -E offset=$offset $diskImage 90 91 root="$PWD/root" 92 mkdir -p $root 93 94 # Copy arbitrary other files into the image 95 # Semi-shamelessly copied from make-etc.sh. I (@copumpkin) shall factor this stuff out as part of 96 # https://github.com/NixOS/nixpkgs/issues/23052. 97 set -f 98 sources_=(${concatStringsSep " " sources}) 99 targets_=(${concatStringsSep " " targets}) 100 set +f 101 102 for ((i = 0; i < ''${#targets_[@]}; i++)); do 103 source="''${sources_[$i]}" 104 target="''${targets_[$i]}" 105 106 if [[ "$source" =~ '*' ]]; then 107 # If the source name contains '*', perform globbing. 108 mkdir -p $root/$target 109 for fn in $source; do 110 rsync -a --no-o --no-g "$fn" $root/$target/ 111 done 112 else 113 mkdir -p $root/$(dirname $target) 114 if ! [ -e $root/$target ]; then 115 rsync -a --no-o --no-g $source $root/$target 116 else 117 echo "duplicate entry $target -> $source" 118 exit 1 119 fi 120 fi 121 done 122 123 # TODO: Nix really likes to chown things it creates to its current user... 124 fakeroot nixos-prepare-root $root ${channelSources} ${config.system.build.toplevel} closure 125 126 echo "copying staging root to image..." 127 cptofs ${pkgs.lib.optionalString partitioned "-P 1"} -t ${fsType} -i $diskImage $root/* / 128 ''; 129in pkgs.vmTools.runInLinuxVM ( 130 pkgs.runCommand name 131 { preVM = prepareImage; 132 buildInputs = with pkgs; [ utillinux e2fsprogs ]; 133 exportReferencesGraph = [ "closure" metaClosure ]; 134 postVM = '' 135 ${if format == "raw" then '' 136 mv $diskImage $out/nixos.img 137 diskImage=$out/nixos.img 138 '' else '' 139 ${pkgs.qemu}/bin/qemu-img convert -f raw -O ${format} $diskImage $out/nixos.${extensions.${format}} 140 diskImage=$out/nixos.${extensions.${format}} 141 ''} 142 ${postVM} 143 ''; 144 memSize = 1024; 145 } 146 '' 147 ${if partitioned then '' 148 . /sys/class/block/vda1/uevent 149 mknod /dev/vda1 b $MAJOR $MINOR 150 rootDisk=/dev/vda1 151 '' else '' 152 rootDisk=/dev/vda 153 ''} 154 155 # Some tools assume these exist 156 ln -s vda /dev/xvda 157 ln -s vda /dev/sda 158 159 mountPoint=/mnt 160 mkdir $mountPoint 161 mount $rootDisk $mountPoint 162 163 # Install a configuration.nix 164 mkdir -p /mnt/etc/nixos 165 ${optionalString (configFile != null) '' 166 cp ${configFile} /mnt/etc/nixos/configuration.nix 167 ''} 168 169 mount --rbind /dev $mountPoint/dev 170 mount --rbind /proc $mountPoint/proc 171 mount --rbind /sys $mountPoint/sys 172 173 # Set up core system link, GRUB, etc. 174 NIXOS_INSTALL_BOOTLOADER=1 chroot $mountPoint /nix/var/nix/profiles/system/bin/switch-to-configuration boot 175 176 # TODO: figure out if I should activate, but for now I won't 177 # chroot $mountPoint /nix/var/nix/profiles/system/activate 178 179 # The above scripts will generate a random machine-id and we don't want to bake a single ID into all our images 180 rm -f $mountPoint/etc/machine-id 181 182 umount -R /mnt 183 184 # Make sure resize2fs works. Note that resize2fs has stricter criteria for resizing than a normal 185 # mount, so the `-c 0` and `-i 0` don't affect it. Setting it to `now` doesn't produce deterministic 186 # output, of course, but we can fix that when/if we start making images deterministic. 187 ${optionalString (fsType == "ext4") '' 188 tune2fs -T now -c 0 -i 0 $rootDisk 189 ''} 190 '' 191)