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 <aszlig@redmoonstudios.org>
This commit is contained in:
aszlig 2014-12-13 11:15:48 +01:00
parent 34b0d860d5
commit 69858d7743
No known key found for this signature in database
GPG key ID: D0EBD0EC8C2DC961
2 changed files with 251 additions and 0 deletions

View file

@ -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 {};

250
nixos/tests/virtualbox.nix Normal file
View file

@ -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 <<GRUB
set root=hd0,1
linux /linux ${pkgs.lib.concatStringsSep " " cfg.boot.kernelParams}
initrd /initrd
boot
GRUB
umount /mnt
'');
in {
name = "virtualbox";
machine = { pkgs, ... }: {
imports = [ ./common/user-account.nix ./common/x11.nix ];
services.virtualboxHost.enable = true;
systemd.sockets.vboxtestlog = {
description = "VirtualBox Test Machine Log Socket";
wantedBy = [ "sockets.target" ];
before = [ "multi-user.target" ];
socketConfig.ListenStream = "/run/virtualbox-log.sock";
socketConfig.Accept = true;
};
systemd.services."vboxtestlog@" = {
description = "VirtualBox Test Machine Log";
serviceConfig.StandardInput = "socket";
serviceConfig.StandardOutput = "syslog";
serviceConfig.SyslogIdentifier = "testvm";
serviceConfig.ExecStart = "${pkgs.coreutils}/bin/cat";
};
};
testScript = let
mkFlags = pkgs.lib.concatStringsSep " ";
createFlags = mkFlags [
"--ostype Linux26"
"--register"
];
vmFlags = mkFlags [
"--uart1 0x3F8 4"
"--uartmode1 client /run/virtualbox-log.sock"
];
controllerFlags = mkFlags [
"--name SATA"
"--add sata"
"--bootable on"
"--hostiocache on"
];
diskFlags = mkFlags [
"--storagectl SATA"
"--port 0"
"--device 0"
"--type hdd"
"--mtype immutable"
"--medium ${testVM}/disk.vdi"
];
sharedFlags = mkFlags [
"--name vboxshare"
"--hostpath /home/alice/vboxshare"
];
in ''
sub ru {
return "su - alice -c '$_[0]'";
}
sub waitForVMBoot {
$machine->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'");
'';
})