From 69858d7743293d8f94b3d3160c9c3401722e4c10 Mon Sep 17 00:00:00 2001 From: aszlig Date: Sat, 13 Dec 2014 11:15:48 +0100 Subject: [PATCH] nixos: Add VM test for VirtualBox. Currently it pretty much tests starting up virtual machines and just shutting down afterwards, but for both VBoxManage and the VirtualBox GUI. This helps catching errors in hardened mode, however we still need to test whether networking works the way intended (and I fear that this is broken at the moment). The VirtualBox VM is _not_ using hardware virtualization support (thus we use system = "i686-linux", because x86_64 has no emulation support), because we're already within a qemu VM, which means it's going to be slow as hell (that's why I've written own subs just for testing startup/shutdown/whatnot with respective timeouts). Signed-off-by: aszlig --- nixos/release.nix | 1 + nixos/tests/virtualbox.nix | 250 +++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 nixos/tests/virtualbox.nix diff --git a/nixos/release.nix b/nixos/release.nix index 12dd81f89707..0694c52a4300 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -306,6 +306,7 @@ in rec { tests.simple = callTest tests/simple.nix {}; tests.tomcat = callTest tests/tomcat.nix {}; tests.udisks2 = callTest tests/udisks2.nix {}; + tests.virtualbox = callTest tests/virtualbox.nix {}; tests.xfce = callTest tests/xfce.nix {}; diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix new file mode 100644 index 000000000000..c8912760f3d6 --- /dev/null +++ b/nixos/tests/virtualbox.nix @@ -0,0 +1,250 @@ +import ./make-test.nix ({ pkgs, ... }: let + + testVMConfig = { config, pkgs, ... }: { + boot.kernelParams = [ + "console=tty0" "console=ttyS0" "ignore_loglevel" + "boot.trace" "panic=1" "boot.panic_on_fail" + ]; + + fileSystems."/" = { + device = "vboxshare"; + fsType = "vboxsf"; + }; + + services.virtualboxGuest.enable = true; + + boot.initrd.kernelModules = [ "vboxsf" ]; + + boot.initrd.extraUtilsCommands = '' + cp -av -t "$out/bin/" \ + "${pkgs.linuxPackages.virtualboxGuestAdditions}/sbin/mount.vboxsf" + ''; + + boot.initrd.postMountCommands = '' + touch /mnt-root/boot-done + + i=0 + while [ ! -e /mnt-root/shutdown ]; do + sleep 10 + i=$(($i + 10)) + [ $i -le 120 ] || fail + done + + rm -f /mnt-root/boot-done /mnt-root/shutdown + poweroff -f + ''; + + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isYes "SERIAL_8250_CONSOLE") + (isYes "SERIAL_8250") + ]; + }; + + testVM = let + cfg = (import ../lib/eval-config.nix { + system = "i686-linux"; + modules = [ + ../modules/profiles/minimal.nix + testVMConfig + ]; + }).config; + in pkgs.vmTools.runInLinuxVM (pkgs.runCommand "virtualbox-image" { + preVM = '' + mkdir -p "$out" + diskImage="$(pwd)/qimage" + ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw "$diskImage" 100M + ''; + + postVM = '' + echo "creating VirtualBox disk image..." + ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vdi \ + "$diskImage" "$out/disk.vdi" + ''; + + buildInputs = [ pkgs.utillinux pkgs.perl ]; + } '' + ${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 + + ${pkgs.e2fsprogs}/sbin/mkfs.ext4 /dev/vda1 + ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1 + mkdir /mnt + mount /dev/vda1 /mnt + cp "${cfg.system.build.kernel}/bzImage" /mnt/linux + cp "${cfg.system.build.initialRamdisk}/initrd" /mnt/initrd + + ${pkgs.grub2}/bin/grub-install --boot-directory=/mnt /dev/vda + + cat > /mnt/grub/grub.cfg <execute(ru( + 'set -e; i=0; '. + 'while ! test -e /home/alice/vboxshare/boot-done; do '. + 'sleep 10; i=$(($i + 10)); [ $i -le 3600 ]; '. + 'VBoxManage list runningvms | grep -qF test; '. + 'done' + )); + } + + sub checkRunning { + my $checkrunning = ru "VBoxManage list runningvms | grep -qF test"; + my ($status, $out) = $machine->execute($checkrunning); + return $status == 0; + } + + sub waitForStartup { + for (my $i = 0; $i <= 120; $i += 10) { + $machine->sleep(10); + return if checkRunning; + } + die "VirtualBox VM didn't start up within 2 minutes"; + } + + sub waitForShutdown { + for (my $i = 0; $i <= 120; $i += 10) { + $machine->sleep(10); + return unless checkRunning; + } + die "VirtualBox VM didn't shut down within 2 minutes"; + } + + sub shutdownVM { + $machine->succeed(ru "touch /home/alice/vboxshare/shutdown"); + $machine->waitUntilSucceeds( + "test ! -e /home/alice/vboxshare/shutdown ". + " -a ! -e /home/alice/vboxshare/boot-done" + ); + waitForShutdown; + } + + sub cleanup { + $machine->execute(ru "VBoxManage controlvm test poweroff") + if checkRunning; + $machine->succeed("rm -rf /home/alice/vboxshare"); + $machine->succeed("mkdir -p /home/alice/vboxshare"); + $machine->succeed("chown alice.users /home/alice/vboxshare"); + } + + $machine->waitForX; + + $machine->succeed(ru "VBoxManage createvm --name test ${createFlags}"); + $machine->succeed(ru "VBoxManage modifyvm test ${vmFlags}"); + + $machine->fail("test -e '/root/VirtualBox VMs'"); + $machine->succeed("test -e '/home/alice/VirtualBox VMs'"); + + $machine->succeed(ru "VBoxManage storagectl test ${controllerFlags}"); + $machine->succeed(ru "VBoxManage storageattach test ${diskFlags}"); + + $machine->succeed(ru "VBoxManage sharedfolder add test ${sharedFlags}"); + + $machine->succeed(ru "VBoxManage showvminfo test >&2"); + + cleanup; + + subtest "virtualbox-gui", sub { + $machine->succeed(ru "VirtualBox &"); + $machine->waitForWindow(qr/Oracle VM VirtualBox Manager/); + $machine->sleep(5); + $machine->screenshot("gui_manager_started"); + $machine->sendKeys("ret"); + $machine->screenshot("gui_manager_sent_startup"); + waitForStartup; + $machine->screenshot("gui_started"); + waitForVMBoot; + $machine->screenshot("gui_booted"); + shutdownVM; + $machine->sleep(5); + $machine->screenshot("gui_stopped"); + $machine->sendKeys("ctrl-q"); + $machine->sleep(5); + $machine->screenshot("gui_manager_stopped"); + }; + + cleanup; + + subtest "virtualbox-cli", sub { + $machine->succeed(ru "VBoxManage startvm test"); + waitForStartup; + $machine->screenshot("cli_started"); + waitForVMBoot; + $machine->screenshot("cli_booted"); + shutdownVM; + }; + + $machine->fail("test -e '/root/VirtualBox VMs'"); + $machine->succeed("test -e '/home/alice/VirtualBox VMs'"); + ''; +})