Documentation
¶
Overview ¶
Package fleetbox provides Linux VMs as Go test fixtures.
On macOS (Apple Silicon) fleetbox boots stock Linux cloud images via Apple Virtualization.framework; on Linux it boots them via cloud-hypervisor. Either way it configures the guest once with cloud-init and provides SSH access for testing, through the same backend-neutral Go API.
The orchestration runs client-side on both platforms and drives a VM helper over a unix socket; the helper holds only the live VMs/network (ADR-0020). On macOS that helper is a separately distributed, ad-hoc-signed fleetbox-helper subprocess the library downloads at first use, so the importable package — and therefore the user's test binary — is pure Go and needs neither cgo nor codesign (ADR-0017). On Linux the single binary self-reexecs into the helper. The public API below is identical on both.
Basic usage:
vm, err := fleetbox.Start(ctx, "myvm")
if err != nil {
log.Fatal(err)
}
defer vm.Stop(ctx)
out, err := vm.SSH(ctx, "uname -a")
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrClustersUnsupported = errors.New("fleetbox: clusters require macOS 26+")
ErrClustersUnsupported is returned when a second cluster member is requested on a backend that cannot interconnect VMs — macOS older than 26, where VZ NAT isolates VMs from one another (ADR-0008, ADR-0012). A single VM still works.
Functions ¶
func NestedVirtSupported ¶
func NestedVirtSupported() bool
NestedVirtSupported returns true if nested virtualization is available — what consumers that run KVM inside guests need. On macOS it requires Apple Silicon M3+ and macOS 15+; on Linux it requires /dev/kvm and the KVM nested parameter enabled. On macOS it is a pure-Go host heuristic (so deciding to skip a test never downloads the helper); the helper performs the authoritative VZ check at boot (ADR-0017, R7).
func Prune ¶
func Prune() error
Prune reclaims the inert host resources a fleetbox holder leaves behind if it dies without running its teardown — on Linux, orphaned bridges, taps, and firewall rules, plus restoring ip_forward once nothing of ours remains. It runs automatically on the CLI's down, so cleanup is never the user's job; this exported form is for library callers that want to sweep explicitly. On macOS it is a no-op: vmnet owns its own state and the in-process VMs of a dead helper die with it (ADR-0013, ADR-0017).
Types ¶
type Cluster ¶
type Cluster struct {
// contains filtered or unexported fields
}
Cluster is a set of VMs sharing one network, so every member reaches the others by IP — a vmnet SharedMode network on macOS, a Linux bridge on Linux (ADR-0008, ADR-0011). The shared network is a runtime object tied to the Cluster's lifetime — never persisted, so a Cluster is a runtime handle, not on-disk state. Members can be added after creation, which is what lets a CLI holder process grow a live cluster without recreating its network.
func NewCluster ¶
NewCluster creates a cluster client. The helper is spawned on the first Add (it is launched on the first member's name) and then owns every member on one shared network. Shared client prep (store, SSH key, image) runs once and is reused for every Add.
func StartCluster ¶
StartCluster boots the named VMs on one shared network and returns the Cluster. On any member's failure it destroys the members already started and closes the cluster, then returns the error (all-or-nothing, like StartN).
func (*Cluster) Add ¶
Add boots an additional VM on the cluster's shared network and registers it as a member. The new VM reaches every existing member by IP. Adding a second member on a backend that cannot interconnect VMs (macOS < 26) is rejected with ErrClustersUnsupported before any boot work — the same guard StartCluster applies up front, here also covering a node re-joining a live cluster (ADR-0012). The first member is a lone VM and is always allowed.
type Fixture ¶
Fixture is a read-only host directory packed into the guest at boot. At first creation HostPath is snapshotted into an ext4 image, attached to the VM as a read-only block device, and mounted by the stock guest at GuestPath via cloud-init. Fixtures are a property the VM is born with: the set is frozen at first creation and persisted, but the content is rebuilt from HostPath on every boot (so the guest sees the directory as it is at that boot, never live within a boot). Files arrive world-readable (0444), directories traversable (0555), owned by root; host permission and executable bits are not preserved. It works identically on macOS and Linux (ADR-0015).
type Option ¶
Option is a functional option for configuring a VM.
func WithFixture ¶
WithFixture packs the host directory hostDir into the guest at guestPath as a read-only fixture: at boot the directory is snapshotted into an ext4 image, attached as a read-only block device, and mounted by the stock guest at guestPath. Call it more than once to add several fixtures. guestPath must be absolute; hostDir must exist and be a directory, and is resolved to an absolute path. The fixture set is frozen when the VM is first created and ignored when passed to an already-existing VM (exactly as cpu/memory/disk options are), but the content is rebuilt from hostDir on every boot. Files arrive world-readable, owned by root. In a StartN or StartCluster every member receives the same fixtures (ADR-0015).
type VM ¶
type VM struct {
// contains filtered or unexported fields
}
VM represents a running virtual machine.
func Start ¶
Start creates and boots a new VM with the given name. The orchestration runs client-side (image resolve, disk/seed/fixture build, store) and drives a VM helper over a unix socket; the helper is the downloaded, signed binary on macOS and a self-reexec of this binary on Linux (ADR-0020). If the VM already exists, the helper boots the existing VM. SSH dials the VM's IP directly.
func StartN ¶
StartN creates and boots N VMs with the given prefix (prefix-1, prefix-2, ...). All N VMs share ONE network, so they reach each other by IP — the cluster is interconnected (ADR-0008 macOS, ADR-0011 Linux). It is a thin wrapper over StartCluster with generated names.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
fleetbox
command
|
|
|
fleetbox-helper
command
On every platform but darwin/arm64 the helper is not a real binary: Linux runs the holder in-process by re-execing the CLI itself (no separate signed VM host is needed), and other platforms are unsupported.
|
On every platform but darwin/arm64 the helper is not a real binary: Linux runs the holder in-process by re-execing the CLI itself (no separate signed VM host is needed), and other platforms are unsupported. |
|
contrib
|
|
|
catalog
command
Command catalog refreshes the pinned cloud-image catalog (internal/image/catalog.json).
|
Command catalog refreshes the pinned cloud-image catalog (internal/image/catalog.json). |
|
Package fleetboxtest provides testing.T integration for fleetbox VMs.
|
Package fleetboxtest provides testing.T integration for fleetbox VMs. |
|
internal
|
|
|
backend
Package backend defines the interface for VM backends.
|
Package backend defines the interface for VM backends. |
|
backend/cloudhypervisor
Package cloudhypervisor implements the backend interface using cloud-hypervisor on Linux.
|
Package cloudhypervisor implements the backend interface using cloud-hypervisor on Linux. |
|
backend/fake
Package fake is a dumb, instant, pure-Go implementation of the backend interfaces used to exercise the cross-process coordination layer (client ↔ helper ↔ holder) on a CI runner that cannot boot a real VM.
|
Package fake is a dumb, instant, pure-Go implementation of the backend interfaces used to exercise the cross-process coordination layer (client ↔ helper ↔ holder) on a CI runner that cannot boot a real VM. |
|
backend/remote
Package remote is a pure-Go backend.Backend that drives a spawned helper over the control protocol instead of touching a hypervisor directly.
|
Package remote is a pure-Go backend.Backend that drives a spawned helper over the control protocol instead of touching a hypervisor directly. |
|
control
Package control is the client half of the holder protocol: it spawns a holder process, waits for its members to come up, and drives them (createnetwork/ reserve/boot-member/status/stop) over the per-member unix sockets.
|
Package control is the client half of the holder protocol: it spawns a holder process, waits for its members to come up, and drives them (createnetwork/ reserve/boot-member/status/stop) over the per-member unix sockets. |
|
dhcp
Package dhcp parses macOS dhcpd_leases file to discover VM IP addresses.
|
Package dhcp parses macOS dhcpd_leases file to discover VM IP addresses. |
|
fetch
Package fetch downloads and caches remote files (cloud images, VMM binaries, firmware), verifying an optional SHA256 and writing atomically so a cached file is always complete.
|
Package fetch downloads and caches remote files (cloud images, VMM binaries, firmware), verifying an optional SHA256 and writing atomically so a cached file is always complete. |
|
fixture
Package fixture packs a host directory into a read-only ext4 filesystem image for attaching to a VM as a block device (ADR-0015).
|
Package fixture packs a host directory into a read-only ext4 filesystem image for attaching to a VM as a block device (ADR-0015). |
|
helperdist
Package helperdist resolves the signed fleetbox-helper binary the darwin client drives: it returns a locally pre-staged helper named by the FLEETBOX_HELPER environment variable, or downloads the checksum-pinned helper for this platform into ~/.fleetbox/bin, strips its Gatekeeper quarantine, and makes it executable.
|
Package helperdist resolves the signed fleetbox-helper binary the darwin client drives: it returns a locally pre-staged helper named by the FLEETBOX_HELPER environment variable, or downloads the checksum-pinned helper for this platform into ~/.fleetbox/bin, strips its Gatekeeper quarantine, and makes it executable. |
|
holder
Package holder is the server half of the holder protocol: one process owns one cluster — its shared network and every VM on it — so a cluster gets the same VM↔VM connectivity the library StartN gives (ADR-0008).
|
Package holder is the server half of the holder protocol: one process owns one cluster — its shared network and every VM on it — so a cluster gets the same VM↔VM connectivity the library StartN gives (ADR-0008). |
|
image
Package image handles cloud image download, verification, and conversion.
|
Package image handles cloud image download, verification, and conversion. |
|
opts
Package opts holds the backend-neutral VM creation options.
|
Package opts holds the backend-neutral VM creation options. |
|
orchestrator
Package orchestrator owns the VM lifecycle CLIENT-SIDE: it resolves the per-call dependencies (store, SSH key, image), spawns the VM helper, creates the network and boots/waits/tears down members by driving that helper over the control protocol.
|
Package orchestrator owns the VM lifecycle CLIENT-SIDE: it resolves the per-call dependencies (store, SSH key, image), spawns the VM helper, creates the network and boots/waits/tears down members by driving that helper over the control protocol. |
|
seed
Package seed creates cloud-init NoCloud seed ISOs.
|
Package seed creates cloud-init NoCloud seed ISOs. |
|
sshkey
Package sshkey manages SSH key generation and provides an SSH client for VM access.
|
Package sshkey manages SSH key generation and provides an SSH client for VM access. |
|
store
Package store manages VM state directories under ~/.fleetbox/clusters/<cluster>/<member>/.
|
Package store manages VM state directories under ~/.fleetbox/clusters/<cluster>/<member>/. |
|
third_party
|
|