mvmctl docs
API Reference
Every CLI command maps 1:1 to a static method on an *Operation class in mvmctl.api.*. Import the API directly to build automation scripts, GUIs, or TUIs without going through the CLI.
Overview
Every CLI command maps 1:1 to a static method on an *Operation class in mvmctl.api.*. The CLI is a thin presentation layer — it handles argument parsing, output formatting, and exit codes, then calls the same functions documented here.
You can import the API directly to build automation scripts, GUIs, or TUIs without going through the CLI. All system interactions (KVM, iptables, bridge devices) happen lazily — importing the package has no side effects.
Installation
Terminal
# From source
git clone https://github.com/AlanD20/mvmctl
cd mvmctl
uv syncImport Pattern
All public types are re-exported from mvmctl.api. Deep imports from sub-modules are not part of the public API.
Correct import
Terminal
from mvmctl.api import VMOperation, VMCreateInput
VMOperation.create(VMCreateInput(name="my-vm", ssh_keys=["my-key"], ...))Avoid deep imports
Terminal
from mvmctl.api.vm_operations import VMOperation # ❌ WRONG — use mvmctl.api insteadModule Overview
| Operation Class | Responsibility |
|---|---|
VMOperation | VM lifecycle: create, remove, list_all, get, start, stop, pause, resume, reboot, snapshot, load_snapshot, inspect, export, import_, prune, attach_volume, detach_volume |
NetworkOperation | Network management: create, remove, list_all, get, set_default, inspect, sync, create_default_network, prune |
ImageOperation | Image operations: pull, import_, remove, list_all, get, set_default, inspect, warm, find_existing_image, prune |
KernelOperation | Kernel operations: pull, list_all, get, set_default, remove, inspect, prune |
KeyOperation | SSH key registry: add, create, list_all, get, inspect, remove, set_default, get_defaults, clear_defaults, export |
BinaryOperation | Binary management: pull, list_all, get, set_default, remove, remove_by_version, ensure_default, prune |
HostOperation | Host init/clean/reset, privilege checks, KVM access, binary checks, state, get_running_vms, get_ip_forward_status, check_kvm_access, check_required_binaries, get_state |
CacheOperation | Cache lifecycle: init_all, prune_vms, prune_networks, prune_images, prune_kernels, prune_binaries, prune_misc, prune_all, clean |
ConsoleOperation | Console access: get_connection_info, get_state, kill |
LogOperation | Log streaming: stream (boot/OS logs following) |
VolumeOperation | Volume management: create, remove, list_all, get, inspect, resize |
ConfigOperation | Config management: get, set, reset, list_all |
CPOperation | File copy operations between host and microVMs (tar-over-SSH) |
SSHOperation | SSH connection (interactive or command execution) |
InitOperation | Onboarding wizard API: run, init_database, setup_host |
Data Models
VM Models VMStatus
All data models are in mvmctl.models.*. Models are pure dataclasses with no business logic. Every domain record uses the *Item suffix.
| Field | Type | Description |
|---|---|---|
STARTING | "starting" | VM is starting up |
RUNNING | "running" | VM is running |
PAUSED | "paused" | VM is paused |
STOPPING | "stopping" | VM is shutting down |
STOPPED | "stopped" | VM is stopped |
CRASHED | "crashed" | VM has crashed |
ERROR | "error" | VM is in error state |
VMInstanceItem VMInstanceItem
| Field | Type | Description |
|---|---|---|
id | str | VM ID (hash) |
name | str | VM name; used as hostname inside guest |
status | str | Current lifecycle state |
pid | int | Firecracker process PID |
ipv4 | str | Assigned guest IP address |
mac | str | Assigned guest MAC address |
network_id | str | Network ID this VM is attached to |
tap_device | str | Host TAP interface name |
image_id | str | Image ID |
kernel_id | str | Kernel ID |
binary_id | str | Firecracker/jailer binary ID |
api_socket_path | str | Path to Firecracker API Unix socket |
config_path | str | Path to Firecracker JSON config |
cloud_init_mode | str | Cloud-init mode used |
vcpu_count | int | Number of vCPUs |
mem_size_mib | int | Memory in MiB |
disk_size_mib | int | Rootfs disk size in MiB |
rootfs_path | str | Path to rootfs image |
rootfs_suffix | str | Rootfs file suffix (e.g. .ext4) |
pci_enabled | bool | Whether PCI support is enabled |
nested_virt | bool | Nested virtualization enabled |
enable_logging | bool | Whether Firecracker logging is enabled |
enable_metrics | bool | Whether Firecracker metrics are enabled |
enable_console | bool | Whether serial console is enabled |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 update timestamp |
exit_code | int | None | Firecracker process exit code |
log_path | str | None | Path to Firecracker log file |
serial_output_path | str | None | Path to serial console log |
nocloud_net_port | int | None | Port for nocloud-net HTTP server |
nocloud_net_pid | int | None | PID of nocloud-net server |
relay_pid | int | None | PID of console relay process |
relay_socket_path | str | None | Path to console relay Unix socket |
process_start_time | int | None | Firecracker process start timestamp (epoch ms) |
lsm_flags | str | None | Linux Security Module flags |
boot_args | str | None | Custom kernel boot arguments |
ssh_keys | list[str] | SSH key names injected into the VM |
ssh_user | str | None | Default SSH user for the VM |
volume_ids | list[str] | None | Attached volume IDs |
cpu_config | CpuConfig | None | CPU template configuration (merged CPU config) |
Resolved relations (populated on request):
| Field | Type | Description |
|---|---|---|
kernel | KernelItem | None | Resolved kernel record |
image | ImageItem | None | Resolved image record |
binary | BinaryItem | None | Resolved binary record |
network | NetworkItem | None | Resolved network record |
volumes | list[VolumeItem] | Resolved volume records |
NetworkItem NetworkItem
| Field | Type | Description |
|---|---|---|
id | str | Network ID (hash) |
name | str | Network name |
subnet | str | IP subnet in CIDR notation |
bridge | str | Linux bridge device name |
ipv4_gateway | str | Host-side gateway IP |
bridge_active | bool | Whether bridge device exists |
nat_enabled | bool | Whether NAT rules are active |
is_default | bool | Whether this is the default network |
is_present | bool | Whether the network is present on the host |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 last update timestamp |
deleted_at | str | None | ISO 8601 soft-delete timestamp |
nat_gateways | str | None | Comma-separated physical NAT interfaces |
leases | list[NetworkLeaseItem] | None | IP leases associated with this network |
iptables_rules | list[FirewallRule] | None | Firewall rules associated with this network |
vms | list[VMInstanceItem] | None | VMs attached to this network for relation enrichment |
ImageItem ImageItem
| Field | Type | Description |
|---|---|---|
id | str | Image ID (SHA256 hash) |
type | str | Image type identifier (e.g. ubuntu, alpine, debian) |
version | str | Image version string (e.g. 24.04) |
name | str | Human-readable image name |
arch | str | Architecture (e.g. x86_64, arm64) |
path | str | Relative path to image file |
fs_type | str | Filesystem type (e.g. ext4, btrfs) |
minimum_rootfs_size_mib | int | Minimum rootfs size in MiB |
original_size | int | Original uncompressed size in bytes |
is_default | bool | Whether this is the default image |
is_present | bool | Whether the file exists on disk |
pulled_at | str | ISO 8601 download timestamp |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 last update timestamp |
distro | str | None | Detected Linux distribution (e.g. ubuntu) |
fs_uuid | str | None | Filesystem UUID |
compressed_size | int | None | Compressed size in bytes |
compression_ratio | float | None | Compression ratio |
compressed_format | str | None | Compression format (e.g. zst) |
deleted_at | str | None | ISO 8601 soft-delete timestamp |
vms | list[VMInstanceItem] | None | VMs referencing this image for relation enrichment |
KernelItem KernelItem
| Field | Type | Description |
|---|---|---|
id | str | Kernel ID (SHA256 hash) |
name | str | Full filename display name |
base_name | str | Base kernel name (e.g. vmlinux-firecracker) |
version | str | Kernel version string |
arch | str | Architecture (x86_64, arm64) |
type | str | Kernel type: firecracker or official |
path | str | Relative path to kernel file |
is_default | bool | Whether this is the default kernel |
is_present | bool | Whether the file exists on disk |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 last update timestamp |
deleted_at | str | None | ISO 8601 soft-delete timestamp |
vms | list[VMInstanceItem] | None | VMs using this kernel for relation enrichment |
KernelPullResult KernelPullResult
Unified result from kernel pull/build operations. Provides a consistent return type for both Firecracker download and official kernel build paths.
| Field | Type | Description |
|---|---|---|
path | Path | Path to the built/fetched vmlinux |
version | str | Kernel version string |
arch | str | Architecture |
kernel_type | str | Kernel type: firecracker or official |
warnings | list[str] | Build warnings |
info_messages | list[str] | Informational messages |
BinaryItem BinaryItem
| Field | Type | Description |
|---|---|---|
id | str | Binary ID (SHA256 hash) |
name | str | Binary name: firecracker or jailer |
version | str | Semantic version string |
full_version | str | Full version string with metadata |
ci_version | str | None | Firecracker CI version tag |
path | str | Relative path to binary file |
is_default | bool | Whether this is the active default binary |
is_present | bool | Whether the file exists on disk |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 last update timestamp |
deleted_at | str | None | ISO 8601 soft-delete timestamp |
vms | list[VMInstanceItem] | None | VMs using this binary for relation enrichment |
VolumeItem VolumeItem
A persistent data disk attachable to VMs. Each volume has a name, size, format, and an attached status.
| Field | Type | Description |
|---|---|---|
id | str | Volume ID (SHA256 hash of name + timestamp) |
name | str | Volume name (used in --volume flag) |
size_bytes | int | Volume size in bytes |
format | str | Disk format: raw or qcow2 |
path | str | Relative path to volume disk file |
status | VolumeStatus | Current status: AVAILABLE or ATTACHED |
vm_id | str | None | VM ID this volume is attached to, if any |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 last update timestamp |
is_read_only | bool | Whether the volume is mounted read-only |
SSHKeyItem SSHKeyItem
| Field | Type | Description |
|---|---|---|
id | str | Key ID (SHA256 hash) |
name | str | Key name (used in --ssh-key) |
fingerprint | str | SHA256 fingerprint |
algorithm | str | Key algorithm (ed25519, rsa, ecdsa) |
comment | str | SSH key comment |
public_key_path | str | Path to .pub file |
is_default | bool | Whether this is a default key |
is_present | bool | Whether the key file exists on disk |
created_at | str | ISO 8601 creation timestamp |
updated_at | str | ISO 8601 last update timestamp |
private_key_path | str | None | Path to private key file |
NetworkLeaseItem NetworkLeaseItem
| Field | Type | Description |
|---|---|---|
id | int | None | Lease ID |
network_id | str | Network ID this lease belongs to |
ipv4 | str | Leased IPv4 address |
vm_id | str | None | VM ID this lease is assigned to |
leased_at | str | ISO 8601 lease timestamp |
expires_at | str | None | ISO 8601 lease expiry timestamp |
FirewallRule FirewallRule
| Field | Type | Description |
|---|---|---|
id | int | None | Rule ID |
table_name | FirewallTable | Firewall table (filter, nat, mangle, raw, security) |
chain_name | FirewallChain | Firewall chain name |
rule_type | FirewallRuleType | Rule type: masquerade, forward_in, forward_out, nocloudnet_input |
protocol | FirewallProtocol | Protocol: tcp, udp, icmp, all |
source | str | Source CIDR or IP |
destination | str | Destination CIDR or IP |
in_interface | str | Input interface |
out_interface | str | Output interface |
target | FirewallTarget | Firewall target: ACCEPT, DROP, MASQUERADE, etc. |
sport | int | Source port |
dport | int | Destination port |
network_id | str | Network ID this rule belongs to |
is_active | bool | Whether the rule is currently active |
network_name | str | None | Network name |
command_string | str | None | Full iptables command string |
comment_tag | str | None | iptables comment tag |
created_at | str | None | ISO 8601 creation timestamp |
last_verified_at | str | None | ISO 8601 last verification timestamp |
VMExportComputeConfig VMExportComputeConfig
Compute resources configuration for VM export (vcpus, memory). Used as a sub-config within VMExportConfig.
| Field | Type | Description |
|---|---|---|
vcpus | int | None | Number of vCPUs |
mem | int | None | Memory in MiB |
VMExportImageConfig VMExportImageConfig
Image specification using portable semantic refs (type, arch, disk_size). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
type | str | None | Image type (e.g. ubuntu-24.04) |
arch | str | None | Architecture (e.g. x86_64) |
disk_size | str | None | Rootfs disk size (e.g. 2G) |
VMExportKernelConfig VMExportKernelConfig
Kernel specification using portable semantic refs (version, arch, type). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
version | str | None | Kernel version (e.g. 6.1.0) |
arch | str | None | Architecture (e.g. x86_64) |
type | str | None | Kernel type: vmlinux or bzImage |
VMExportBinaryConfig VMExportBinaryConfig
Firecracker binary specification using portable semantic refs (name, version). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
name | str | Binary name: firecracker |
version | str | None | Semantic version string (e.g. v1.15.0) |
VMExportNetworkConfig VMExportNetworkConfig
Network configuration with portable semantic refs (name, subnet, gateway, NAT). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
name | str | None | Network name (e.g. default) |
subnet | str | None | Subnet in CIDR notation (e.g. 172.27.0.0/24) |
ipv4_gateway | str | None | Gateway IPv4 (e.g. 172.27.0.1) |
nat_gateways | str | None | Comma-separated NAT gateway interfaces |
nat_enabled | bool | None | Whether NAT rules are enabled |
ip | str | None | Assigned guest IP |
mac | str | None | Assigned guest MAC |
VMExportBootConfig VMExportBootConfig
Boot configuration (kernel args, console). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
args | str | None | Kernel boot arguments |
enable_console | bool | None | Whether serial console is enabled |
VMExportFirecrackerConfig VMExportFirecrackerConfig
Firecracker feature flags for VM export (PCI, LSM, nested virt, CPU config). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
enable_api_socket | bool | None | Whether the API socket is enabled |
pci_enabled | bool | None | Whether PCI support is enabled |
lsm_flags | str | None | Linux Security Module flags |
nested_virt | bool | None | Whether nested virtualization is enabled |
cpu_config | str | None | JSON string of merged CPU template config |
VMExportCloudInitConfig VMExportCloudInitConfig
Cloud-init configuration for VM export (mode, user, SSH key). Part of VMExportConfig.
| Field | Type | Description |
|---|---|---|
mode | str | None | Cloud-init mode: inject, iso, net, off |
user | str | None | SSH user |
ssh_key | str | None | SSH key name or path |
keep_iso | bool | None | Retain cloud-init ISO after boot |
nocloud_net_port | int | None | Port for nocloud-net server (0 or None = auto-assign) |
VMExportConfig VMExportConfig
Portable VM configuration for export/import across hosts. Uses semantic field references (type, version, name) — NEVER internal IDs. On import, the API layer resolves semantic refs to actual paths via DB queries.
| Field | Type | Description |
|---|---|---|
schema_version | str | Schema version (fixed: 1.0) |
name | str | VM name |
compute | VMExportComputeConfig | Compute resources sub-config |
image | VMExportImageConfig | Image specification sub-config |
kernel | VMExportKernelConfig | Kernel specification sub-config |
binary | VMExportBinaryConfig | Binary specification sub-config |
network | VMExportNetworkConfig | Network configuration sub-config |
boot | VMExportBootConfig | Boot configuration sub-config |
firecracker | VMExportFirecrackerConfig | Firecracker feature flags sub-config |
cloud_init | VMExportCloudInitConfig | Cloud-init configuration sub-config |
Error Handling
All exceptions derive from mvmctl.exceptions.MVMError.
Example
Terminal
from mvmctl.api import NetworkOperation, NetworkCreateInput
from mvmctl.exceptions import MVMError, NetworkError
try:
result = NetworkOperation.create(
NetworkCreateInput(name="my-net", subnet="192.168.100.0/24")
)
except NetworkError as e:
print(f"Network setup failed: {e}")
except MVMError as e:
print(f"Unexpected MVM error: {e}")VMOperation
All methods are @staticmethod. VM instances are identified using VMInput objects.
VMOperation.create(inputs: VMCreateInput, *, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[list[VMInstanceItem]] | NeedsInteraction
Create and start a new Firecracker microVM. Copies the rootfs image, generates cloud-init data, sets up bridge networking, writes the Firecracker JSON config, starts the Firecracker process, and registers the VM in the database.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | — | VM name (required) |
inputs.ssh_keys | list[str] | — | SSH key names to inject |
inputs.image | str | None | None | Image name/ID or path |
inputs.kernel_id | str | None | None | Kernel ID (DB-backed default) |
inputs.vcpu_count | int | None | None | Number of vCPUs |
inputs.mem_size_mib | int | None | None | Memory in MiB |
inputs.network_name | str | None | None | Network name |
inputs.cloud_init_mode | str | None | None | off, inject, iso, or net (resolved to off by default) |
inputs.user | str | None | None | Default SSH user |
inputs.disk_size | str | None | None | Rootfs disk size (e.g. 1G) |
inputs.requested_guest_ip | str | None | None | Guest IP address |
inputs.requested_guest_mac | str | None | None | Guest MAC address |
inputs.custom_user_data | Path | None | None | Custom cloud-init user-data file |
inputs.nocloud_net_port | int | None | None | Port for nocloud-net server |
inputs.pci_enabled | bool | None | None | Enable PCI support |
inputs.nested_virt | bool | None | None | Enable nested virtualization |
inputs.cpu_config | CpuConfig | None | None | Pre-resolved CPU configuration (from import) |
inputs.enable_logging | bool | None | None | Enable Firecracker logging |
inputs.enable_metrics | bool | None | None | Enable Firecracker metrics |
inputs.enable_console | bool | None | None | Enable serial console (DB-backed default) |
inputs.lsm_flags | str | None | None | Linux Security Module flags |
inputs.boot_args | str | None | None | Custom kernel boot arguments |
inputs.firecracker_bin | str | None | None | Path to Firecracker binary |
inputs.binary_id | str | None | None | Firecracker/jailer binary ID |
inputs.skip_cleanup | bool | False | Skip cleanup on failure |
inputs.skip_ci_network_config | bool | False | Skip cloud-init network config |
inputs.keep_cloud_init_iso | bool | False | Keep cloud-init ISO after creation |
inputs.skip_deblob | bool | False | Skip OS cache cleanup (deblob) |
inputs.count | int | None | None | Number of VMs to create (batch mode) |
inputs.atomic | bool | False | Roll back all VMs if any creation fails (batch mode) |
inputs.volumes | list[str] | None | None | Volume names to attach on creation |
inputs.cloud_init_iso_path | Path | None | None | Path to a pre-built cloud-init ISO |
Raises: VMCreateError, NetworkError, FirecrackerSpawnError, PrivilegeError
Example
Terminal
from mvmctl.api import VMOperation, VMCreateInput
VMOperation.create(
VMCreateInput(
name="my-vm",
ssh_keys=["my-key"],
vcpu_count=2,
mem_size_mib=2048,
image="ubuntu:24.04",
)
)VMOperation.remove(inputs: VMInput) -> BatchResult[VMInstanceItem]
Stop and remove one or more VMs. Sends SIGTERM (graceful shutdown), then SIGKILL if still running. Tears down TAP device and iptables rules.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.identifiers | list[str] | [] | VM identifiers (names or IDs) to remove |
inputs.force | bool | False | Skip graceful shutdown |
VMOperation.list_all(status: VMStatus | list[VMStatus] | None = None) -> list[VMInstanceItem]
Return all registered VMs, optionally filtered by status.
VMOperation.get(inputs: VMInput) -> VMInstanceItem
Look up a single VM by name, ID, IP, or MAC.
Raises: VMNotFoundError if not found or ambiguous.
VMOperation.start(inputs: VMInput) -> BatchResult[VMInstanceItem]
Start one or more stopped VMs.
VMOperation.stop(inputs: VMInput) -> BatchResult[VMInstanceItem]
Stop one or more running VMs gracefully.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.force | bool | False | Skip graceful shutdown |
VMOperation.pause(inputs: VMInput) -> BatchResult[VMInstanceItem]
Pause one or more running VMs.
VMOperation.resume(inputs: VMInput) -> BatchResult[VMInstanceItem]
Resume one or more paused VMs.
VMOperation.reboot(inputs: VMInput) -> BatchResult[VMInstanceItem]
Reboot one or more VMs.
VMOperation.snapshot(inputs: VMInput, mem_out: Path, state_out: Path) -> OperationResult[VMInstanceItem]
Create a snapshot of a single VM's memory and state. Requires memory and state file output paths.
VMOperation.load_snapshot(inputs: VMInput, mem_in: Path, state_in: Path, resume_after: bool | None = None) -> OperationResult[VMInstanceItem]
Load a VM from memory and state snapshot files. Optionally resume after loading.
VMOperation.inspect(inputs: VMInput) -> dict[str, Any]
Show detailed information about a VM including all paths, features, and relations.
VMOperation.export(inputs: VMInput) -> VMExportConfig
Export a VM's configuration to a portable VMExportConfig object.
VMOperation.import_(inputs: VMImportInput, *, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[VMInstanceItem] | NeedsInteraction
Create a VM from a portable config file. Resolves images, kernels, binaries, and networks.
VMOperation.prune(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune VMs based on their status. By default, removes all VMs EXCEPT those in RUNNING or STARTING state. Use include_all=True to prune ALL VMs regardless of state.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
dry_run | bool | False | Only report what would be removed, without actually removing |
include_all | bool | False | Prune ALL VMs including RUNNING and STARTING |
VMOperation.attach_volume(vm_inputs: VMInput, volume_name: str) -> OperationResult[VMInstanceItem]
Attach a volume to a running VM. Updates the VM record so the volume is included on next start.
VMOperation.detach_volume(vm_inputs: VMInput, volume_name: str) -> OperationResult[VMInstanceItem]
Detach a volume from a running VM. Updates the VM record so the volume is excluded on next start.
NetworkOperation
All methods are @staticmethod. Networks are identified using NetworkInput objects.
NetworkOperation.create(inputs: NetworkCreateInput) -> OperationResult[NetworkItem] | NeedsInteraction
Create a named bridge network: sets up the bridge device, assigns the gateway IP, optionally configures NAT rules.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | — | Network name (must be unique) |
inputs.subnet | str | — | Subnet in CIDR notation |
inputs.ipv4_gateway | str | None | None | Gateway IPv4 for the bridge |
inputs.nat_enabled | bool | True | Configure NAT/masquerade |
inputs.nat_gateways | list[str] | [] | Physical interfaces for NAT |
NetworkOperation.remove(inputs: NetworkInput, force: bool = False) -> OperationResult[NetworkItem]
Remove a named network: tears down bridge and NAT rules, removes persisted state.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
force | bool | False | Remove even if VMs reference it |
NetworkOperation.list_all() -> list[NetworkItem]
List all named networks with lease enrichment.
NetworkOperation.get(inputs: NetworkInput) -> NetworkItem
Get a single network by name or ID.
Raises: NetworkError if not found or ambiguous.
NetworkOperation.set_default(inputs: NetworkInput) -> OperationResult[NetworkItem]
Set a network as the default for VM creation.
NetworkOperation.inspect(inputs: NetworkInput) -> dict[str, Any]
Show detailed network information including leases and iptables rules.
NetworkOperation.sync(network_id: str | None = None) -> OperationResult[dict[str, dict[str, int]]]
Sync iptables rules between database and host. Optionally target a specific network.
NetworkOperation.create_default_network() -> OperationResult[NetworkItem]
Ensure the default network exists, creating it if needed. Called automatically by HostOperation.init(). Idempotent.
NetworkOperation.prune(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune unused networks. By default, skips the default network and networks referenced by VMs or with active leases. Use include_all=True to remove ALL networks.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
dry_run | bool | False | Only report what would be removed, without actually removing |
include_all | bool | False | Remove ALL networks including default and referenced |
ImageOperation
All methods are @staticmethod. Images are identified using ImageInput objects.
ImageOperation.pull(inputs: ImagePullInput, *, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[ImageItem] | NeedsInteraction
Pull (download) a VM rootfs image (qcow2, tar, or raw), convert to ext4, and register in the database.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.type | str | — | Image type (e.g. ubuntu, alpine, debian) |
inputs.version | str | None | None | Image spec version |
inputs.no_cache | bool | False | Skip cached version listing |
inputs.force | bool | False | Re-download even if cached |
inputs.skip_optimization | bool | False | Skip shrink and compression |
inputs.set_default | bool | False | Set as default after download |
inputs.arch | str | None | None | Image architecture |
inputs.disabled_detectors | list[str] | [] | Detectors to disable: type, label, size, filesystem |
ImageOperation.import_(inputs: ImageImportInput, *, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[ImageItem]
Import an existing local image file (qcow2, raw, tar-rootfs) and register it in the database.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | — | Display name for the image |
inputs.source_path | Path | — | Path to local image file |
inputs.format | str | None | None | Image format: qcow2, raw, tar-rootfs, or auto |
inputs.arch | str | None | None | Image architecture |
inputs.partition | int | None | None | Root partition number |
inputs.force | bool | False | Overwrite existing |
inputs.skip_optimization | bool | False | Skip shrink and compression |
inputs.set_default | bool | False | Set as default after import |
inputs.disabled_detectors | list[str] | [] | Detectors to disable: type, label, size, filesystem |
ImageOperation.remove(inputs: ImageInput, force: bool = False) -> BatchResult[ImageItem]
Remove an image from cache and database.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
force | bool | False | Remove even if referenced by VMs |
ImageOperation.list_all(inputs: ImageInput | None = None, *, remote: bool = False, no_cache: bool = False, type_filter: str | None = None) -> list[ImageItem] | list[ImageVersion]
List local cached images or available remote images.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
no_cache | bool | False | Skip cached version listing and fetch live |
type_filter | str | None | None | Filter by image type (e.g. ubuntu) |
ImageOperation.get(inputs: ImageInput) -> ImageItem
Get a single image by ID or OS slug.
ImageOperation.set_default(inputs: ImageInput) -> OperationResult[ImageItem]
Set an image as the default for new VMs.
ImageOperation.inspect(inputs: ImageInput) -> dict[str, Any]
Show detailed information about an image including compression stats and storage details.
ImageOperation.warm(inputs: ImageInput | None = None, *, all: bool = False, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[list[Path]]
Pre-decompress image to tmpfs ready pool for fast VM creation.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
all | bool | False | Warm all images, not just the default |
KernelOperation
All methods are @staticmethod. Kernels are identified using KernelInput objects.
KernelOperation.pull(inputs: KernelPullInput, *, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[KernelItem] | NeedsInteraction
Pull (download) or build a Firecracker kernel. Requires kernel_type (firecracker or official).
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.kernel_type | str | — | firecracker or official |
inputs.version | str | None | None | Kernel version (default: 6.19.9 for official) |
inputs.arch | str | None | None | Architecture |
inputs.set_default | bool | False | Set as default after fetch |
inputs.jobs | int | None | None | Parallel build jobs (official only) |
inputs.keep_build_dir | bool | False | Keep build directory (official only) |
inputs.clean_build | bool | False | Skip build cache (official only) |
inputs.kernel_config | Path | None | None | Custom kernel config fragment |
inputs.features | str | "" | Comma-separated kernel features (kvm, nftables) |
KernelOperation.remove(inputs: KernelInput, force: bool = False) -> BatchResult[KernelItem]
Remove a kernel from cache and database.
KernelOperation.list_all(remote: bool = False, *, no_cache: bool = False) -> list[KernelItem] | list[VersionInfo]
List kernels. When remote=True, returns available remote kernel versions from upstream providers (kernel.org for official kernels, Firecracker S3 for firecracker kernels). When remote=False (default), returns locally cached kernels.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
remote | bool | False | If True, list remote kernel versions instead of local |
no_cache | bool | False | Skip cached version listing and fetch live from upstream. Only relevant when remote=True. |
KernelOperation.get(inputs: KernelInput) -> KernelItem
Get a single kernel by ID or name.
KernelOperation.inspect(inputs: KernelInput) -> dict[str, Any]
Show detailed kernel information.
KernelOperation.set_default(inputs: KernelInput) -> OperationResult[KernelItem]
Set a kernel as the default for VM creation.
KeyOperation
All methods are @staticmethod. Keys are identified using KeyInput objects.
KeyOperation.create(inputs: KeyCreateInput) -> OperationResult[SSHKeyItem]
Generate a new SSH keypair via ssh-keygen and register it.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | — | Key name and base filename |
inputs.algorithm | str | None | None | Key algorithm: ed25519, rsa, or ecdsa |
inputs.bits | int | None | None | Key size in bits (RSA only; default 4096) |
inputs.comment | str | None | None | Key comment |
inputs.set_default | bool | False | Set as default after creation |
inputs.overwrite | bool | False | Overwrite existing key |
inputs.output_dir | Path | None | None | Output directory for the keypair |
KeyOperation.add(name: str, pub_key_path: Path, overwrite: bool = False) -> OperationResult[SSHKeyItem]
Import an existing .pub file into the cache.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | — | Name for the key |
pub_key_path | Path | — | Path to .pub file |
overwrite | bool | False | Overwrite existing key with same name |
KeyOperation.list_all() -> list[SSHKeyItem]
List all keys in the cache.
KeyOperation.get(inputs: KeyInput) -> SSHKeyItem
Get a single key by name or ID.
KeyOperation.inspect(inputs: KeyInput) -> dict[str, Any]
Show detailed key information.
KeyOperation.set_default(inputs: KeyInput) -> OperationResult[SSHKeyItem]
Set one or more keys as defaults for new VMs.
KeyOperation.get_defaults() -> list[SSHKeyItem]
Get all default keys.
KeyOperation.clear_defaults() -> OperationResult[None]
Clear all default key assignments.
KeyOperation.remove(inputs: KeyInput) -> BatchResult[SSHKeyItem]
Remove keys from the cache.
KeyOperation.export(inputs: KeyInput, destination: Path, overwrite: bool = False) -> OperationResult[tuple[Path, Path]]
Export a keypair to a destination directory.
BinaryOperation
All methods are @staticmethod. Binaries are identified using BinaryInput objects.
BinaryOperation.pull(inputs: BinaryPullInput) -> OperationResult[list[BinaryItem]] | NeedsInteraction
Pull (download) a specific Firecracker/jailer binary version from GitHub releases.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | "firecracker" | Binary name (only 'firecracker' is supported for download/build) |
inputs.version | str | — | Semantic version string (e.g. 1.15.0) |
inputs.git_ref | str | None | None | Git ref to build from source (e.g. v1.15.0). When set, skips release download and builds from source instead. |
inputs.set_default | bool | False | Set as default after download |
inputs.download_override | bool | True | Re-download even if cached |
BinaryOperation.remove(inputs: BinaryInput, force: bool = False) -> BatchResult[BinaryItem]
Remove binaries by identifier.
BinaryOperation.remove_by_version(version: str, force: bool = False) -> OperationResult[None]
Remove both firecracker and jailer by version string.
BinaryOperation.list_all(remote: bool = False, limit: int | None = None) -> list[BinaryItem] | list[str]
List binaries. When remote=False (default), returns locally installed binaries. When remote=True, returns available remote versions from GitHub.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
remote | bool | False | If True, list remote versions instead of local |
limit | int | None | None | Limit remote versions returned |
BinaryOperation.get(inputs: BinaryInput) -> list[BinaryItem]
Get a binary by name and version.
BinaryOperation.set_default(inputs: BinaryInput) -> OperationResult[BinaryItem]
Set a binary (by ID) as the active default.
BinaryOperation.ensure_default() -> OperationResult[BinaryItem]
Ensure a default Firecracker binary exists.
VolumeOperation
All methods are @staticmethod. Volumes are identified using VolumeInput objects.
VolumeOperation.create(inputs: VolumeCreateInput) -> OperationResult[VolumeItem]
Create a new persistent data disk. Creates the disk file via fallocate (raw) or qemu-img (qcow2), registers the volume in the database.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | — | Volume name (required) |
inputs.size | str | — | Volume size (e.g. 10G, 512M) |
inputs.format | str | None | None | Disk format: raw or qcow2 (resolved to raw by default) |
inputs.read_only | bool | None | None | Mount volume as read-only (resolved to False by default) |
Raises: VolumeError
Example
Terminal
from mvmctl.api import VolumeOperation, VolumeCreateInput
result = VolumeOperation.create(
VolumeCreateInput(name="my-data", size="10G")
)VolumeOperation.remove(inputs: VolumeInput, force: bool = False) -> BatchResult[VolumeItem]
Remove one or more volumes by name or ID prefix. Deletes the disk file and removes from the database.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.identifiers | list[str] | [] | Volume names or ID prefixes to remove |
force | bool | False | Remove even if attached to VMs |
VolumeOperation.list_all() -> list[VolumeItem]
List all volumes from the database.
VolumeOperation.get(inputs: VolumeInput) -> VolumeItem
Get a single volume by name or ID.
Raises: VolumeNotFoundError if not found or ambiguous.
VolumeOperation.inspect(inputs: VolumeInput) -> dict[str, Any]
Show detailed information about a volume including qemu-img disk info.
VolumeOperation.resize(inputs: VolumeCreateInput) -> OperationResult[VolumeItem]
Resize a volume. Raw format supports grow only (fallocate). qcow2 supports both grow and shrink (qemu-img).
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.name | str | — | Volume name to resize |
inputs.size | str | — | New size (e.g. 20G) |
Raises: VolumeError
HostOperation
All methods are @staticmethod.
HostOperation.init(cache_dir: Path, *, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[Any] | NeedsInteraction
Apply host configuration: enable IP forwarding, persist sysctl, load KVM modules, create the mvm unix group, configure sudoers, set up iptables chains, and ensure the default network. Fully idempotent.
Raises: HostError, PrivilegeError
HostOperation.clean(cache_dir: Path) -> OperationResult[list[str]]
Remove all networking config (bridges, TAPs, iptables rules). Does not touch sysctl, sudoers, or group.
HostOperation.reset(cache_dir: Path) -> OperationResult[list[str]]
Full rollback to pre-init state: networking, sysctl, sudoers, and group removal.
HostOperation.check_kvm_access() -> bool
Return True if /dev/kvm exists and is accessible by the current user.
HostOperation.check_required_binaries() -> list[str]
Return a list of missing required binary names.
HostOperation.get_ip_forward_status() -> str
Return the current net.ipv4.ip_forward value.
HostOperation.info() -> OperationResult[dict[str, object]]
Return current host info with capacity analysis. Returns hardware, limits, resource usage, and capacity projections from stored or auto-detected state.
HostOperation.refresh_capacity() -> OperationResult[dict[str, object]]
Redetect host hardware/limits and refresh info output. Returns the same structure as info() but forces fresh detection instead of using cached state.
HostOperation.get_state() -> HostStateItem | None
Return the saved host state if one exists.
HostOperation.get_running_vms() -> list[VMInstanceItem]
Return all currently running VMs.
CacheOperation
All methods are @staticmethod.
CacheOperation.init_all(*, on_progress: Callable[[ProgressEvent], None] | None = None) -> OperationResult[dict[str, str | list[str] | None]]
Initialize all cache directories and optionally build the libguestfs fixed appliance.
CacheOperation.prune_vms(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune VMs. By default prunes all except RUNNING/STARTING.
CacheOperation.prune_networks(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune unused networks.
CacheOperation.prune_images(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune unused images.
CacheOperation.prune_kernels(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune unused kernels.
CacheOperation.prune_binaries(dry_run: bool = False, include_all: bool = False) -> OperationResult[list[str]]
Prune unused binaries.
CacheOperation.prune_misc(dry_run: bool = False) -> OperationResult[dict[str, bool]]
Prune misc cache (libguestfs appliance, warm images).
CacheOperation.prune_all(dry_run: bool = False, include_all: bool = False) -> OperationResult[PruneAllResult]
Prune all cache resources in one call.
CacheOperation.clean(dry_run: bool = False) -> OperationResult[CleanResult]
Completely clean all cache — prune everything, clean host networking, remove cache directory.
SSHOperation
SSHOperation.connect(inputs: SSHInput) -> OperationResult[int]
Open an interactive SSH session into a VM, or execute a command.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.identifier | str | — | VM identifier (name, ID, IP, or MAC) |
inputs.user | str | None | None | SSH user |
inputs.key | Path | None | None | SSH private key path or key name |
inputs.cmd | str | None | None | Command to execute (None = interactive) |
inputs.timeout | int | None | None | SSH connection timeout in seconds |
CPOperation
File copy operations between host and microVMs via tar-over-SSH. Supports three directions: host_to_vm, vm_to_host, and vm_to_vm. Paths use vm_name:/path syntax to reference VM-side locations.
CPOperation.copy(inputs: CPInput, *, on_progress: Callable[[int], None] | None = None) -> OperationResult[dict[str, Any]]
Copy files between the host and microVMs. Uses tar-over-SSH for efficient streaming. Returns an OperationResult with bytes transferred and a summary message.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
inputs.sources | list[str] | — | Source paths (local paths or vm_name:/remote/path) |
inputs.dst | str | — | Destination path (local path or vm_name:/remote/path) |
inputs.user | str | None | None | SSH user (resolved from VM record if not set) |
inputs.key | str | None | None | SSH key name or path (resolved from VM record if not set) |
inputs.force | bool | False | Overwrite existing destination files |
Raises: CPError, CPSourceNotFoundError, CPDestinationExistsError, CPDestinationNotDirectoryError, SSHError
ConsoleOperation
Methods for managing the VM serial console relay via vsock.
ConsoleOperation.get_connection_info(identifier: str) -> ConsoleConnectionInfo
Get connection info (socket path) for attaching to a VM serial console.
ConsoleOperation.get_state(identifier: str) -> dict[str, Any]
Check the console relay state for a VM (running, PID, socket path).
ConsoleOperation.kill(identifier: str) -> OperationResult[bool]
Kill the console relay process for a VM.
LogOperation
Methods for streaming VM logs.
LogOperation.stream(inputs: LogInput) -> Generator[str]
Stream VM boot or OS logs. Supports line limits and follow mode.
ConfigOperation
Methods for managing mvmctl settings.
ConfigOperation.get(category: str, key: str | None = None) -> Any
Get a config value by category and optional key.
ConfigOperation.set(category: str, key: str, value: Any) -> OperationResult[None]
Set a config value persistently in config.json.
ConfigOperation.reset(category: str | None = None, key: str | None = None, all_overrides: bool = False) -> OperationResult[int]
Reset config override(s) to defaults.
ConfigOperation.list_all() -> dict
List all overridable settings with their current values and types.
InitOperation
InitOperation.run(skip_host: bool = False, non_interactive: bool = False, *, on_progress: Callable[[ProgressEvent], None] | None = None, sudo_completed: bool = False, host_setup_message: str | None = None, download_version: str | None = None, guestfs_enabled: bool | None = None) -> InitResult
Run the full init wizard: local state → host setup → cache init → binary fetch.
InitOperation.init_database() -> None
Initialize the local SQLite database (run migrations).
InitOperation.setup_host(cache_dir: Path) -> OperationResult[Any] | NeedsInteraction
Set up host configuration. Delegates to HostOperation.init().
End-to-End Example
Complete orchestration script: initialize database, set up host, fetch binary, create SSH key, ensure default network, create a VM, and list running instances.
Terminal
#!/usr/bin/env python3
"""Orchestrate microVM lifecycle using the mvmctl Python API."""
from pathlib import Path
from mvmctl.api import (
BinaryOperation, BinaryPullInput,
HostOperation,
ImageOperation, ImagePullInput,
InitOperation,
KeyOperation, KeyCreateInput,
NetworkOperation,
VMOperation, VMCreateInput,
)
from mvmctl.exceptions import MVMError
from mvmctl.models.result import NeedsInteraction, OperationResult
# CacheUtils.get_cache_dir() is not part of the public API —
# use Path.home() for the default cache path instead.
CACHE_DIR = Path.home() / ".cache" / "mvmctl"
def main() -> None:
# 1. Initialise the SQLite database
InitOperation.init_database()
print("Database ready.")
# 2. Initialise the host (idempotent)
host_result = HostOperation.init(CACHE_DIR)
if isinstance(host_result, NeedsInteraction):
print("Host init requires sudo. Run: sudo mvm host init")
return
changes = host_result.metadata.get("changes", [])
if changes:
for change in changes:
print(f" Applied: {change.setting} = {change.applied_value}")
else:
print("Host already configured.")
# 3. Ensure a Firecracker binary is available
local = BinaryOperation.list_all()
if not local:
print("Downloading Firecracker 1.15.1 ...")
result = BinaryOperation.pull(BinaryPullInput(version="1.15.1"))
if isinstance(result, NeedsInteraction):
print("Binary download requires privileges.")
return
if result.is_error:
print(f"Download failed: {result.message}")
return
# 4. Ensure a kernel is available (via CLI: mvm kernel pull)
# or use KernelOperation.pull() directly
# 5. Ensure an image is available (via CLI: mvm image pull)
# or use ImageOperation.pull() directly
# 6. Create or register an SSH key
key_result = KeyOperation.create(
KeyCreateInput(name="my-api-key", set_default=True)
)
if key_result.is_error:
print(f"Key creation failed: {key_result.message}")
return
key = key_result.item
assert key is not None
print(f"Created SSH key: {key.name} ({key.fingerprint})")
# 7. Ensure the default network exists
net_result = NetworkOperation.create_default_network()
if net_result.is_error:
print(f"Network creation failed: {net_result.message}")
return
default_net = net_result.item
assert default_net is not None
print(f"Default network: {default_net.name} ({default_net.subnet})")
# 8. Create a VM using the API
create_result = VMOperation.create(
VMCreateInput(
name="my-api-vm",
ssh_keys=["my-api-key"],
vcpu_count=2,
mem_size_mib=2048,
image="ubuntu",
network_name="default",
)
)
if isinstance(create_result, NeedsInteraction):
print("VM creation requires privileges.")
return
if create_result.is_error:
print(f"VM creation failed: {create_result.message}")
return
created_vms = create_result.item or []
names = [vm.name for vm in created_vms]
print(f"Created VM(s): {', '.join(names)}")
# 9. List all VMs
instances = VMOperation.list_all()
print(f"\nRegistered VMs ({len(instances)}):")
for vm in instances:
print(f" {vm.name:20s} {vm.status:10s} {vm.ipv4}")
if __name__ == "__main__":
try:
main()
except MVMError as e:
print(f"Error: {e}")
raise SystemExit(1)