Snapshots
Capturing and restoring a running microVM's state
client.Snapshots captures and restores the state of a running microVM. Take
a snapshot before something risky, and restore if it goes wrong:
snap, err := client.Snapshots.Create(ctx, env.ID, fuse.SnapshotRequest{
Comment: "before risky migration",
Mode: "manual",
})
if err != nil {
log.Fatal(err)
}
// ... do the risky thing ...
if err := client.Snapshots.Restore(ctx, snap.ID); err != nil {
log.Fatal(err)
}
Create’svmIDmust be arunningenvironment.SnapshotRequestis entirely optional, a zero-value struct is a valid request;Modeis"manual"or"auto", andRetentionSecondsof0keeps it forever.Restoreis in place only: it restores onto the snapshot’s original VM, which must still be running. There is no cross-host restore, clone, or standalone restore into a new VM, useForkonEnvironmentsServicefor that instead.
Live snapshots
SnapshotRequest.Live opts into capturing the guest’s memory and vCPU state
alongside the disk. The zero value is a disk-only snapshot, which is the default
and the fallback:
snap, err := client.Snapshots.Create(ctx, env.ID, fuse.SnapshotRequest{
Comment: "warmed model loaded",
Live: true,
})
if err != nil {
log.Fatal(err)
}
// snap.Kind is "live" here, "disk" on every other snapshot
Snapshot.Kind is "live" or "disk" and is set by the host agent, not by the
caller reading its own request back. Restore has no Live counterpart: it
reads the kind off the snapshot and either resumes the guest or cold-boots it.
The trade-offs are the same ones documented under Snapshots, and they are sharp enough to repeat:
Snapshot.SizeByteson a live snapshot includes a full copy of the environment’s configured memory, on every create. Tenant byte quotas were calibrated for rootfs-only snapshots, so aCreateloop withLive: truewill hit409conflicton quota much sooner than the snapshot count implies.- the guest is paused for the duration of the capture.
- a live snapshot cannot seed a new environment.
Environments.ForkandCreateRequest.SeedSnapshotIDread only a snapshot’s rootfs, and a live snapshot’s rootfs is captured without quiescing the guest filesystem, so it mounts cleanly only alongside its memory image. Both reject one with409conflict. Take a disk snapshot when you want a copy rather than a rewind. - a live snapshot is pinned to the host that took it. The memory image depends on that host’s CPU model and Firecracker version.
Live: true against a backend with no live-snapshot support returns 501
unimplemented, not a conflict, so fuse.IsConflict(err) does not match it.
The message says to retry without live for a disk snapshot.
Snapshot.Kind is worth checking rather than assuming: a host running an agent
too old to know about live snapshots answers Live: true with a disk snapshot,
and the record then says "disk". Recording the request rather than the result
would file a cold-booting artifact as a resumable one.
Everything else
| Method | Purpose |
|---|---|
List(ctx, ListSnapshotsOptions{...}) |
List snapshots, optionally filtered by VMID/TaskID/TenantID/State. |
Get(ctx, snapshotID) |
Fetch one snapshot’s full detail, including State (creating|ready|restoring|deleting|error), Kind (disk|live), and Exports. |
Delete(ctx, snapshotID) |
Leaf-only delete; also removes the underlying provider artifact. No soft-delete. |
These mirror the HTTP API one to one.
The QEMU/GPU exception
Environments running on the QEMU backend (whole-GPU passthrough) cannot be
snapshotted or forked at all, Snapshots.Create and Environments.Fork against
a GPU environment fail with a 409 conflict *APIError rather than silently
no-op-ing. Restore carries no GPU check of its own, it is simply unreachable
for a GPU environment because no snapshot of one can exist. See
Providers.
fuse.IsConflict(err) reports true for the GPU guardrail, so branch on that
rather than on the error message. A backend with no snapshot support at all
returns 501 unimplemented instead, which IsConflict does not match.