libvirt

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DomainRunning int32 = 1
	DomainShutoff int32 = 5
)

virDomainState values (subset).

Variables

View Source
var (
	// ErrUnreachable: TCP dial failed — libvirtd is not listening (or the
	// host is wrong).
	ErrUnreachable = errors.New("libvirtd unreachable")
	// ErrHandshake: TCP connected but the libvirt RPC handshake failed —
	// wrong service on the port, or auth rejected.
	ErrHandshake = errors.New("libvirt handshake failed")
)

Typed connection errors, so callers (preflight, CELL-376) can map each failure to its own remediation instead of showing a raw dial error.

Functions

func ParseURI

func ParseURI(uri string) (string, error)

ParseURI validates a libvirt connection URI and returns the TCP dial address. Only qemu+tcp:// is supported: the CLI runs inside a Linux cell and reaches the host's libvirtd over TCP (qemu+ssh:// is future work).

func Preflight

func Preflight(ctx context.Context, uri string) error

Preflight verifies a libvirtd daemon answers at uri and completes the RPC handshake, mapping each failure mode to one actionable message (the CELL-44 pattern: read the error, know the next command).

func ShouldDefaultToLibvirt

func ShouldDefaultToLibvirt(engine string, forceLocal bool, p Probes) (bool, string)

ShouldDefaultToLibvirt decides whether an --engine=qemu launch should upgrade to libvirt remote mode, and why.

Authority ordering follows accel.go: explicit intent always wins (--local pins the in-container path; any engine other than qemu is untouched), and the upgrade fires only when every probe agrees the environment is a Docker cell on a Mac where local qemu can only mean TCG.

func SpecToDomainXML

func SpecToDomainXML(spec qemu.Spec) ([]byte, error)

SpecToDomainXML renders a qemu.Spec as a libvirt domain document.

The domain always targets the macOS host (type hvf, machine virt, cpu host-passthrough): in libvirt mode the CLI may run inside a Linux cell, but the VM boots on the darwin side of the connection — command.go's runtime.GOOS switches must not leak in here.

Anything libvirt can express natively is native (name, memory, vcpu, firmware, VNC, reboot policy). Everything else — guest NVMe controller (Windows ARM64 has no virtio storage driver inbox, CELL-359), ramfb, hostfwd user networking, xhci port sizing, serial chardevs — is taken VERBATIM from qemu.BuildRunCommand's argv and passed through <qemu:commandline>, so the two launch paths cannot drift: a new argv flag flows through automatically unless it is claimed by the native map.

func TranslateSpecPaths

func TranslateSpecPaths(spec qemu.Spec, m PathMap) (qemu.Spec, error)

TranslateSpecPaths returns a copy of spec with every field QEMU opens on the host rewritten through the map. Empty fields stay empty; the input is not mutated. SSHKeyPath is deliberately absent: the ssh client runs on the CLI side, in the container namespace.

Types

type Client

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

Client is a connection to a libvirtd daemon.

func Connect

func Connect(ctx context.Context, uri string) (*Client, error)

Connect dials the daemon named by uri and completes the libvirt handshake. The context bounds both the dial and the handshake.

func (*Client) Close

func (c *Client) Close() error

Close disconnects from the daemon and closes the socket.

go-libvirt's Disconnect tears the socket down itself, so both it and our conn.Close can report "use of closed network connection" — benign teardown noise, not a failure (it broke the first field run, 2026-07-30).

func (*Client) DefineDomain

func (c *Client) DefineDomain(xml string) (string, error)

DefineDomain registers (or replaces) a persistent domain from XML and returns its name.

func (*Client) DestroyDomain

func (c *Client) DestroyDomain(name string) error

DestroyDomain force-stops a domain (hard power-off).

func (*Client) DomainState

func (c *Client) DomainState(name string) (int32, error)

DomainState returns the libvirt run state for a domain (values from virDomainState: 1=running, 5=shutoff, ...).

func (*Client) ListDomains

func (c *Client) ListDomains() ([]string, error)

ListDomains returns the names of all domains, active and inactive.

func (*Client) ShutdownDomain

func (c *Client) ShutdownDomain(name string) error

ShutdownDomain requests a graceful guest shutdown (ACPI).

func (*Client) StartDomain

func (c *Client) StartDomain(name string) error

StartDomain boots a defined domain by name.

func (*Client) UndefineDomain

func (c *Client) UndefineDomain(name string) error

UndefineDomain removes a persistent domain definition.

type DomainClient

type DomainClient interface {
	DefineDomain(xml string) (string, error)
	StartDomain(name string) error
	ShutdownDomain(name string) error
	DestroyDomain(name string) error
	DomainState(name string) (int32, error)
	Close() error
}

DomainClient is the slice of Client the engine needs; injectable in tests.

type Engine

type Engine struct {
	URI  string
	Spec qemu.Spec
	Map  PathMap

	// SSHWaitTimeout bounds the post-boot SSH wait. The template is already
	// installed and provisioned, so this is a boot, not a Windows install.
	SSHWaitTimeout time.Duration
	// ShutdownGraceTimeout bounds the graceful-shutdown wait before escalating
	// to destroy.
	ShutdownGraceTimeout time.Duration
	// ShutdownPollInterval is how often Shutdown re-checks the domain state.
	ShutdownPollInterval time.Duration

	// ConnectFn is the transport factory; tests inject a fake.
	ConnectFn func(ctx context.Context, uri string) (DomainClient, error)
	// WaitSSHFn waits for the forwarded SSH port; tests inject a fake.
	WaitSSHFn func(host string, port uint16, timeout time.Duration) error
	// contains filtered or unexported fields
}

Engine boots and stops a prepped Windows template on the machine behind a libvirtd connection (CELL-377). It implements the vm.Engine lifecycle.

func NewEngine

func NewEngine(uri string, spec qemu.Spec, m PathMap) *Engine

NewEngine builds an engine with production defaults.

func (*Engine) Boot

func (e *Engine) Boot(ctx context.Context) error

Boot defines and starts the domain, then waits for SSH. A domain that is already running is attached to instead of redefined.

func (*Engine) DomainXML

func (e *Engine) DomainXML() ([]byte, error)

DomainXML renders the domain document this engine would define: paths translated to the host namespace, hostfwd bound on all interfaces so the forward is reachable from the container (the mac's 127.0.0.1 is not).

func (*Engine) Preflight

func (e *Engine) Preflight() error

Preflight verifies the daemon answers (vm.Engine interface).

func (*Engine) SSHArgv

func (e *Engine) SSHArgv(binary string, flags, args []string) []string

SSHArgv builds the exec argv for the booted guest (vm.Engine interface).

func (*Engine) SSHHost

func (e *Engine) SSHHost() string

SSHHost returns where the forwarded guest ports are reachable from the CLI's network namespace: the libvirt URI's hostname — the forward lives on the same machine as libvirtd.

func (*Engine) Shutdown

func (e *Engine) Shutdown(ctx context.Context) error

Shutdown requests a graceful stop and escalates to destroy when the guest does not power off within ShutdownGraceTimeout. A no-op before Boot.

type PathMap

type PathMap []PathMapping

PathMap translates container paths to host paths for domain XML.

Empty means the CLI already runs on the host — every path passes through. Non-empty means strict translation: QEMU on the host cannot open a container-only path, so an unmapped path is an error, not a passthrough.

func (PathMap) TranslateToHost

func (m PathMap) TranslateToHost(p string) (string, error)

TranslateToHost rewrites p using the longest matching mapping prefix. Prefixes match on path boundaries only: /devcell-1555 does not match a /devcell-155 mapping.

type PathMapping

type PathMapping struct {
	From string // container-side prefix (bind mount target)
	To   string // host-side prefix (bind mount source)
}

PathMapping rewrites one container path prefix to its host equivalent.

type Probes

type Probes struct {
	// InContainer reports whether the CLI runs inside a container.
	InContainer func() bool
	// HostResolves reports whether the Docker host gateway name resolves.
	HostResolves func() bool
	// KVMUsable reports whether /dev/kvm can actually be opened.
	KVMUsable func() error
}

Probes are the environment signals behind the qemu→libvirt auto-default (CELL-378). Injectable so the decision matrix is unit-testable.

func DefaultProbes

func DefaultProbes() Probes

DefaultProbes wires the production signals: /.dockerenv, a DNS lookup of host.docker.internal, and qemu.ProbeKVM. All three are one cheap syscall or lookup — this runs on every launch.

Jump to

Keyboard shortcuts

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