From c1295661c4bc68d9120c834e2a456e8125e9fe18 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 13 Sep 2010 12:34:58 +0000 Subject: [PATCH] * Added a command `nixos-rebuild build-vm-with-bootloader'. This is like `build-vm', but boots using the regular boot loader (i.e. GRUB 1 or 2) rather than booting directly from the kernel/initrd. Thus it allows testing of GRUB. svn path=/nixos/trunk/; revision=23747 --- default.nix | 15 ++- doc/manual/man-nixos-rebuild.xml | 31 +++++++ modules/installer/tools/nixos-rebuild.sh | 9 +- .../activation/switch-to-configuration.sh | 2 +- modules/virtualisation/qemu-vm.nix | 92 +++++++++++++++++-- 5 files changed, 137 insertions(+), 12 deletions(-) diff --git a/default.nix b/default.nix index e63a76cd03f3..6b929537ee42 100644 --- a/default.nix +++ b/default.nix @@ -11,11 +11,22 @@ let inherit (eval) config pkgs; + # This is for `nixos-rebuild build-vm'. vmConfig = (import ./lib/eval-config.nix { inherit system; modules = [ configuration ./modules/virtualisation/qemu-vm.nix ]; }).config; - + + # This is for `nixos-rebuild build-vm-with-bootloader'. + vmWithBootLoaderConfig = (import ./lib/eval-config.nix { + inherit system; + modules = + [ configuration + ./modules/virtualisation/qemu-vm.nix + { virtualisation.useBootLoader = true; } + ]; + }).config; + in { @@ -25,6 +36,8 @@ in vm = vmConfig.system.build.vm; + vmWithBootLoader = vmWithBootLoaderConfig.system.build.vm; + # The following are used by nixos-rebuild. nixFallback = pkgs.nixUnstable; manifests = config.installer.manifests; diff --git a/doc/manual/man-nixos-rebuild.xml b/doc/manual/man-nixos-rebuild.xml index 0bdc925efd9e..6f888172d48a 100644 --- a/doc/manual/man-nixos-rebuild.xml +++ b/doc/manual/man-nixos-rebuild.xml @@ -24,6 +24,8 @@ + + @@ -151,6 +153,35 @@ $ ./result/bin/run-*-vm + + + + Like , but boots using the + regular boot loader of your configuration (e.g., GRUB 1 or 2), + rather than booting directly into the kernel and initial ramdisk + of the system. This allows you to test whether the boot loader + works correctly. However, it does not guarantee that your NixOS + configuration will boot successfully on the host hardware (i.e., + after running nixos-rebuild switch), because + the hardware and boot loader configuration in the VM are + different. The boot loader is installed on an automatically + generated virtual disk containing a /boot + partition, which is mounted read-only in the VM. + + + + + + + This operation merely fetches the latest manifest in the + Nixpkgs channel to speed up subsequent + nix-env operations. This is useful if you + are not using nix-channel but still want to + use pre-built binary packages. It doesn’t reconfigure the + system at all. + + + diff --git a/modules/installer/tools/nixos-rebuild.sh b/modules/installer/tools/nixos-rebuild.sh index 4d01ff53f890..41b74494337d 100644 --- a/modules/installer/tools/nixos-rebuild.sh +++ b/modules/installer/tools/nixos-rebuild.sh @@ -22,6 +22,8 @@ The operation is one of the following: activate it build-vm: build a virtual machine containing the configuration (useful for testing) + build-vm-with-bootloader: + like build-vm, but include a boot loader in the VM dry-run: just show what store paths would be built/downloaded pull: just pull the Nixpkgs channel manifest and exit @@ -64,7 +66,7 @@ while test "$#" -gt 0; do --help) showSyntax ;; - switch|boot|test|build|dry-run|build-vm|pull) + switch|boot|test|build|dry-run|build-vm|build-vm-with-bootloader|pull) action="$i" ;; --install-grub) @@ -171,9 +173,12 @@ if test -z "$rollback"; then elif test "$action" = test -o "$action" = build -o "$action" = dry-run; then nix-build $NIXOS -A system -K -k $extraBuildFlags > /dev/null pathToConfig=./result - elif test "$action" = build-vm; then + elif [ "$action" = build-vm ]; then nix-build $NIXOS -A vm -K -k $extraBuildFlags > /dev/null pathToConfig=./result + elif [ "$action" = build-vm-with-bootloader ]; then + nix-build $NIXOS -A vmWithBootLoader -K -k $extraBuildFlags > /dev/null + pathToConfig=./result else showSyntax fi diff --git a/modules/system/activation/switch-to-configuration.sh b/modules/system/activation/switch-to-configuration.sh index 6aec8225fdfc..ffc9845622c0 100644 --- a/modules/system/activation/switch-to-configuration.sh +++ b/modules/system/activation/switch-to-configuration.sh @@ -38,7 +38,7 @@ if [ "$action" = "switch" -o "$action" = "boot" ]; then if [ "$NIXOS_INSTALL_GRUB" = 1 -o "$oldGrubVersion" != "$newGrubVersion" ]; then echo "installing the GRUB bootloader..." - @grub@/sbin/grub-install "@grubDevice@" --no-floppy --recheck + @grub@/sbin/grub-install "@grubDevice@" --no-floppy echo "$newGrubVersion" > /boot/grub/version fi fi diff --git a/modules/virtualisation/qemu-vm.nix b/modules/virtualisation/qemu-vm.nix index fb4779c63a1e..bc36b32a778a 100644 --- a/modules/virtualisation/qemu-vm.nix +++ b/modules/virtualisation/qemu-vm.nix @@ -110,7 +110,24 @@ let example = "-vga std"; description = "Options passed to QEMU."; }; - + + virtualisation.useBootLoader = + mkOption { + default = true; + description = + '' + If enabled, the virtual machine will be booted using the + regular boot loader (i.e., GRUB 1 or 2). This allows + testing of the boot loader. However, it does not + guarantee that your NixOS configuration will boot + successfully on the host hardware, because the hardware + and boot loader configuration in the VM are different. If + disabled (the default), the VM directly boots the NixOS + kernel and initial ramdisk, bypassing the boot loader + altogether. + ''; + }; + }; cfg = config.virtualisation; @@ -146,12 +163,17 @@ let -net nic,vlan=0,model=virtio \ -chardev socket,id=samba,path=./samba \ -net user,vlan=0,guestfwd=tcp:10.0.2.4:139-chardev:samba''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS} \ - -drive file=$NIX_DISK_IMAGE,if=virtio,boot=on,cache=writeback,werror=report \ - -kernel ${config.system.build.toplevel}/kernel \ - -initrd ${config.system.build.toplevel}/initrd \ + ${if cfg.useBootLoader then '' + -drive index=0,file=$NIX_DISK_IMAGE,if=virtio,cache=writeback,werror=report \ + -drive index=1,file=${bootDisk}/disk.img,if=virtio,boot=on \ + '' else '' + -drive file=$NIX_DISK_IMAGE,if=virtio,boot=on,cache=writeback,werror=report \ + -kernel ${config.system.build.toplevel}/kernel \ + -initrd ${config.system.build.toplevel}/initrd \ + -append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.bootStage2} systemConfig=${config.system.build.toplevel} regInfo=${regInfo} ${kernelConsole} $QEMU_KERNEL_PARAMS" \ + ''} ${qemuGraphics} \ $QEMU_OPTS \ - -append "$(cat ${config.system.build.toplevel}/kernel-params) init=${config.system.build.bootStage2} systemConfig=${config.system.build.toplevel} regInfo=${regInfo} ${kernelConsole} $QEMU_KERNEL_PARAMS" \ ${config.virtualisation.qemu.options} ''; @@ -165,11 +187,54 @@ let printRegistration=1 perl ${pkgs.pathsFromGraph} closure-* > $out ''; + + # Generate a hard disk image containing a /boot partition and GRUB + # in the MBR. Used when the `useBootLoader' option is set. + bootDisk = + pkgs.vmTools.runInLinuxVM ( + pkgs.runCommand "nixos-boot-disk" + { preVM = + '' + mkdir $out + diskImage=$out/disk.img + ${pkgs.vmTools.kvm}/bin/qemu-img create -f qcow2 $diskImage "32M" + ''; + buildInputs = [ pkgs.utillinux ]; + } + '' + # Create a single /boot partition. + ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos + ${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s + . /sys/class/block/vda1/uevent + mknod /dev/vda1 b $MAJOR $MINOR + . /sys/class/block/vda/uevent + ${pkgs.e2fsprogs}/sbin/mkfs.ext3 -L boot /dev/vda1 + ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1 + + # Mount /boot. + mkdir /boot + mount /dev/vda1 /boot + + # This is needed for GRUB 0.97, which doesn't know about virtio devices. + mkdir /boot/grub + echo '(hd0) /dev/vda' > /boot/grub/device.map + + # Install GRUB and generate the GRUB boot menu. + touch /etc/NIXOS + mkdir -p /nix/var/nix/profiles + ${config.system.build.toplevel}/bin/switch-to-configuration boot + + umount /boot + '' + ); + in { require = options; + boot.loader.grub.device = mkOverride 50 "/dev/vda"; + # All the modules the initrd needs to mount the host filesystem via # CIFS. Also use paravirtualised network and block devices for # performance. @@ -207,6 +272,7 @@ in boot.initrd.postMountCommands = '' + mkdir -p $targetRoot/boot mount -o remount,ro $targetRoot/nix/store ${optionalString cfg.writableStore '' mkdir /mnt-store-tmpfs @@ -225,7 +291,9 @@ in boot.postBootCommands = '' ( source /proc/cmdline - ${config.environment.nix}/bin/nix-store --load-db < $regInfo + if [ -n "$regInfo" ]; then + ${config.environment.nix}/bin/nix-store --load-db < $regInfo + fi ) ''; @@ -237,7 +305,7 @@ in # where the regular value for the `fileSystems' attribute should be # disregarded for the purpose of building a VM test image (since # those filesystems don't exist in the VM). - fileSystems = mkOverride 50 + fileSystems = mkOverride 50 ( [ { mountPoint = "/"; device = "/dev/vda"; } @@ -253,7 +321,15 @@ in options = "bind"; neededForBoot = true; } - ]; + ] ++ optional cfg.useBootLoader + { mountPoint = "/boot"; + device = "/dev/disk/by-label/boot"; + fsType = "ext3"; + options = "ro"; + noCheck = true; # fsck fails on a r/o filesystem + }); + + swapDevices = mkOverride 50 [ ]; # Starting DHCP brings down eth0, which kills the connection to the # host filesystem and thus deadlocks the system.