From: Gregory Price Date: Fri, 23 Jan 2026 19:48:09 +0000 (-0500) Subject: config / qemu: add Console=headless X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=114ae558efd647fbb49e974bb9aa4c2ba9751103;p=thirdparty%2Fmkosi.git config / qemu: add Console=headless Add a headless option for Console so automation can run the qemu instance in a background task. In the current modes, qemu just exits on boot because the console has nothing to attach to. vmspawn does not support headless for now, just die if this is set. Signed-off-by: Gregory Price --- diff --git a/mkosi/config.py b/mkosi/config.py index 0916dac4e..37d3b4912 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -376,6 +376,7 @@ class ConsoleMode(StrEnum): read_only = enum.auto() native = enum.auto() gui = enum.auto() + headless = enum.auto() class Network(StrEnum): diff --git a/mkosi/qemu.py b/mkosi/qemu.py index 6617677bf..e7cbdfeb9 100644 --- a/mkosi/qemu.py +++ b/mkosi/qemu.py @@ -809,7 +809,7 @@ def finalize_kernel_command_line_extra(config: Config) -> list[str]: ): cmdline += [f"systemd.hostname={config.machine}"] - if config.console != ConsoleMode.gui: + if config.console not in (ConsoleMode.gui, ConsoleMode.headless): cmdline += [ f"systemd.tty.term.console={term}", f"systemd.tty.columns.console={columns}", @@ -817,7 +817,7 @@ def finalize_kernel_command_line_extra(config: Config) -> list[str]: "console=hvc0", f"TERM={term}", ] - elif config.architecture.is_arm_variant(): + elif config.console == ConsoleMode.gui and config.architecture.is_arm_variant(): cmdline += ["console=tty0"] for s in config.kernel_command_line_extra: @@ -993,9 +993,11 @@ def run_qemu(args: Args, config: Config) -> None: if config.vsock == ConfigFeature.enabled and QemuDeviceNode.vhost_vsock not in qemu_device_fds: die("VSock requested but cannot access /dev/vhost-vsock") - if config.console not in (ConsoleMode.native, ConsoleMode.gui) and not config.find_binary( - "systemd-pty-forward" - ): + if config.console not in ( + ConsoleMode.native, + ConsoleMode.gui, + ConsoleMode.headless, + ) and not config.find_binary("systemd-pty-forward"): die(f"Console mode {config.console} requested but systemd-pty-forward not found") if config.linux: @@ -1141,12 +1143,16 @@ def run_qemu(args: Args, config: Config) -> None: cmdline += [ "-nographic", "-nodefaults", - "-chardev", "stdio,mux=on,id=console,signal=off", - "-device", "virtio-serial-pci,id=mkosi-virtio-serial-pci", - "-device", "virtconsole,chardev=console", - "-mon", "console", ] # fmt: skip + if config.console != ConsoleMode.headless: + cmdline += [ + "-chardev", "stdio,mux=on,id=console,signal=off", + "-device", "virtio-serial-pci,id=mkosi-virtio-serial-pci", + "-device", "virtconsole,chardev=console", + "-mon", "console", + ] # fmt: skip + # QEMU has built-in logic to look for the BIOS firmware so we don't need to do anything special for that. if firmware.is_uefi(): assert ovmf diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index cb3fcd53b..23adf9d18 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -1818,11 +1818,13 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, kernel command line arguments. `Console=`, `--console=` -: Configures how to set up the console of the VM. Takes one of `interactive`, `read-only`, `native`, or - `gui`. Defaults to `interactive`. `interactive` provides an interactive terminal interface to the VM. - `read-only` is similar, but is strictly read-only, i.e. does not accept any input from the user. - `native` also provides a TTY-based interface, but uses **qemu**'s native implementation (which means the **qemu** - monitor is available). `gui` shows the **qemu** graphical UI. +: Configures how to set up the console of the VM. Takes one of `interactive`, `read-only`, `native`, + `gui`, or `headless`. Defaults to `interactive`. `interactive` provides an interactive terminal interface + to the VM. `read-only` is similar, but is strictly read-only, i.e. does not accept any input from the + user. `native` also provides a TTY-based interface, but uses **qemu**'s native implementation (which means + the **qemu** monitor is available). `gui` shows the **qemu** graphical UI. `headless` runs the VM without + any console attached, useful for fully automated or scripted VM usage. `headless` is only supported by + the `qemu` verb. `CPUs=`, `--cpus=` : Configures the number of CPU cores to assign to the guest when booting a virtual machine. diff --git a/mkosi/vmspawn.py b/mkosi/vmspawn.py index c8e7e55d9..c93f9453f 100644 --- a/mkosi/vmspawn.py +++ b/mkosi/vmspawn.py @@ -9,6 +9,7 @@ from pathlib import Path from mkosi.config import ( Args, Config, + ConsoleMode, Firmware, Network, OutputFormat, @@ -36,6 +37,9 @@ def run_vmspawn(args: Args, config: Config) -> None: if config.firmware_variables and config.firmware_variables != Path("microsoft"): die("mkosi vmspawn does not support FirmwareVariables=") + if config.console == ConsoleMode.headless: + die("Console=headless is not supported by vmspawn") + kernel = config.expand_linux_specifiers() if config.linux else None firmware = finalize_firmware(config, kernel)