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, # Whether the disk should be partitioned (with a single partition
11 # containing the root filesystem) or contain the root filesystem
12 # directly.
13 partitioned ? true
14
15, # The root file system type.
16 fsType ? "ext4"
17
18, # The initial NixOS configuration file to be copied to
19 # /etc/nixos/configuration.nix.
20 configFile ? null
21
22, # Shell code executed after the VM has finished.
23 postVM ? ""
24
25}:
26
27with lib;
28
29pkgs.vmTools.runInLinuxVM (
30 pkgs.runCommand "nixos-disk-image"
31 { preVM =
32 ''
33 mkdir $out
34 diskImage=$out/nixos.img
35 ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "${toString diskSize}M"
36 mv closure xchg/
37 '';
38 buildInputs = [ pkgs.utillinux pkgs.perl pkgs.e2fsprogs pkgs.parted ];
39 exportReferencesGraph =
40 [ "closure" config.system.build.toplevel ];
41 inherit postVM;
42 memSize = 1024;
43 }
44 ''
45 ${if partitioned then ''
46 # Create a single / partition.
47 parted /dev/vda mklabel msdos
48 parted /dev/vda -- mkpart primary ext2 1M -1s
49 . /sys/class/block/vda1/uevent
50 mknod /dev/vda1 b $MAJOR $MINOR
51 rootDisk=/dev/vda1
52 '' else ''
53 rootDisk=/dev/vda
54 ''}
55
56 # Create an empty filesystem and mount it.
57 mkfs.${fsType} -L nixos $rootDisk
58 ${optionalString (fsType == "ext4") ''
59 tune2fs -c 0 -i 0 $rootDisk
60 ''}
61 mkdir /mnt
62 mount $rootDisk /mnt
63
64 # The initrd expects these directories to exist.
65 mkdir /mnt/dev /mnt/proc /mnt/sys
66
67 mount -o bind /proc /mnt/proc
68 mount -o bind /dev /mnt/dev
69 mount -o bind /sys /mnt/sys
70
71 # Copy all paths in the closure to the filesystem.
72 storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
73
74 mkdir -p /mnt/nix/store
75 echo "copying everything (will take a while)..."
76 set -f
77 cp -prd $storePaths /mnt/nix/store/
78
79 # Register the paths in the Nix database.
80 printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
81 chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group ""
82
83 # Add missing size/hash fields to the database. FIXME:
84 # exportReferencesGraph should provide these directly.
85 chroot /mnt ${config.nix.package}/bin/nix-store --verify --check-contents
86
87 # Create the system profile to allow nixos-rebuild to work.
88 chroot /mnt ${config.nix.package}/bin/nix-env --option build-users-group "" \
89 -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
90
91 # `nixos-rebuild' requires an /etc/NIXOS.
92 mkdir -p /mnt/etc
93 touch /mnt/etc/NIXOS
94
95 # `switch-to-configuration' requires a /bin/sh
96 mkdir -p /mnt/bin
97 ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
98
99 # Install a configuration.nix.
100 mkdir -p /mnt/etc/nixos
101 ${optionalString (configFile != null) ''
102 cp ${configFile} /mnt/etc/nixos/configuration.nix
103 ''}
104
105 # Generate the GRUB menu.
106 ln -s vda /dev/xvda
107 ln -s vda /dev/sda
108 chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
109
110 umount /mnt/proc /mnt/dev /mnt/sys
111 umount /mnt
112
113 # Do a fsck to make sure resize2fs works.
114 fsck.${fsType} -f -y $rootDisk
115 ''
116)