Loading nixos/doc/manual/redirects.json +3 −0 Original line number Diff line number Diff line Loading @@ -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" ], Loading nixos/lib/qemu-common.nix +15 −8 Original line number Diff line number Diff line Loading @@ -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"; }; }; Loading nixos/lib/test-driver/src/test_driver/driver.py +19 −1 Original line number Diff line number Diff line Loading @@ -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() Loading @@ -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"): Loading nixos/lib/test-driver/src/test_driver/machine/__init__.py +24 −2 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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 Loading nixos/lib/testing/driver.nix +10 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
nixos/doc/manual/redirects.json +3 −0 Original line number Diff line number Diff line Loading @@ -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" ], Loading
nixos/lib/qemu-common.nix +15 −8 Original line number Diff line number Diff line Loading @@ -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"; }; }; Loading
nixos/lib/test-driver/src/test_driver/driver.py +19 −1 Original line number Diff line number Diff line Loading @@ -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() Loading @@ -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"): Loading
nixos/lib/test-driver/src/test_driver/machine/__init__.py +24 −2 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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 Loading
nixos/lib/testing/driver.nix +10 −0 Original line number Diff line number Diff line Loading @@ -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