Commit 5f5734db authored by Michael Schneider's avatar Michael Schneider
Browse files

nixos/test-driver: add option to force kvm use

parent bffdf7c2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2246,6 +2246,9 @@
  "test-opt-passthru": [
    "index.html#test-opt-passthru"
  ],
  "test-opt-qemu.forceAccel": [
    "index.html#test-opt-qemu.forceAccel"
  ],
  "test-opt-qemu.package": [
    "index.html#test-opt-qemu.package"
  ],
+15 −8
Original line number Diff line number Diff line
@@ -24,30 +24,37 @@ rec {
    else
      throw "Unknown QEMU serial device for system '${stdenv.hostPlatform.system}'";

  qemuBinary =
    qemuPkg:
  qemuBinary = qemuPkg: qemuBinaryWith { inherit qemuPkg; };

  qemuBinaryWith =
    {
      qemuPkg,
      forceAccel ? false,
    }:
    let
      hostStdenv = qemuPkg.stdenv;
      hostSystem = hostStdenv.system;
      guestSystem = stdenv.hostPlatform.system;

      accel = accelName: if forceAccel then accelName else "${accelName}:tcg";

      linuxHostGuestMatrix = {
        x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine accel=kvm:tcg -cpu max";
        armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -machine virt,accel=kvm:tcg -cpu max";
        aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=max,accel=kvm:tcg -cpu max";
        x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine accel=${accel "kvm"} -cpu max";
        armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -machine virt,accel=${accel "kvm"} -cpu max";
        aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=max,accel=${accel "kvm"} -cpu max";
        powerpc64le-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
        powerpc64-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
        riscv32-linux = "${qemuPkg}/bin/qemu-system-riscv32 -machine virt";
        riscv64-linux = "${qemuPkg}/bin/qemu-system-riscv64 -machine virt";
        x86_64-darwin = "${qemuPkg}/bin/qemu-system-x86_64 -machine accel=kvm:tcg -cpu max";
        x86_64-darwin = "${qemuPkg}/bin/qemu-system-x86_64 -machine accel=${accel "kvm"} -cpu max";
      };
      otherHostGuestMatrix = {
        aarch64-darwin = {
          aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=2,accel=hvf:tcg -cpu max";
          aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=2,accel=${accel "hvf"} -cpu max";
          inherit (otherHostGuestMatrix.x86_64-darwin) x86_64-linux;
        };
        x86_64-darwin = {
          x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine type=q35,accel=hvf:tcg -cpu max";
          x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine type=q35,accel=${accel "hvf"} -cpu max";
        };
      };

+19 −1
Original line number Diff line number Diff line
@@ -336,10 +336,22 @@ class Driver:
    def start_all(self) -> None:
        """Start all machines"""
        with self.logger.nested("start all VMs"):
            errors: list[tuple[str, BaseException]] = []

            def start_machine(machine: BaseMachine) -> None:
                try:
                    machine.start()
                except Exception as e:
                    errors.append((machine.name, e))

            threads = []
            for machine in self.machines:
                # Create a thread for each machine's start method
                t = threading.Thread(target=machine.start, name=f"start-{machine.name}")
                t = threading.Thread(
                    target=start_machine,
                    args=(machine,),
                    name=f"start-{machine.name}",
                )
                threads.append(t)
                t.start()

@@ -347,6 +359,12 @@ class Driver:
            for t in threads:
                t.join()

            if errors:
                messages = [f"{name}: {e}" for name, e in errors]
                raise MachineError(
                    "Failed to start the following machines:\n" + "\n".join(messages)
                )

    def join_all(self) -> None:
        """Wait for all machines to shut down"""
        with self.logger.nested("wait for all VMs to finish"):
+24 −2
Original line number Diff line number Diff line
@@ -212,6 +212,7 @@ class QemuStartCommand:
            ),
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            shell=True,
            cwd=state_dir,
            env=self.build_environment(state_dir, shared_dir),
@@ -1227,8 +1228,29 @@ class QemuMachine(BaseMachine):
            self.shell_path,
            allow_reboot,
        )
        self.monitor, _ = monitor_socket.accept()
        self.shell, _ = shell_socket.accept()

        def accept_or_fail(sock: socket.socket, name: str) -> socket.socket:
            """Accept a connection on a socket, polling the status to check
            if the QEMU process is still alive. Without this, socket.accept()
            would block forever if QEMU exits before connecting.
            """
            assert self.process
            while True:
                readable, _, _ = select.select([sock], [], [], 1.0)
                if readable:
                    conn, _ = sock.accept()
                    return conn
                rc = self.process.poll()
                if rc is not None:
                    output = ""
                    if self.process.stdout:
                        output = self.process.stdout.read().decode(errors="ignore")
                    raise MachineError(
                        f"QEMU process exited with code {rc} before connecting to {name} socket.\n{output}"
                    )

        self.monitor = accept_or_fail(monitor_socket, "monitor")
        self.shell = accept_or_fail(shell_socket, "shell")
        self.qmp_client = QMPSession.from_path(self.qmp_path)

        # Store last serial console lines for use
+10 −0
Original line number Diff line number Diff line
@@ -159,6 +159,16 @@ in
      defaultText = "hostPkgs.qemu_test";
    };

    qemu.forceAccel = mkOption {
      description = ''
        Whether to force the use of hardware-accelerated virtualisation.
        When enabled, QEMU will not fall back to the slower software emulation
        (TCG) and will instead error out if the accelerator is not available.
      '';
      type = types.bool;
      default = false;
    };

    globalTimeout = mkOption {
      description = ''
        A global timeout for the complete test, expressed in seconds.
Loading