@ -33,42 +33,124 @@
, name ? " n i x o s - d i s k - i m a g e "
# This prevents errors while checking nix-store validity, see
# https://github.com/NixOS/nix/issues/1134
, fixValidity ? true
, format ? " r a w "
} :
with lib ;
pkgs . vmTools . runInLinuxVM (
let
# Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/cd-dvd/channel.nix
# TODO: factor out more cleanly
# Do not include these things:
# - The '.git' directory
# - Result symlinks from nix-build ('result', 'result-2', 'result-bin', ...)
# - VIM/Emacs swap/backup files ('.swp', '.swo', '.foo.swp', 'foo~', ...)
filterFn = path : type : let basename = baseNameOf ( toString path ) ; in
if type == " d i r e c t o r y " then basename != " . g i t "
else if type == " s y m l i n k " then builtins . match " ^ r e s u l t ( | - . * ) $ " basename == null
else builtins . match " ^ ( ( | \. . * ) \. s w [ a - z ] | . * ~ ) $ " basename == null ;
nixpkgs = builtins . filterSource filterFn pkgs . path ;
channelSources = pkgs . runCommand " n i x o s - ${ config . system . nixosVersion } " { } ''
mkdir - p $ out
cp - prd $ { nixpkgs } $ out/nixos
chmod - R u + w $ out/nixos
if [ ! - e $ out/nixos/nixpkgs ] ; then
ln - s . $ out/nixos/nixpkgs
fi
rm - rf $ out/nixos/.git
echo - n $ { config . system . nixosVersionSuffix } > $ out/nixos/.version-suffix
'' ;
metaClosure = pkgs . writeText " m e t a " ''
$ { config . system . build . toplevel }
$ { config . nix . package . out }
$ { channelSources }
'' ;
prepareImageInputs = with pkgs ; [ rsync utillinux parted e2fsprogs lkl fakeroot config . system . build . nixos-prepare-root ] ++ stdenv . initialPath ;
# I'm preserving the line below because I'm going to search for it across nixpkgs to consolidate
# image building logic. The comment right below this now appears in 4 different places in nixpkgs :)
# !!! should use XML.
sources = map ( x : x . source ) contents ;
targets = map ( x : x . target ) contents ;
prepareImage = ''
export PATH = $ { pkgs . lib . makeSearchPathOutput " b i n " " b i n " prepareImageInputs }
mkdir $ out
diskImage = nixos . raw
truncate - s $ { toString diskSize } M $ diskImage
$ { if partitioned then ''
parted $ diskImage - - mklabel msdos mkpart primary ext4 1 M - 1 s
offset = $ ( ( 2048 * 512 ) )
'' e l s e ''
offset = 0
'' }
mkfs . ${ fsType } - F - L nixos - E offset = $ offset $ diskImage
root = " $ P W D / r o o t "
mkdir - p $ root
# Copy arbitrary other files into the image
# Semi-shamelessly copied from make-etc.sh. I (@copumpkin) shall factor this stuff out as part of
# https://github.com/NixOS/nixpkgs/issues/23052.
set - f
sources_ = ( $ { concatStringsSep " " sources } )
targets_ = ( $ { concatStringsSep " " targets } )
set + f
for ( ( i = 0 ; i < '' ${ #targets_[@]}; i++)); do
source = " ' ' ${ sources_ [ $ i ] } "
target = " ' ' ${ targets_ [ $ i ] } "
if [ [ " $ s o u r c e " = ~ ' * ' ] ] ; then
# If the source name contains '*', perform globbing.
mkdir - p $ root / $ target
for fn in $ source ; do
rsync - a - - no-o - - no-g " $ f n " $ root / $ target /
done
else
mkdir - p $ root / $ ( dirname $ target )
if ! [ - e $ root / $ target ] ; then
rsync - a - - no-o - - no-g $ source $ root / $ target
else
echo " d u p l i c a t e e n t r y $ t a r g e t - > $ s o u r c e "
exit 1
fi
fi
done
# TODO: Nix really likes to chown things it creates to its current user...
fakeroot nixos-prepare-root $ root $ { channelSources } $ { config . system . build . toplevel } closure
echo " c o p y i n g s t a g i n g r o o t t o i m a g e . . . "
cptofs $ { pkgs . lib . optionalString partitioned " - P 1 " } - t $ { fsType } - i $ diskImage $ root /* /
'' ;
in pkgs . vmTools . runInLinuxVM (
pkgs . runCommand name
{ preVM =
''
mkdir $ out
diskImage = $ out/nixos. $ { if format == " q c o w 2 " then " q c o w 2 " else " i m g " }
$ { pkgs . vmTools . qemu } /bin/qemu-img create - f $ { format } $ diskImage " ${ toString diskSize } M "
mv closure xchg /
'' ;
buildInputs = with pkgs ; [ utillinux perl e2fsprogs parted rsync ] ;
# I'm preserving the line below because I'm going to search for it across nixpkgs to consolidate
# image building logic. The comment right below this now appears in 4 different places in nixpkgs :)
# !!! should use XML.
sources = map ( x : x . source ) contents ;
targets = map ( x : x . target ) contents ;
exportReferencesGraph =
[ " c l o s u r e " config . system . build . toplevel ] ;
inherit postVM ;
{ preVM = prepareImage ;
buildInputs = with pkgs ; [ utillinux e2fsprogs ] ;
exportReferencesGraph = [ " c l o s u r e " metaClosure ] ;
postVM = ''
$ { if format == " r a w " then ''
mv $ diskImage $ out/nixos.img
diskImage = $ out/nixos.img
'' e l s e ''
$ { pkgs . qemu } /bin/qemu-img convert - f raw - O qcow2 $ diskImage $ out/nixos.qcow2
diskImage = $ out/nixos.qcow2
'' }
$ { postVM }
'' ;
memSize = 1024 ;
}
''
$ { if partitioned then ''
# Create a single / partition.
parted /dev/vda mklabel msdos
parted /dev/vda - - mkpart primary ext2 1 M - 1 s
. /sys/class/block/vda1/uevent
mknod /dev/vda1 b $ MAJOR $ MINOR
rootDisk = /dev/vda1
@ -76,74 +158,34 @@ pkgs.vmTools.runInLinuxVM (
rootDisk = /dev/vda
'' }
# Create an empty filesystem and mount it.
mkfs . ${ fsType } - L nixos $ rootDisk
mkdir /mnt
mount $ rootDisk /mnt
# Register the paths in the Nix database.
printRegistration = 1 perl $ { pkgs . pathsFromGraph } /tmp/xchg/closure | \
$ { config . nix . package . out } /bin/nix-store - - load-db - - option build-users-group " "
$ { if fixValidity then ''
# Add missing size/hash fields to the database. FIXME:
# exportReferencesGraph should provide these directly.
$ { config . nix . package . out } /bin/nix-store - - verify - - check-contents - - option build-users-group " "
'' e l s e " " }
# In case the bootloader tries to write to /dev/sda…
# Some tools assume these exist
ln - s vda /dev/xvda
ln - s vda /dev/sda
# Install the closure onto the image
USER = root $ { config . system . build . nixos-install } /bin/nixos-install \
- - closure $ { config . system . build . toplevel } \
- - no-channel-copy \
- - no-root-passwd \
$ { optionalString ( ! installBootLoader ) " - - n o - b o o t l o a d e r " }
mountPoint = /mnt
mkdir $ mountPoint
mount $ rootDisk $ mountPoint
# Install a configuration.nix.
# Install a configuration.nix
mkdir - p /mnt/etc/nixos
$ { optionalString ( configFile != null ) ''
cp $ { configFile } /mnt/etc/nixos/configuration.nix
'' }
# Remove /etc/machine-id so that each machine cloning this image will get its own id
rm - f /mnt/etc/machine-id
# Copy arbitrary other files into the image
# Semi-shamelessly copied from make-etc.sh. I (@copumpkin) shall factor this stuff out as part of
# https://github.com/NixOS/nixpkgs/issues/23052.
set - f
sources_ = ( $ sources )
targets_ = ( $ targets )
set + f
for ( ( i = 0 ; i < '' ${ #targets_[@]}; i++)); do
source = " ' ' ${ sources_ [ $ i ] } "
target = " ' ' ${ targets_ [ $ i ] } "
mount - - rbind /dev $ mountPoint/dev
mount - - rbind /proc $ mountPoint/proc
mount - - rbind /sys $ mountPoint/sys
if [ [ " $ s o u r c e " = ~ ' * ' ] ] ; then
# Set up core system link, GRUB, etc.
NIXOS_INSTALL_BOOTLOADER = 1 chroot $ mountPoint /nix/var/nix/profiles/system/bin/switch-to-configuration boot
# If the source name contains '*', perform globbing.
mkdir - p /mnt / $ target
for fn in $ source ; do
rsync - a - - no-o - - no-g " $ f n " /mnt / $ target /
done
# TODO: figure out if I should activate, but for now I won't
# chroot $mountPoint /nix/var/nix/profiles/system/activate
else
mkdir - p /mnt / $ ( dirname $ target )
if ! [ - e /mnt / $ target ] ; then
rsync - a - - no-o - - no-g $ source /mnt / $ target
else
echo " d u p l i c a t e e n t r y $ t a r g e t - > $ s o u r c e "
exit 1
fi
fi
done
# The above scripts will generate a random machine-id and we don't want to bake a single ID into all our images
rm - f $ mountPoint/etc/machine-id
umount /mnt
umount - R /mnt
# Make sure resize2fs works. Note that resize2fs has stricter criteria for resizing than a normal
# mount, so the `-c 0` and `-i 0` don't affect it. Setting it to `now` doesn't produce deterministic