qemu

package
v0.0.0-...-5d9f3d3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2024 License: BSD-3-Clause Imports: 16 Imported by: 1

Documentation

Overview

Package qemu provides a Go API for starting QEMU VMs.

qemu is mainly suitable for running QEMU-based integration tests.

The environment variable `VMTEST_QEMU` overrides the path to QEMU and the first few arguments. For example:

VMTEST_QEMU='qemu-system-x86_64 -L . -m 4096 -enable-kvm'

Other environment variables:

VMTEST_ARCH (used when Arch is empty or ArchUseEnvv is set)
VMTEST_QEMU_APPEND (always added to QEMU arguments)
VMTEST_KERNEL (used when Options.Kernel is empty)
VMTEST_KERNEL_APPEND (always added to kernel args)
VMTEST_INITRAMFS (used when Options.Initramfs is empty)
VMTEST_TIMEOUT (used when Options.VMTimeout is empty)

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidDir = errors.New("no directory specified")

ErrInvalidDir is used when no directory is specified for file sharing.

View Source
var ErrInvalidTag = errors.New("no tag specified for 9P file system")

ErrInvalidTag is used when no tag is specified for 9P file system sharing.

View Source
var ErrInvalidTimeout = errors.New("could not parse VMTEST_TIMEOUT")

ErrInvalidTimeout is returned when VMTEST_TIMEOUT could not be parsed.

View Source
var ErrIsNotDir = errors.New("file system sharing requires directory")

ErrIsNotDir is used when the directory specified for file sharing is not a directory.

View Source
var ErrKernelRequiredForArgs = errors.New("KernelArgs can only be used when Kernel is also specified due to how QEMU bootloader works")

ErrKernelRequiredForArgs is returned when KernelArgs is populated but Kernel is empty.

View Source
var ErrUnsupportedArch = errors.New("unsupported guest architecture specified -- guest arch is required to decide some QEMU command-line arguments")

ErrUnsupportedArch is returned when an unsupported guest architecture value is used.

View Source
var SupportedArches = []Arch{
	ArchAMD64,
	ArchI386,
	ArchArm64,
	ArchArm,
	ArchRiscv64,
}

SupportedArches are the supported guest architecture values.

Functions

func SkipIfNotArch

func SkipIfNotArch(tb testing.TB, allowed ...Arch)

SkipIfNotArch skips this test if GuestArch() (which is either VMTEST_ARCH or runtime.GOARCH) is not one of the given values.

func SkipWithoutQEMU

func SkipWithoutQEMU(tb testing.TB)

SkipWithoutQEMU skips the test when the QEMU environment variable is not set.

Types

type Arch

type Arch string

Arch is the QEMU guest architecture.

const (
	// ArchUseEnvv will derive the architecture from the VMTEST_ARCH env var.
	ArchUseEnvv Arch = ""

	// ArchAMD64 is the x86 64bit architecture.
	ArchAMD64 Arch = "amd64"

	// ArchI386 is the x86 32bit architecture.
	ArchI386 Arch = "i386"

	// ArchArm64 is the aarch64 architecture.
	ArchArm64 Arch = "arm64"

	// ArchArm is the arm 32bit architecture.
	ArchArm Arch = "arm"

	// ArchRiscv64 is the riscv 64bit architecture.
	ArchRiscv64 Arch = "riscv64"
)

Architecture values are derived from GOARCH values.

func GuestArch

func GuestArch() Arch

GuestArch returns the Guest architecture under test. Either VMTEST_ARCH or runtime.GOARCH.

func (Arch) Valid

func (g Arch) Valid() bool

Valid returns whether the guest arch is a supported guest arch value.

type Fn

type Fn func(*IDAllocator, *Options) error

Fn is a QEMU configuration option supplied to Start or OptionsFor.

Fns rely on a QEMU architecture already having been determined.

func All

func All(fn ...Fn) Fn

All applies all given configurators in order. If an error occurs, it returns the error early.

func ArbitraryArgs

func ArbitraryArgs(aa ...string) Fn

ArbitraryArgs adds arbitrary arguments to the QEMU command line.

func ByArch

func ByArch(m map[Arch]Fn) Fn

ByArch applies only the Fn config function applicable to the VM guest architecture.

func HaltOnKernelPanic

func HaltOnKernelPanic() Fn

HaltOnKernelPanic passes args to QEMU and kernel to halt when the kernel panics.

Linux's default behavior is to hang forever, which is not great test behavior.

func IDEBlockDevice

func IDEBlockDevice(file string) Fn

IDEBlockDevice emulates an AHCI/IDE block device.

func IfArch

func IfArch(arch Arch, fn Fn) Fn

IfArch applies fn only if the VM guest arch is the given arch.

func IfNotArch

func IfNotArch(arch Arch, fn Fn) Fn

IfNotArch applies fn only if the VM guest arch is not the given arch.

func LogSerialByLine

func LogSerialByLine(callback LinePrinter) Fn

LogSerialByLine processes serial output from the guest one line at a time and calls callback on each full line.

func P9BootDirectory

func P9BootDirectory(dir string) Fn

P9BootDirectory adds QEMU args that expose a directory as a Plan9 (9p) read-write filesystem in the VM as the boot device.

The directory will be used as the root volume. There can only be one boot 9pfs at a time. The tag used will be /dev/root, and Linux kernel args will be appended to mount it as the root file system.

func P9Directory

func P9Directory(dir string, tag string) Fn

P9Directory adds QEMU args that expose a directory as a Plan9 (9p) read-write filesystem in the VM.

dir is the directory to expose as read-write 9p filesystem.

tag is an identifier that is used within the VM when mounting an fs, e.g. 'mount -t 9p my-vol-ident mountpoint'. The tag must be unique for each dir.

P9Directory will add a kernel cmdline argument in the style of VMTEST_MOUNT9P_$qemuID=$tag. Likely this is only useful on Linux. The vmmount command in vminit/vmmount can be used to mount 9P directories passed to the VM this way at /mount/9p/$tag in the guest. See the example in ./examples/shareddir.

func ReadOnlyDirectory

func ReadOnlyDirectory(dir string) Fn

ReadOnlyDirectory adds args that expose a directory as a /dev/sda1 readonly vfat partition in the VM guest.

func VirtioRandom

func VirtioRandom() Fn

VirtioRandom adds QEMU args that expose a PCI random number generator to the guest VM.

func WithAppendKernel

func WithAppendKernel(args ...string) Fn

WithAppendKernel appends kernel arguments.

func WithInitramfs

func WithInitramfs(initramfs string) Fn

WithInitramfs sets the path to the initramfs.

func WithKernel

func WithKernel(kernel string) Fn

WithKernel sets the path to the kernel binary.

func WithQEMUArgs

func WithQEMUArgs(aa ...string) Fn

WithQEMUArgs adds arguments to the QEMU command line.

func WithQEMUCommand

func WithQEMUCommand(cmd string) Fn

WithQEMUCommand sets a QEMU command. It's expected to provide a QEMU binary and optionally some arguments.

cmd may contain additional QEMU args, such as "qemu-system-x86_64 -enable-kvm -m 1G". They will be appended to the command-line.

func WithSerialOutput

func WithSerialOutput(w ...io.WriteCloser) Fn

WithSerialOutput writes serial output to w as well.

func WithTask

func WithTask(t ...Task) Fn

WithTask adds a goroutine running alongside the guest.

Task goroutines are started right before the guest is started.

VM.Wait waits for all tasks to complete before returning an error. Errors produced by tasks are returned by VM.Wait.

A task is expected to exit either when ctx is canceled or when the QEMU subprocess exits. When the context is canceled, the QEMU subprocess is expected to exit as well, and when the QEMU subprocess exits, the context is canceled.

func WithVMTimeout

func WithVMTimeout(timeout time.Duration) Fn

WithVMTimeout is a timeout for the QEMU guest subprocess.

func WithVmtestIdent

func WithVmtestIdent() Fn

WithVmtestIdent adds VMTEST_IN_GUEST=1 to kernel commmand-line.

Tests may use this env var to identify they are running inside a vmtest using guest.SkipIfNotInVM or guest.SkipIfInVM.

type IDAllocator

type IDAllocator struct {
	// contains filtered or unexported fields
}

IDAllocator is used to ensure no overlapping QEMU option IDs.

func NewIDAllocator

func NewIDAllocator() *IDAllocator

NewIDAllocator returns a new ID allocator for QEMU option IDs.

func (*IDAllocator) ID

func (a *IDAllocator) ID(prefix string) string

ID returns the next available ID for the given prefix.

type LinePrinter

type LinePrinter func(line string)

LinePrinter prints one line to some output.

func DefaultPrint

func DefaultPrint(prefix string, printer func(fmt string, arg ...any)) LinePrinter

DefaultPrint is the default LinePrinter, adding a prefix and relative timestamp.

func Prefix

func Prefix(prefix string, printer LinePrinter) LinePrinter

Prefix returns a LinePrinter that prefixes the given LinePrinter with "prefix: ".

func PrintLine

func PrintLine(printer func(fmt string, arg ...any)) LinePrinter

PrintLine is a LinePrinter that prints to a standard "formatter" like testing.TB.Logf or fmt.Printf.

func RelativeTS

func RelativeTS(printer LinePrinter) LinePrinter

RelativeTS prefixes line printer output with "[%06.4fs] " seconds since the first log line.

func TS

func TS(format string, printer LinePrinter) LinePrinter

TS prefixes line printer output with a timestamp since the first log line.

format can be any Time.Format format string. Recommendations are time.TimeOnly or time.DateTime.

type Notifications

type Notifications struct {
	// VMStarted will be closed when the VM is started.
	VMStarted chan struct{}

	// VMExited will receive exactly 1 event when the VM exits and then be closed.
	VMExited chan error
}

Notifications gives tasks the option to wait for certain VM events.

Tasks must not be required to listen on notifications; there must be no blocking channel I/O.

type Options

type Options struct {

	// QEMUCommand is QEMU binary to invoke and some additional args.
	//
	// If empty, the VMTEST_QEMU env var will be used.
	QEMUCommand string

	// Path to the kernel to boot.
	//
	// If empty, VMTEST_KERNEL env var will be used.
	Kernel string

	// Path to the initramfs.
	//
	// If empty, VMTEST_INITRAMFS env var will be used.
	Initramfs string

	// Extra kernel command-line arguments.
	//
	// VMTEST_KERNEL_APPEND env var will always be prepended.
	KernelArgs string

	// Where to send serial output.
	SerialOutput []io.WriteCloser

	// Tasks are goroutines running alongside the guest.
	//
	// Task goroutines are started right before the guest is started.
	//
	// A task is expected to exit either when ctx is canceled or when the
	// QEMU subprocess exits. When the context is canceled, the QEMU
	// subprocess is expected to exit as well, and when the QEMU subprocess
	// exits, the context is canceled.
	//
	// Tasks may depend on ExtraFiles or SerialOutput to be closed to exit.
	Tasks []Task

	// Additional QEMU cmdline arguments.
	QEMUArgs []string

	// VMTimeout is a timeout for the QEMU subprocess.
	VMTimeout time.Duration

	// ExtraFiles are extra files passed to QEMU on start.
	ExtraFiles []*os.File
	// contains filtered or unexported fields
}

Options are VM start-up parameters.

func OptionsFor

func OptionsFor(arch Arch, fns ...Fn) (*Options, error)

OptionsFor evaluates the given config functions and returns an Options object.

func (*Options) AddFile

func (o *Options) AddFile(f *os.File) int

AddFile adds the file to the QEMU process and returns the FD it will be in the child process.

func (*Options) AppendKernel

func (o *Options) AppendKernel(s ...string)

AppendKernel appends to kernel args.

func (*Options) AppendQEMU

func (o *Options) AppendQEMU(s ...string)

AppendQEMU appends args to the QEMU command line.

func (*Options) Arch

func (o *Options) Arch() Arch

Arch returns the guest architecture.

func (*Options) Cmdline

func (o *Options) Cmdline() ([]string, error)

Cmdline returns the command line arguments used to start QEMU. These arguments are derived from the given QEMU struct.

func (*Options) Start

func (o *Options) Start(ctx context.Context) (*VM, error)

Start starts a QEMU VM and its associated task goroutines.

When the context is done, the QEMU subprocess will be killed and all associated goroutines cleaned up as long as VM.Wait() is called.

SerialOutput will be relayed only if VM.Wait is also called some time after the VM starts.

type Task

type Task func(ctx context.Context, n *Notifications) error

A Task is a goroutine running alongside the guest.

Tasks are started before the guest process is started. A task is expected to exit either when ctx is canceled or when the QEMU subprocess exits.

VM.Wait waits for all tasks to finish after the guest process exits, and returns their non-nil errors.

func Cleanup

func Cleanup(f func() error) Task

Cleanup adds a function to be run after the VM process exits. If the function returns an error, Wait will return that error.

func WaitVMStarted

func WaitVMStarted(t Task) Task

WaitVMStarted waits until the VM has started before starting t, or never starts t if context is canceled before the VM is started.

type VM

type VM struct {
	// Console provides in/output to the QEMU subprocess.
	Console *expect.Console

	// Options are the options that were used to start the VM.
	//
	// They are not used once the VM is started.
	Options *Options
	// contains filtered or unexported fields
}

VM is a running QEMU virtual machine.

func Start

func Start(arch Arch, fns ...Fn) (*VM, error)

Start starts a QEMU VM and its associated task goroutines with the given config.

SerialOutput will be relayed only if VM.Wait is also called some time after the VM starts.

func StartContext

func StartContext(ctx context.Context, arch Arch, fns ...Fn) (*VM, error)

StartContext starts a QEMU VM and its associated task goroutines with the given config.

When the context is done, the QEMU subprocess will be killed and all associated goroutines cleaned up as long as VM.Wait() is called.

SerialOutput will be relayed only if VM.Wait is also called some time after the VM starts.

func StartT

func StartT(t testing.TB, name string, arch Arch, fns ...Fn) *VM

StartT starts a QEMU VM and its associated task goroutines with the given config.

Logs serial console to t.Logf using name as a prefix, with relative timestamps.

If the start fails, the test fails. At the end of the test, the command-line invocation for the VM is logged for reproduction. Also ensures that vm.Wait() was called by the end of the test, as it is required to drain console output.

SerialOutput will be relayed only if VM.Wait is also called some time after the VM starts.

func (*VM) Cmdline

func (v *VM) Cmdline() []string

Cmdline is the command-line the VM was started with.

func (*VM) CmdlineQuoted

func (v *VM) CmdlineQuoted() string

CmdlineQuoted quotes any of QEMU's command line arguments containing a space so it is easy to copy-n-paste into a shell for debugging.

func (*VM) Kill

func (v *VM) Kill() error

Kill kills the QEMU subprocess.

Callers are still responsible for calling VM.Wait after calling kill to clean up task goroutines and to get remaining serial console output.

func (*VM) Signal

func (v *VM) Signal(sig os.Signal) error

Signal signals the QEMU subprocess.

Callers are still responsible for calling VM.Wait if the subprocess exits due to this signal to clean up task goroutines and to get remaining serial console output.

func (*VM) Wait

func (v *VM) Wait() error

Wait waits for the VM guest process to exit, drains serial console output, and waits for any associated task to exit.

If the guest process returned a non-zero exit status or any task returned an error, Wait returns an error.

func (*VM) Waited

func (v *VM) Waited() bool

Waited returns whether Wait has been called on VM.

Directories

Path Synopsis
Package qcoverage allows collecting kernel and Go integration test coverage.
Package qcoverage allows collecting kernel and Go integration test coverage.
Package qevent implements a JSON-based event channel between guest and host.
Package qevent implements a JSON-based event channel between guest and host.
Package qfirmware provides firmware configurators for use with the Go qemu API.
Package qfirmware provides firmware configurators for use with the Go qemu API.
Package qnetwork provides net device configurators for use with the Go qemu API.
Package qnetwork provides net device configurators for use with the Go qemu API.
Package quimage provides a Go API for creating QEMU VMs with u-root uimage initramfses.
Package quimage provides a Go API for creating QEMU VMs with u-root uimage initramfses.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL