Something went wrong. Try again.
What happens if I push all of nixpkgs
Something went wrong. Try again.
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617{ system ? builtins.currentSystem, config ? { }, pkgs ? import ../.. { inherit system config; }, debug ? false, enableUnfree ? false, enableKvm ? false, use64bitGuest ? true,}:
with import ../lib/testing-python.nix { inherit system pkgs; };with pkgs.lib;
let testVMConfig = vmName: attrs: { config, pkgs, lib, ... }: let guestAdditions = pkgs.linuxPackages.virtualboxGuestAdditions;
miniInit = '' #!${pkgs.runtimeShell} -xe export PATH="${ lib.makeBinPath [ pkgs.coreutils pkgs.util-linux ] }"
mkdir -p /run/dbus /var ln -s /run /var cat > /etc/passwd <<EOF root:x:0:0::/root:/bin/false messagebus:x:1:1::/run/dbus:/bin/false EOF cat > /etc/group <<EOF root:x:0: messagebus:x:1: EOF
"${pkgs.dbus}/bin/dbus-daemon" --fork \ --config-file="${pkgs.dbus}/share/dbus-1/system.conf"
${guestAdditions}/bin/VBoxService ${(attrs.vmScript or (const "")) pkgs}
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 ''; in { boot.kernelParams = [ "console=tty0" "console=ttyS0" "ignore_loglevel" "boot.trace" "panic=1" "boot.panic_on_fail" "init=${pkgs.writeScript "mini-init.sh" miniInit}" ];
fileSystems."/" = { device = "vboxshare"; fsType = "vboxsf"; };
virtualisation.virtualbox.guest.enable = true;
boot.initrd.kernelModules = [ "af_packet" "vboxsf" "virtio" "virtio_pci" "virtio_ring" "virtio_net" "vboxguest" ];
boot.initrd.extraUtilsCommands = '' copy_bin_and_libs "${guestAdditions}/bin/mount.vboxsf" copy_bin_and_libs "${pkgs.util-linux}/bin/unshare" ${(attrs.extraUtilsCommands or (const "")) pkgs} '';
boot.initrd.postMountCommands = '' touch /mnt-root/boot-done hostname "${vmName}" mkdir -p /nix/store unshare -m ${escapeShellArg pkgs.runtimeShell} -c ' mount -t vboxsf nixstore /nix/store exec "$stage2Init" ' poweroff -f '';
system.requiredKernelConfig = with config.lib.kernelConfig; [ (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 if debug then "machine.execute(ru('${logcmd} & disown'))" else "pass";
testVM = vmName: vmScript: let cfg = (import ../lib/eval-config.nix { system = if use64bitGuest then "x86_64-linux" else "i686-linux"; modules = [ (testVMConfig vmName vmScript) ]; }).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.util-linux pkgs.perl ]; } '' ${pkgs.parted}/sbin/parted --script /dev/vda mklabel msdos ${pkgs.parted}/sbin/parted --script /dev/vda -- mkpart primary ext2 1M -1s ${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 ${concatStringsSep " " cfg.boot.kernelParams} initrd /initrd boot GRUB umount /mnt '' );
createVM = name: attrs: let mkFlags = concatStringsSep " ";
sharePath = "/home/alice/vboxshare-${name}";
createFlags = mkFlags [ "--ostype ${if use64bitGuest then "Linux26_64" else "Linux26"}" "--register" ];
vmFlags = mkFlags ( [ "--uart1 0x3F8 4" "--uartmode1 client /run/virtualbox-log-${name}.sock" "--memory 768" "--audio none" ] ++ (attrs.vmFlags or [ ]) );
controllerFlags = mkFlags [ "--name SATA" "--add sata" "--bootable on" "--hostiocache on" ];
diskFlags = mkFlags [ "--storagectl SATA" "--port 0" "--device 0" "--type hdd" "--mtype immutable" "--medium ${testVM name attrs}/disk.vdi" ];
sharedFlags = mkFlags [ "--name vboxshare" "--hostpath ${sharePath}" ];
nixstoreFlags = mkFlags [ "--name nixstore" "--hostpath /nix/store" "--readonly" ]; in { machine = { systemd.sockets."vboxtestlog-${name}" = { description = "VirtualBox Test Machine Log Socket For ${name}"; wantedBy = [ "sockets.target" ]; before = [ "multi-user.target" ]; socketConfig.ListenStream = "/run/virtualbox-log-${name}.sock"; socketConfig.Accept = true; };
systemd.services."vboxtestlog-${name}@" = { description = "VirtualBox Test Machine Log For ${name}"; serviceConfig.StandardInput = "socket"; serviceConfig.StandardOutput = "journal"; serviceConfig.SyslogIdentifier = "GUEST-${name}"; serviceConfig.ExecStart = "${pkgs.coreutils}/bin/cat"; }; };
testSubs = ''
${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}(): cleanup_${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}")
${mkLog "$HOME/VirtualBox VMs/${name}/Logs/VBox.log" "HOST-${name}"}
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" getip = f"VBoxManage guestproperty get ${name} {property} | sed -n -e 's/^Value: //p'"
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}() ''; };
hostonlyVMFlags = [ "--nictype1 virtio" "--nictype2 virtio" "--nic2 hostonly" "--hostonlyadapter2 vboxnet0" ];
# The VirtualBox Oracle Extension Pack lets you use USB 3.0 (xHCI). enableExtensionPackVMFlags = [ "--usbxhci on" ];
dhcpScript = pkgs: '' ${pkgs.dhcpcd}/bin/dhcpcd eth0 eth1
otherIP="$(${pkgs.netcat}/bin/nc -l 1234 || :)" ${pkgs.iputils}/bin/ping -I eth1 -c1 "$otherIP" echo "$otherIP reachable" | ${pkgs.netcat}/bin/nc -l 5678 || : '';
sysdDetectVirt = pkgs: '' ${pkgs.systemd}/bin/systemd-detect-virt > /mnt-root/result '';
vboxVMs = mapAttrs createVM { simple = { };
detectvirt.vmScript = sysdDetectVirt;
test1.vmFlags = hostonlyVMFlags; test1.vmScript = dhcpScript;
test2.vmFlags = hostonlyVMFlags; test2.vmScript = dhcpScript;
headless.virtualisation.virtualbox.headless = true; headless.services.xserver.enable = false; };
vboxVMsWithExtpack = mapAttrs createVM { testExtensionPack.vmFlags = enableExtensionPackVMFlags; };
mkVBoxTest = vboxHostConfig: vms: name: testScript: makeTest { name = "virtualbox-${name}";
nodes.machine = { lib, config, ... }: { imports = let mkVMConf = name: val: val.machine // { key = "${name}-config"; }; vmConfigs = mapAttrsToList mkVMConf vms; in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs; virtualisation.memorySize = 2048;
virtualisation.qemu.options = let # IvyBridge is reasonably ancient to be compatible with recent # Intel/AMD hosts and sufficient for the KVM flavor. guestCpu = if config.virtualisation.virtualbox.host.enableKvm then "IvyBridge" else "kvm64"; in [ "-cpu" "${guestCpu},svm=on,vmx=on" ];
test-support.displayManager.auto.user = "alice"; users.users.alice.extraGroups = let inherit (config.virtualisation.virtualbox.host) enableHardening; in lib.mkIf enableHardening [ "vboxusers" ];
virtualisation.virtualbox.host = { enable = true; } // vboxHostConfig;
nixpkgs.config.allowUnfree = config.virtualisation.virtualbox.host.enableExtensionPack; };
testScript = '' from shlex import quote ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vms)}
def ru(cmd: str) -> str: return f"su - alice -c {quote(cmd)}"
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.wait_for_x()
${mkLog "$HOME/.config/VirtualBox/VBoxSVC.log" "HOST-SVC"}
${testScript} # (keep black happy) '';
meta = with pkgs.lib.maintainers; { maintainers = [ aszlig ]; }; };
unfreeTests = mapAttrs (mkVBoxTest { enableExtensionPack = true; } vboxVMsWithExtpack) { enable-extension-pack = '' 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() ''; };
kvmTests = mapAttrs (mkVBoxTest { enableKvm = true;
# Once the KVM version supports these, we can enable them. addNetworkInterface = false; enableHardening = false; } vboxVMs) { kvm-headless = '' create_vm_headless() machine.succeed(ru("VBoxHeadless --startvm headless >&2 & disown %1")) wait_for_startup_headless() wait_for_vm_boot_headless() shutdown_vm_headless() destroy_vm_headless() ''; };
inmapAttrs (mkVBoxTest { } vboxVMs) { simple-gui = '' # Home to select Tools, down to move to the VM, enter to start it. def send_vm_startup(): machine.send_key("home") machine.send_key("down") machine.send_key("ret")
create_vm_simple() machine.succeed(ru("VirtualBox >&2 &")) machine.wait_until_succeeds(ru("xprop -name 'Oracle 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 = '' 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 = '' create_vm_headless() machine.succeed(ru("VBoxHeadless --startvm headless >&2 & disown %1")) wait_for_startup_headless() wait_for_vm_boot_headless() shutdown_vm_headless() destroy_vm_headless() '';
host-usb-permissions = '' import sys
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 = '' 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 = '' create_vm_test1() create_vm_test2()
vbm("startvm test1") wait_for_startup_test1() wait_for_vm_boot_test1()
vbm("startvm test2") wait_for_startup_test2() wait_for_vm_boot_test2()
machine.screenshot("net_booted")
test1_ip = wait_for_ip_test1(1) test2_ip = wait_for_ip_test2(1)
machine.succeed(f"echo '{test2_ip}' | nc -N '{test1_ip}' 1234") machine.succeed(f"echo '{test1_ip}' | nc -N '{test2_ip}' 1234")
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")
shutdown_vm_test1() shutdown_vm_test2()
destroy_vm_test1() destroy_vm_test2() '';}// (optionalAttrs enableKvm kvmTests)// (optionalAttrs enableUnfree unfreeTests)