vm

package
v0.51.0 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsCgroupV2Available

func IsCgroupV2Available() bool

func SetVMLogMaxBytes

func SetVMLogMaxBytes(n int64)

SetVMLogMaxBytes sets the per-VM in-memory log capture limit in bytes. A non-positive value restores the 4 MiB default. Call once at daemon startup.

Types

type CgroupLimit

type CgroupLimit struct {
	CPUShares uint64
	MemoryMax int64
}

type CgroupManager

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

func NewCgroupManager

func NewCgroupManager(vmID string) *CgroupManager

func (*CgroupManager) Apply

func (m *CgroupManager) Apply(pid int, limits CgroupLimit) error

func (*CgroupManager) Remove

func (m *CgroupManager) Remove() error

type CommandFunc

type CommandFunc func(ctx context.Context, name string, args ...string) *exec.Cmd

CommandFunc builds an exec.Cmd. Defaults to exec.CommandContext; replaceable in tests.

type Config

type Config struct {
	// ImagePath is the raw disk image containing the kernel and application.
	ImagePath string
	// ImageRef is the image reference the VM was created from (e.g.
	// "flaskapp:latest"), preserved for display. Empty when the VM was started
	// from a raw ImagePath with no registered image.
	ImageRef string
	// Memory is the QEMU memory string (e.g. "256M").
	Memory string
	// CPUs is the number of virtual CPUs; 0 uses QEMU default.
	CPUs int
	// NetworkName is the TAP interface name to attach; empty disables networking.
	// Networking is TAP only (SLIRP is not supported), so PortMaps require a
	// non-empty NetworkName.
	NetworkName string
	// PortMaps is the list of host-to-guest port forwarding rules, published by
	// a userspace forwarder. Requires TAP networking (a non-empty NetworkName).
	PortMaps []PortMap
	// Env is a list of "KEY=VALUE" environment variable pairs injected at
	// boot time via QEMU fw_cfg. The kernel reads opt/uni/env to consume them.
	Env []string
	// Name is a human-readable identifier for the VM. If empty, the UUID is used.
	Name string
	// Volumes is the list of additional disk images to attach to the VM.
	Volumes []VolumeMount
	// Attach when true, creates a pipe for streaming serial console output.
	Attach bool
	// IPAddress is the static IP address to assign to the VM. Requires TAP
	// networking (NetworkName). If empty, no static IP is configured.
	IPAddress string
	// GatewayIP is the gateway IP for the VM's network. Derived from IPAddress
	// when using TAP networking. Used to assign an IP to the bridge interface.
	GatewayIP string
	// BridgeName is the Linux bridge interface name for the VM's network.
	// When set, the daemon creates/destroys this bridge on VM start/stop.
	BridgeName string
	// SubnetMask is the CIDR mask for the VM's network (e.g. "24").
	// Used to build the guest network configuration passed via fw_cfg.
	SubnetMask string
	// HealthCheck configures liveness probing for the VM. Nil disables probing.
	HealthCheck *HealthCheckConfig
	// Restart controls automatic restart behavior when the VM exits.
	Restart RestartConfig
	// CPUShares is the cgroup v2 CPU weight (1–10000). 0 means no limit.
	CPUShares uint64
	// MemoryMax is the cgroup v2 memory hard limit in bytes. 0 means no limit.
	MemoryMax int64
	// DiskIOPS is the maximum I/O operations per second for the boot disk (QEMU throttle). 0 means no limit.
	DiskIOPS uint64
	// DiskBPS is the maximum bytes per second for the boot disk (QEMU throttle). 0 means no limit.
	DiskBPS int64
}

Config holds the parameters used to create a VM.

type FCOption

type FCOption func(*FirecrackerManager)

FCOption configures a FirecrackerManager.

func WithFCCommandFunc

func WithFCCommandFunc(fn CommandFunc) FCOption

WithFCCommandFunc injects a custom command builder (for tests).

func WithFCStore

func WithFCStore(s Store) FCOption

WithFCStore injects a custom Store implementation.

type FileStore

type FileStore struct {
	MemoryStore
	// contains filtered or unexported fields
}

FileStore is a Store that persists VM state to disk as JSON files. It wraps a MemoryStore for in-memory lookups and mirrors every mutation to ~/.jerboa/vms/<id>/state.json.

func NewFileStore

func NewFileStore(dir string) *FileStore

NewFileStore returns a FileStore rooted at dir (~/.jerboa/vms). Call Restore() to load any previously persisted VMs.

func (*FileStore) Create

func (s *FileStore) Create(cfg Config) (*VM, error)

func (*FileStore) Remove

func (s *FileStore) Remove(id string) error

func (*FileStore) Restore

func (s *FileStore) Restore() error

Restore loads all persisted VMs from disk into memory. VMs that were in the "running" or "starting" state are marked as "stopped" with DaemonRecovered=true, since the QEMU process died with the daemon.

func (*FileStore) Save

func (s *FileStore) Save(v *VM) error

type FirecrackerManager

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

FirecrackerManager implements Manager by spawning firecracker processes configured via a JSON config file and managed via the Firecracker REST API over a per-VM Unix socket.

Limitations vs. QEMUManager:

  • TAP networking only (like QEMU now): port maps require a NetworkName and are rejected at Start otherwise. Publishing is done by the userspace forwarder, shared with QEMU.
  • DiskIOPS / DiskBPS throttling is not available (no Firecracker equivalent).
  • On Windows, Firecracker runs inside WSL2; KVM must be available in WSL2.
  • The kernel image must be a flat ELF vmlinux compatible with Firecracker (different from the BIOS-bootable kernel.img used by QEMU).

func NewFirecrackerManager

func NewFirecrackerManager(fcBin, kernelImage string, opts ...FCOption) *FirecrackerManager

NewFirecrackerManager returns a FirecrackerManager. fcBin is the path to the firecracker binary. kernelImage is the path to a Firecracker-compatible vmlinux ELF kernel.

func (*FirecrackerManager) Create

func (m *FirecrackerManager) Create(_ context.Context, cfg Config) (*VM, error)

Create registers a new VM with the given config.

func (*FirecrackerManager) Get

func (m *FirecrackerManager) Get(id string) (*VM, error)

Get returns the VM with the given id, name, or ID prefix.

func (*FirecrackerManager) Kill

Kill immediately terminates the firecracker process.

func (*FirecrackerManager) List

func (m *FirecrackerManager) List() []*VM

List returns all registered VMs.

func (*FirecrackerManager) Remove

func (m *FirecrackerManager) Remove(_ context.Context, id string) error

Remove deletes a stopped VM from the registry.

func (*FirecrackerManager) Signal

func (m *FirecrackerManager) Signal(_ context.Context, id string, sig os.Signal) error

Signal sends sig to the VM. SIGKILL kills the host process immediately; all other signals trigger a graceful SendCtrlAltDel via the Firecracker API, falling back to an OS-level signal on failure.

func (*FirecrackerManager) Start

func (m *FirecrackerManager) Start(ctx context.Context, id string) error

Start writes a Firecracker config file and launches the firecracker process. The VM boots immediately upon process start (no separate InstanceStart call needed).

func (*FirecrackerManager) Stop

func (m *FirecrackerManager) Stop(ctx context.Context, id string) error

Stop gracefully shuts down the VM via Firecracker's SendCtrlAltDel API action, falling back to SIGTERM → SIGKILL after gracePeriod.

func (*FirecrackerManager) Store

func (m *FirecrackerManager) Store() Store

Store returns the underlying Store.

type HealthCheckConfig

type HealthCheckConfig struct {
	// Type is "tcp" or "http". For HTTP, a GET request is made to Path.
	Type string
	// Port is the guest port to probe.
	Port int
	// Path is the HTTP path (only used when Type is "http").
	Path string
	// Interval between probes. Defaults to 10s if zero.
	Interval time.Duration
	// Timeout per probe. Defaults to 3s if zero.
	Timeout time.Duration
	// Retries is the number of consecutive failures before marking unhealthy.
	// Defaults to 3 if zero.
	Retries int
}

HealthCheckConfig defines how to probe a VM for liveness.

type HealthChecker

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

func NewHealthChecker

func NewHealthChecker() *HealthChecker

func (*HealthChecker) Start

func (h *HealthChecker) Start(ctx context.Context, v *VM)

func (*HealthChecker) Stop

func (h *HealthChecker) Stop(id string)

type HealthStatus

type HealthStatus string

HealthStatus represents the result of a health check probe.

const (
	// HealthHealthy means the probe succeeded.
	HealthHealthy HealthStatus = "healthy"
	// HealthUnhealthy means the probe failed.
	HealthUnhealthy HealthStatus = "unhealthy"
	// HealthStarting means the VM is within the grace period and not yet probed.
	HealthStarting HealthStatus = "starting"
	// HealthUnknown means no health check is configured.
	HealthUnknown HealthStatus = "unknown"
)

type Manager

type Manager interface {
	// Create registers a new VM with the given config.
	Create(ctx context.Context, cfg Config) (*VM, error)
	// Start launches the QEMU process for the VM with the given id.
	Start(ctx context.Context, id string) error
	// Stop gracefully shuts down the VM: SIGTERM, 30s grace, then SIGKILL.
	Stop(ctx context.Context, id string) error
	// Kill immediately sends SIGKILL to the VM process.
	Kill(ctx context.Context, id string) error
	// Signal sends an arbitrary OS signal to the VM process.
	Signal(ctx context.Context, id string, sig os.Signal) error
	// Remove deletes a stopped VM from the registry.
	Remove(ctx context.Context, id string) error
	// Get returns the VM with the given id.
	Get(id string) (*VM, error)
	// List returns all registered VMs.
	List() []*VM
}

Manager manages the lifecycle of unikernel VMs.

type MemoryStore

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

MemoryStore is a thread-safe in-memory registry of VMs.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore returns an empty in-memory Store.

func NewStore deprecated

func NewStore() *MemoryStore

NewStore returns an empty in-memory Store.

Deprecated: use NewMemoryStore for clarity.

func (*MemoryStore) Create

func (s *MemoryStore) Create(cfg Config) (*VM, error)

func (*MemoryStore) Get

func (s *MemoryStore) Get(id string) (*VM, error)

func (*MemoryStore) List

func (s *MemoryStore) List() []*VM

func (*MemoryStore) Remove

func (s *MemoryStore) Remove(id string) error

func (*MemoryStore) Resolve

func (s *MemoryStore) Resolve(nameOrID string) (*VM, error)

func (*MemoryStore) Restore

func (s *MemoryStore) Restore() error

Restore is a no-op for MemoryStore; there is nothing to restore from.

func (*MemoryStore) Save

func (s *MemoryStore) Save(_ *VM) error

Save is a no-op for MemoryStore; state lives only in memory.

type Migrator

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

func NewMigrator

func NewMigrator(fileRoot string, sqliteDB *SQLiteStore) *Migrator

func (*Migrator) Migrate

func (m *Migrator) Migrate() (int, error)

type MockManager

type MockManager struct {
	CreateFn func(ctx context.Context, cfg Config) (*VM, error)
	StartFn  func(ctx context.Context, id string) error
	StopFn   func(ctx context.Context, id string) error
	KillFn   func(ctx context.Context, id string) error
	SignalFn func(ctx context.Context, id string, sig os.Signal) error
	RemoveFn func(ctx context.Context, id string) error
	GetFn    func(id string) (*VM, error)
	ListFn   func() []*VM
	// contains filtered or unexported fields
}

func NewMockManager

func NewMockManager() *MockManager

func (*MockManager) Create

func (m *MockManager) Create(ctx context.Context, cfg Config) (*VM, error)

func (*MockManager) Get

func (m *MockManager) Get(id string) (*VM, error)

func (*MockManager) Kill

func (m *MockManager) Kill(ctx context.Context, id string) error

func (*MockManager) List

func (m *MockManager) List() []*VM

func (*MockManager) Remove

func (m *MockManager) Remove(ctx context.Context, id string) error

func (*MockManager) Signal

func (m *MockManager) Signal(ctx context.Context, id string, sig os.Signal) error

func (*MockManager) Start

func (m *MockManager) Start(ctx context.Context, id string) error

func (*MockManager) Stop

func (m *MockManager) Stop(ctx context.Context, id string) error

type NoopStatsCollector

type NoopStatsCollector struct {
	ID    string
	State string
}

NoopStatsCollector returns fallback stats when no collector is available.

func (NoopStatsCollector) Collect

func (n NoopStatsCollector) Collect() RuntimeStats

type Option

type Option func(*QEMUManager)

Option configures a QEMUManager.

func WithCommandFunc

func WithCommandFunc(fn CommandFunc) Option

WithCommandFunc injects a custom command builder (for tests).

func WithStore

func WithStore(s Store) Option

WithStore injects a custom Store implementation (e.g. FileStore for persistence).

type PortMap

type PortMap struct {
	// HostPort is the port on the host to listen on.
	HostPort uint16
	// GuestPort is the port inside the VM to forward to.
	GuestPort uint16
	// Protocol is "tcp" or "udp"; defaults to "tcp".
	Protocol PortProtocol
}

PortMap describes a single host-to-guest port forwarding rule.

func ParsePortMap

func ParsePortMap(s string) (PortMap, error)

ParsePortMap parses a port mapping string in one of these forms:

"8080:80"        → tcp, host=8080, guest=80
"8080:80/tcp"    → tcp, host=8080, guest=80
"5353:53/udp"    → udp, host=5353, guest=53

func ParsePortMaps

func ParsePortMaps(specs []string) ([]PortMap, error)

ParsePortMaps parses multiple port mapping strings (e.g. from CLI -p flags).

func (PortMap) String

func (p PortMap) String() string

String returns the canonical "host:guest/proto" representation.

type PortProtocol

type PortProtocol string

PortProtocol is the transport layer protocol for a port mapping.

const (
	// ProtocolTCP is the TCP protocol.
	ProtocolTCP PortProtocol = "tcp"
	// ProtocolUDP is the UDP protocol.
	ProtocolUDP PortProtocol = "udp"
)

type ProcStatsCollector

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

ProcStatsCollector reads /proc/[pid]/ io files for CPU, memory, and I/O stats.

func (*ProcStatsCollector) Collect

func (c *ProcStatsCollector) Collect() RuntimeStats

type QEMUManager

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

QEMUManager implements Manager by spawning qemu-system-x86_64 processes.

func NewQEMUManager

func NewQEMUManager(qemuBin string, opts ...Option) *QEMUManager

NewQEMUManager returns a QEMUManager using qemuBin as the QEMU executable.

func (*QEMUManager) Create

func (m *QEMUManager) Create(_ context.Context, cfg Config) (*VM, error)

Create registers a new VM with the given config.

func (*QEMUManager) Get

func (m *QEMUManager) Get(id string) (*VM, error)

Get returns the VM with the given id, name, or ID prefix.

func (*QEMUManager) Kill

func (m *QEMUManager) Kill(_ context.Context, id string) error

Kill immediately sends SIGKILL to the VM process.

func (*QEMUManager) List

func (m *QEMUManager) List() []*VM

List returns all registered VMs.

func (*QEMUManager) Remove

func (m *QEMUManager) Remove(_ context.Context, id string) error

Remove deletes a stopped VM from the registry.

func (*QEMUManager) Signal

func (m *QEMUManager) Signal(_ context.Context, id string, sig os.Signal) error

Signal sends sig to the VM. SIGKILL terminates the QEMU host process immediately (cross-platform). All other signals request graceful guest shutdown via QEMU QMP (system_powerdown sends an ACPI power-button event); if QMP is unavailable the call falls back to an OS-level signal (Linux/macOS only).

func (*QEMUManager) Start

func (m *QEMUManager) Start(ctx context.Context, id string) error

Start launches the QEMU process for the VM identified by id. The ctx parameter controls the command lifecycle; canceling ctx will kill the QEMU process via exec.CommandContext.

func (*QEMUManager) Stop

func (m *QEMUManager) Stop(ctx context.Context, id string) error

Stop gracefully shuts down the VM: sends SIGTERM, waits up to gracePeriod, then kills if still running.

func (*QEMUManager) Store

func (m *QEMUManager) Store() Store

Store returns the underlying Store for lifecycle operations like Restore.

type RestartConfig

type RestartConfig struct {
	// Policy is the restart policy: "never", "on-failure", or "always".
	Policy RestartPolicy
	// MaxRetries is the maximum number of restart attempts. 0 means unlimited.
	MaxRetries int
}

RestartConfig controls automatic VM restart behavior.

type RestartPolicy

type RestartPolicy string

RestartPolicy determines when a VM is automatically restarted after exiting.

const (
	// RestartNever means the VM is never automatically restarted.
	RestartNever RestartPolicy = "never"
	// RestartOnFailure means the VM is restarted only if it exits with a non-zero
	// exit code (crash).
	RestartOnFailure RestartPolicy = "on-failure"
	// RestartAlways means the VM is always restarted regardless of exit status,
	// unless explicitly stopped.
	RestartAlways RestartPolicy = "always"
)

type RuntimeStats

type RuntimeStats struct {
	ID         string
	State      string
	CPUPct     float64
	MemBytes   int64
	DiskBytes  int64
	NetRxBytes int64
	NetTxBytes int64
	Timestamp  time.Time
	Source     string
}

RuntimeStats holds runtime resource usage for a VM.

type SQLiteStore

type SQLiteStore struct {
	MemoryStore
	// contains filtered or unexported fields
}

func NewSQLiteStore

func NewSQLiteStore(dsn string) (*SQLiteStore, error)

func (*SQLiteStore) Close

func (s *SQLiteStore) Close() error

func (*SQLiteStore) Create

func (s *SQLiteStore) Create(cfg Config) (*VM, error)

func (*SQLiteStore) Remove

func (s *SQLiteStore) Remove(id string) error

func (*SQLiteStore) Restore

func (s *SQLiteStore) Restore() error

func (*SQLiteStore) Save

func (s *SQLiteStore) Save(v *VM) error

type State

type State string

State represents a VM lifecycle state.

const (
	// StateCreated is the initial state after registration.
	StateCreated State = "created"
	// StateStarting means the QEMU process is being launched.
	StateStarting State = "starting"
	// StateRunning means the QEMU process is alive.
	StateRunning State = "running"
	// StateStopping means a kill signal has been sent.
	StateStopping State = "stopping"
	// StateStopped means the QEMU process has exited.
	StateStopped State = "stopped"
)

type StatsCollector

type StatsCollector interface {
	Collect() RuntimeStats
}

StatsCollector provides runtime resource usage for a VM process.

type Store

type Store interface {
	Create(cfg Config) (*VM, error)
	Get(id string) (*VM, error)
	Resolve(nameOrID string) (*VM, error)
	List() []*VM
	Remove(id string) error
	Save(v *VM) error
	Restore() error
}

Store is the interface for a VM registry. Implementations may persist state to disk (FileStore) or keep it in memory only (MemoryStore).

type VM

type VM struct {
	// ID uniquely identifies the VM.
	ID string
	// Cfg is the configuration the VM was created with.
	Cfg Config
	// State is the current lifecycle state.
	State State
	// CreatedAt is when the VM was registered.
	CreatedAt time.Time
	// StartedAt is when the QEMU process started (nil until then).
	StartedAt *time.Time
	// StoppedAt is when the QEMU process exited (nil until then).
	StoppedAt *time.Time
	// DaemonRecovered is true when this VM was recovered from a previous
	// daemon run. The original QEMU process is gone; the VM is in StateStopped.
	DaemonRecovered bool
	// HealthStatus is the latest probe result. "unknown" if no health check.
	HealthStatus HealthStatus
	// RestartCount is the number of times this VM has been restarted.
	RestartCount int
	// contains filtered or unexported fields
}

VM is a managed unikernel instance. All exported fields are read-only after Start; internal mutation is guarded by mu.

func (*VM) AttachReader

func (v *VM) AttachReader() io.Reader

AttachReader returns a reader that streams QEMU serial console output. Returns nil if no attach pipe was created (VM not started in attach mode).

func (*VM) Done

func (v *VM) Done() <-chan struct{}

Done returns a channel that is closed when the VM reaches StateStopped.

func (*VM) GetHealthStatus

func (v *VM) GetHealthStatus() HealthStatus

GetHealthStatus returns the current health status under a read lock.

func (*VM) GetRestartCount

func (v *VM) GetRestartCount() int

GetRestartCount returns the number of times this VM has been restarted.

func (*VM) GetState

func (v *VM) GetState() State

GetState returns the current state under a read lock.

func (*VM) GetTimes

func (v *VM) GetTimes() (startedAt, stoppedAt *time.Time)

GetTimes returns the start and stop timestamps under a read lock.

func (*VM) IsExplicitStop

func (v *VM) IsExplicitStop() bool

IsExplicitStop returns whether the VM was explicitly stopped.

func (*VM) Logs

func (v *VM) Logs() []byte

Logs returns a snapshot of captured QEMU serial console output.

func (*VM) SetExplicitStop

func (v *VM) SetExplicitStop()

SetExplicitStop marks the VM as explicitly stopped by the user. When true, the monitor goroutine will not attempt to restart the VM.

func (*VM) SetHealthStatus

func (v *VM) SetHealthStatus(s HealthStatus)

SetHealthStatus sets the health status under a write lock.

func (*VM) SetStatsProvider

func (v *VM) SetStatsProvider(fn func() RuntimeStats)

SetStatsProvider sets the function that returns live VM stats.

func (*VM) Stats

func (v *VM) Stats() RuntimeStats

Stats returns the current runtime stats for the VM. If no stats provider is available, it returns a minimal snapshot.

type VolumeMount

type VolumeMount struct {
	// DiskPath is the absolute path to the raw disk image on the host.
	DiskPath string
	// GuestPath is the mount point inside the VM. The hypervisor passes
	// "Label:GuestPath" to the guest kernel (QEMU fw_cfg opt/uni/mounts or
	// Firecracker boot args) so the volume is mounted there.
	GuestPath string
	// ReadOnly marks the volume as read-only.
	ReadOnly bool
	// Label is the volume's TFS filesystem label, used by the guest kernel's
	// volume_match to bind this disk to GuestPath. Empty volumes are skipped
	// for mount injection (attached as a bare block device only).
	Label string
}

VolumeMount describes a volume attached to a VM.

Jump to

Keyboard shortcuts

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