vmrunner
A utility to enable running tests, or components of integration tests specifically, in a micro-vm.
Supported hosts and limitations
vmrunner is currently intended for Linux integration tests that launch Linux guests with
libkrun. The tested path is Fedora Linux on x86_64 with a recent kernel and KVM enabled.
Minimum practical host requirements:
- Linux with KVM support.
/dev/kvmmust exist and be accessible to the user running the tests (for example through the host'skvmgroup or equivalent permissions). - Kernel support for unprivileged user and network namespaces. The default
#[vmrunner::test]wrapper usesunshareto enter an isolated user+network namespace before preparing VM state. - TUN/TAP support (
/dev/net/tun) when tests opt into host-visibletun-rsTAP-backed networking. The default harness network uses libkrun Unix-stream sockets and an in-process L2 switch instead of Linux bridges orkrun_add_net_tap. libkrunand its runtime dependencies installed for the host architecture.libkrunfw, the Linux kernel firmware shared object loaded bylibkrun.- A prepared Linux guest root filesystem. For
#[vmrunner::test(system = "fedora")], the consuming crate's build script must setKRUN_TEST_BASE_DIRto an unpacked rootfs path. Tests can also pass an explicit unpacked rootfs withsystem_rootfs = "...".
Known usage limitations:
- Linux hosts only for the default runner path. The harness code contains a few macOS-specific
libkrunsettings, butvmrunner's default namespace setup depends on Linuxunshare, user namespaces, network namespaces, and TAP semantics. - The
#[vmrunner::test(system = "fedora")]macro remains the built-in shorthand forKRUN_TEST_BASE_DIR. Callers can provide an unpacked rootfs directly withsystem_rootfs = "...". - Requires Rust 1.85 or newer, matching the crate's
rust-versionand Edition 2024 manifest. - Run VM tests from a normal user account that is allowed to use KVM and unprivileged namespaces. Running inside containers, CI sandboxes, nested virtualization, or hardened distributions may require extra host configuration or may not work at all.
- VM launch uses
forkand then enterslibkrun; avoid doing manual namespace setup or VM launch from already-complex multithreaded test processes. The macro-generated wrapper performs namespace setup at the start of the test to avoid common Tokio/threading pitfalls.
The Magic
It takes std::env::current_exe() and uses a provided rootfs to execute the current process again inside the VM, mapping
the specific binary into the VM. For Linux tests, the default macro still uses unshare to prepare an isolated user/network
namespace before VM setup. The harness network itself uses libkrun Unix-stream sockets by default; host-visible TAP/feth
uplinks are available through the optional tun-rs backend.
A typical test uses #[vmrunner::test(...)] instead of #[test]. The macro builds a
TestSetup before calling the test body; VM harness code can then use the setup's per-test
system rootfs path when launching the guest.
use TestSetup;
The generated wrapper is roughly equivalent to this expanded form:
use TestSetup;