aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/tests/virtualbox.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/tests/virtualbox.nix')
-rw-r--r--nixpkgs/nixos/tests/virtualbox.nix419
1 files changed, 215 insertions, 204 deletions
diff --git a/nixpkgs/nixos/tests/virtualbox.nix b/nixpkgs/nixos/tests/virtualbox.nix
index aec8da6a2af..0d9eafa4a20 100644
--- a/nixpkgs/nixos/tests/virtualbox.nix
+++ b/nixpkgs/nixos/tests/virtualbox.nix
@@ -15,7 +15,7 @@
assert use64bitGuest -> useKvmNestedVirt;
-with import ../lib/testing.nix { inherit system pkgs; };
+with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
let
@@ -91,13 +91,15 @@ let
(isYes "SERIAL_8250_CONSOLE")
(isYes "SERIAL_8250")
];
+
+ networking.usePredictableInterfaceNames = false;
};
mkLog = logfile: tag: let
rotated = map (i: "${logfile}.${toString i}") (range 1 9);
all = concatMapStringsSep " " (f: "\"${f}\"") ([logfile] ++ rotated);
logcmd = "tail -F ${all} 2> /dev/null | logger -t \"${tag}\"";
- in optionalString debug "$machine->execute(ru '${logcmd} & disown');";
+ in if debug then "machine.execute(ru('${logcmd} & disown'))" else "pass";
testVM = vmName: vmScript: let
cfg = (import ../lib/eval-config.nix {
@@ -198,103 +200,111 @@ let
systemd.services."vboxtestlog-${name}@" = {
description = "VirtualBox Test Machine Log For ${name}";
serviceConfig.StandardInput = "socket";
- serviceConfig.StandardOutput = "syslog";
serviceConfig.SyslogIdentifier = "GUEST-${name}";
serviceConfig.ExecStart = "${pkgs.coreutils}/bin/cat";
};
};
testSubs = ''
- my ${"$" + name}_sharepath = '${sharePath}';
-
- sub checkRunning_${name} {
- my $cmd = 'VBoxManage list runningvms | grep -q "^\"${name}\""';
- my ($status, $out) = $machine->execute(ru $cmd);
- return $status == 0;
- }
-
- sub cleanup_${name} {
- $machine->execute(ru "VBoxManage controlvm ${name} poweroff")
- if checkRunning_${name};
- $machine->succeed("rm -rf ${sharePath}");
- $machine->succeed("mkdir -p ${sharePath}");
- $machine->succeed("chown alice.users ${sharePath}");
- }
-
- sub createVM_${name} {
- vbm("createvm --name ${name} ${createFlags}");
- vbm("modifyvm ${name} ${vmFlags}");
- vbm("setextradata ${name} VBoxInternal/PDM/HaltOnReset 1");
- vbm("storagectl ${name} ${controllerFlags}");
- vbm("storageattach ${name} ${diskFlags}");
- vbm("sharedfolder add ${name} ${sharedFlags}");
- vbm("sharedfolder add ${name} ${nixstoreFlags}");
- cleanup_${name};
-
- ${mkLog "$HOME/VirtualBox VMs/${name}/Logs/VBox.log" "HOST-${name}"}
- }
-
- sub destroyVM_${name} {
- cleanup_${name};
- vbm("unregistervm ${name} --delete");
- }
-
- sub waitForVMBoot_${name} {
- $machine->execute(ru(
- 'set -e; i=0; '.
- 'while ! test -e ${sharePath}/boot-done; do '.
- 'sleep 10; i=$(($i + 10)); [ $i -le 3600 ]; '.
- 'VBoxManage list runningvms | grep -q "^\"${name}\""; '.
- 'done'
- ));
- }
-
- sub waitForIP_${name} ($) {
- my $property = "/VirtualBox/GuestInfo/Net/$_[0]/V4/IP";
- my $getip = "VBoxManage guestproperty get ${name} $property | ".
- "sed -n -e 's/^Value: //p'";
- my $ip = $machine->succeed(ru(
- 'for i in $(seq 1000); do '.
- 'if ipaddr="$('.$getip.')" && [ -n "$ipaddr" ]; then '.
- 'echo "$ipaddr"; exit 0; '.
- 'fi; '.
- 'sleep 1; '.
- 'done; '.
- 'echo "Could not get IPv4 address for ${name}!" >&2; '.
- 'exit 1'
- ));
- chomp $ip;
- return $ip;
- }
-
- sub waitForStartup_${name} {
- for (my $i = 0; $i <= 120; $i += 10) {
- $machine->sleep(10);
- return if checkRunning_${name};
- eval { $_[0]->() } if defined $_[0];
- }
- die "VirtualBox VM didn't start up within 2 minutes";
- }
-
- sub waitForShutdown_${name} {
- for (my $i = 0; $i <= 120; $i += 10) {
- $machine->sleep(10);
- return unless checkRunning_${name};
- }
- die "VirtualBox VM didn't shut down within 2 minutes";
- }
-
- sub shutdownVM_${name} {
- $machine->succeed(ru "touch ${sharePath}/shutdown");
- $machine->execute(
- 'set -e; i=0; '.
- 'while test -e ${sharePath}/shutdown '.
- ' -o -e ${sharePath}/boot-done; do '.
- 'sleep 1; i=$(($i + 1)); [ $i -le 3600 ]; '.
- 'done'
- );
- waitForShutdown_${name};
- }
+
+
+ ${name}_sharepath = "${sharePath}"
+
+
+ def check_running_${name}():
+ cmd = "VBoxManage list runningvms | grep -q '^\"${name}\"'"
+ (status, _) = machine.execute(ru(cmd))
+ return status == 0
+
+
+ def cleanup_${name}():
+ if check_running_${name}():
+ machine.execute(ru("VBoxManage controlvm ${name} poweroff"))
+ machine.succeed("rm -rf ${sharePath}")
+ machine.succeed("mkdir -p ${sharePath}")
+ machine.succeed("chown alice.users ${sharePath}")
+
+
+ def create_vm_${name}():
+ # fmt: off
+ vbm(f"createvm --name ${name} ${createFlags}")
+ vbm(f"modifyvm ${name} ${vmFlags}")
+ vbm(f"setextradata ${name} VBoxInternal/PDM/HaltOnReset 1")
+ vbm(f"storagectl ${name} ${controllerFlags}")
+ vbm(f"storageattach ${name} ${diskFlags}")
+ vbm(f"sharedfolder add ${name} ${sharedFlags}")
+ vbm(f"sharedfolder add ${name} ${nixstoreFlags}")
+ cleanup_${name}()
+
+ ${mkLog "$HOME/VirtualBox VMs/${name}/Logs/VBox.log" "HOST-${name}"}
+ # fmt: on
+
+
+ def destroy_vm_${name}():
+ cleanup_${name}()
+ vbm("unregistervm ${name} --delete")
+
+
+ def wait_for_vm_boot_${name}():
+ machine.execute(
+ ru(
+ "set -e; i=0; "
+ "while ! test -e ${sharePath}/boot-done; do "
+ "sleep 10; i=$(($i + 10)); [ $i -le 3600 ]; "
+ "VBoxManage list runningvms | grep -q '^\"${name}\"'; "
+ "done"
+ )
+ )
+
+
+ def wait_for_ip_${name}(interface):
+ property = f"/VirtualBox/GuestInfo/Net/{interface}/V4/IP"
+ # fmt: off
+ getip = f"VBoxManage guestproperty get ${name} {property} | sed -n -e 's/^Value: //p'"
+ # fmt: on
+
+ ip = machine.succeed(
+ ru(
+ "for i in $(seq 1000); do "
+ f'if ipaddr="$({getip})" && [ -n "$ipaddr" ]; then '
+ 'echo "$ipaddr"; exit 0; '
+ "fi; "
+ "sleep 1; "
+ "done; "
+ "echo 'Could not get IPv4 address for ${name}!' >&2; "
+ "exit 1"
+ )
+ ).strip()
+ return ip
+
+
+ def wait_for_startup_${name}(nudge=lambda: None):
+ for _ in range(0, 130, 10):
+ machine.sleep(10)
+ if check_running_${name}():
+ return
+ nudge()
+ raise Exception("VirtualBox VM didn't start up within 2 minutes")
+
+
+ def wait_for_shutdown_${name}():
+ for _ in range(0, 130, 10):
+ machine.sleep(10)
+ if not check_running_${name}():
+ return
+ raise Exception("VirtualBox VM didn't shut down within 2 minutes")
+
+
+ def shutdown_vm_${name}():
+ machine.succeed(ru("touch ${sharePath}/shutdown"))
+ machine.execute(
+ "set -e; i=0; "
+ "while test -e ${sharePath}/shutdown "
+ " -o -e ${sharePath}/boot-done; do "
+ "sleep 1; i=$(($i + 1)); [ $i -le 3600 ]; "
+ "done"
+ )
+ wait_for_shutdown_${name}()
'';
};
@@ -365,26 +375,31 @@ let
};
testScript = ''
- sub ru ($) {
- my $esc = $_[0] =~ s/'/'\\${"'"}'/gr;
- return "su - alice -c '$esc'";
- }
+ from shlex import quote
+ ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vms)}
- sub vbm {
- $machine->succeed(ru("VBoxManage ".$_[0]));
- };
+ def ru(cmd: str) -> str:
+ return f"su - alice -c {quote(cmd)}"
- sub removeUUIDs {
- return join("\n", grep { $_ !~ /^UUID:/ } split(/\n/, $_[0]))."\n";
- }
- ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vms)}
+ def vbm(cmd: str) -> str:
+ return machine.succeed(ru(f"VBoxManage {cmd}"))
+
+
+ def remove_uuids(output: str) -> str:
+ return "\n".join(
+ [line for line in (output or "").splitlines() if not line.startswith("UUID:")]
+ )
+
- $machine->waitForX;
+ machine.wait_for_x()
+ # fmt: off
${mkLog "$HOME/.config/VirtualBox/VBoxSVC.log" "HOST-SVC"}
+ # fmt: on
${testScript}
+ # (keep black happy)
'';
meta = with pkgs.stdenv.lib.maintainers; {
@@ -394,133 +409,129 @@ let
unfreeTests = mapAttrs (mkVBoxTest true vboxVMsWithExtpack) {
enable-extension-pack = ''
- createVM_testExtensionPack;
- vbm("startvm testExtensionPack");
- waitForStartup_testExtensionPack;
- $machine->screenshot("cli_started");
- waitForVMBoot_testExtensionPack;
- $machine->screenshot("cli_booted");
-
- $machine->nest("Checking for privilege escalation", sub {
- $machine->fail("test -e '/root/VirtualBox VMs'");
- $machine->fail("test -e '/root/.config/VirtualBox'");
- $machine->succeed("test -e '/home/alice/VirtualBox VMs'");
- });
-
- shutdownVM_testExtensionPack;
- destroyVM_testExtensionPack;
+ create_vm_testExtensionPack()
+ vbm("startvm testExtensionPack")
+ wait_for_startup_testExtensionPack()
+ machine.screenshot("cli_started")
+ wait_for_vm_boot_testExtensionPack()
+ machine.screenshot("cli_booted")
+
+ with machine.nested("Checking for privilege escalation"):
+ machine.fail("test -e '/root/VirtualBox VMs'")
+ machine.fail("test -e '/root/.config/VirtualBox'")
+ machine.succeed("test -e '/home/alice/VirtualBox VMs'")
+
+ shutdown_vm_testExtensionPack()
+ destroy_vm_testExtensionPack()
'';
};
in mapAttrs (mkVBoxTest false vboxVMs) {
simple-gui = ''
- createVM_simple;
- $machine->succeed(ru "VirtualBox &");
- $machine->waitUntilSucceeds(
- ru "xprop -name 'Oracle VM VirtualBox Manager'"
- );
- $machine->sleep(5);
- $machine->screenshot("gui_manager_started");
# Home to select Tools, down to move to the VM, enter to start it.
- $machine->sendKeys("home");
- $machine->sendKeys("down");
- $machine->sendKeys("ret");
- $machine->screenshot("gui_manager_sent_startup");
- waitForStartup_simple (sub {
- $machine->sendKeys("home");
- $machine->sendKeys("down");
- $machine->sendKeys("ret");
- });
- $machine->screenshot("gui_started");
- waitForVMBoot_simple;
- $machine->screenshot("gui_booted");
- shutdownVM_simple;
- $machine->sleep(5);
- $machine->screenshot("gui_stopped");
- $machine->sendKeys("ctrl-q");
- $machine->sleep(5);
- $machine->screenshot("gui_manager_stopped");
- destroyVM_simple;
+ def send_vm_startup():
+ machine.send_key("home")
+ machine.send_key("down")
+ machine.send_key("ret")
+
+
+ create_vm_simple()
+ machine.succeed(ru("VirtualBox &"))
+ machine.wait_until_succeeds(ru("xprop -name 'Oracle VM VirtualBox Manager'"))
+ machine.sleep(5)
+ machine.screenshot("gui_manager_started")
+ send_vm_startup()
+ machine.screenshot("gui_manager_sent_startup")
+ wait_for_startup_simple(send_vm_startup)
+ machine.screenshot("gui_started")
+ wait_for_vm_boot_simple()
+ machine.screenshot("gui_booted")
+ shutdown_vm_simple()
+ machine.sleep(5)
+ machine.screenshot("gui_stopped")
+ machine.send_key("ctrl-q")
+ machine.sleep(5)
+ machine.screenshot("gui_manager_stopped")
+ destroy_vm_simple()
'';
simple-cli = ''
- createVM_simple;
- vbm("startvm simple");
- waitForStartup_simple;
- $machine->screenshot("cli_started");
- waitForVMBoot_simple;
- $machine->screenshot("cli_booted");
-
- $machine->nest("Checking for privilege escalation", sub {
- $machine->fail("test -e '/root/VirtualBox VMs'");
- $machine->fail("test -e '/root/.config/VirtualBox'");
- $machine->succeed("test -e '/home/alice/VirtualBox VMs'");
- });
-
- shutdownVM_simple;
- destroyVM_simple;
+ create_vm_simple()
+ vbm("startvm simple")
+ wait_for_startup_simple()
+ machine.screenshot("cli_started")
+ wait_for_vm_boot_simple()
+ machine.screenshot("cli_booted")
+
+ with machine.nested("Checking for privilege escalation"):
+ machine.fail("test -e '/root/VirtualBox VMs'")
+ machine.fail("test -e '/root/.config/VirtualBox'")
+ machine.succeed("test -e '/home/alice/VirtualBox VMs'")
+
+ shutdown_vm_simple()
+ destroy_vm_simple()
'';
headless = ''
- createVM_headless;
- $machine->succeed(ru("VBoxHeadless --startvm headless & disown %1"));
- waitForStartup_headless;
- waitForVMBoot_headless;
- shutdownVM_headless;
- destroyVM_headless;
+ create_vm_headless()
+ machine.succeed(ru("VBoxHeadless --startvm headless & disown %1"))
+ wait_for_startup_headless()
+ wait_for_vm_boot_headless()
+ shutdown_vm_headless()
+ destroy_vm_headless()
'';
host-usb-permissions = ''
- my $userUSB = removeUUIDs vbm("list usbhost");
- print STDERR $userUSB;
- my $rootUSB = removeUUIDs $machine->succeed("VBoxManage list usbhost");
- print STDERR $rootUSB;
-
- die "USB host devices differ for root and normal user"
- if $userUSB ne $rootUSB;
- die "No USB host devices found" if $userUSB =~ /<none>/;
+ user_usb = remove_uuids(vbm("list usbhost"))
+ print(user_usb, file=sys.stderr)
+ root_usb = remove_uuids(machine.succeed("VBoxManage list usbhost"))
+ print(root_usb, file=sys.stderr)
+
+ if user_usb != root_usb:
+ raise Exception("USB host devices differ for root and normal user")
+ if "<none>" in user_usb:
+ raise Exception("No USB host devices found")
'';
systemd-detect-virt = ''
- createVM_detectvirt;
- vbm("startvm detectvirt");
- waitForStartup_detectvirt;
- waitForVMBoot_detectvirt;
- shutdownVM_detectvirt;
- my $result = $machine->succeed("cat '$detectvirt_sharepath/result'");
- chomp $result;
- destroyVM_detectvirt;
- die "systemd-detect-virt returned \"$result\" instead of \"oracle\""
- if $result ne "oracle";
+ create_vm_detectvirt()
+ vbm("startvm detectvirt")
+ wait_for_startup_detectvirt()
+ wait_for_vm_boot_detectvirt()
+ shutdown_vm_detectvirt()
+ result = machine.succeed(f"cat '{detectvirt_sharepath}/result'").strip()
+ destroy_vm_detectvirt()
+ if result != "oracle":
+ raise Exception(f'systemd-detect-virt returned "{result}" instead of "oracle"')
'';
net-hostonlyif = ''
- createVM_test1;
- createVM_test2;
+ create_vm_test1()
+ create_vm_test2()
- vbm("startvm test1");
- waitForStartup_test1;
- waitForVMBoot_test1;
+ vbm("startvm test1")
+ wait_for_startup_test1()
+ wait_for_vm_boot_test1()
- vbm("startvm test2");
- waitForStartup_test2;
- waitForVMBoot_test2;
+ vbm("startvm test2")
+ wait_for_startup_test2()
+ wait_for_vm_boot_test2()
- $machine->screenshot("net_booted");
+ machine.screenshot("net_booted")
- my $test1IP = waitForIP_test1 1;
- my $test2IP = waitForIP_test2 1;
+ test1_ip = wait_for_ip_test1(1)
+ test2_ip = wait_for_ip_test2(1)
- $machine->succeed("echo '$test2IP' | nc -N '$test1IP' 1234");
- $machine->succeed("echo '$test1IP' | nc -N '$test2IP' 1234");
+ machine.succeed(f"echo '{test2_ip}' | nc -N '{test1_ip}' 1234")
+ machine.succeed(f"echo '{test1_ip}' | nc -N '{test2_ip}' 1234")
- $machine->waitUntilSucceeds("nc -N '$test1IP' 5678 < /dev/null >&2");
- $machine->waitUntilSucceeds("nc -N '$test2IP' 5678 < /dev/null >&2");
+ machine.wait_until_succeeds(f"nc -N '{test1_ip}' 5678 < /dev/null >&2")
+ machine.wait_until_succeeds(f"nc -N '{test2_ip}' 5678 < /dev/null >&2")
- shutdownVM_test1;
- shutdownVM_test2;
+ shutdown_vm_test1()
+ shutdown_vm_test2()
- destroyVM_test1;
- destroyVM_test2;
+ destroy_vm_test1()
+ destroy_vm_test2()
'';
} // (if enableUnfree then unfreeTests else {})