The guide · explanation

Snapshots

9 min read · 2026-09-02 · vmlab 0.9

A snapshot captures a machine so you can return to it later: a known good state before an experiment, a checkpoint mid-way through a long install, a domain just after promotion. vmlab takes them online or offline, per machine or across a whole lab, and restores each to the power state it was captured in. This chapter explains the mechanism, its limits, and what a restore does to a dev machine's workspace, which is the one place a snapshot is not what it looks like. The verbs are in vmlab snapshot.

Online and offline

An offline snapshot, taken while the machine is powered off, captures disk state only. An online snapshot, taken while it runs, captures disk, RAM and device state, and pauses the guest only for as long as the save takes. Every snapshot records the machine's power state at capture, and a restore does the right thing with it: restoring an online snapshot resumes the machine exactly where it was, and restoring an offline one leaves it powered off. A machine mid-transition, still starting or stopping, is refused until it settles.

Both kinds are qcow2-internal snapshots, so the on-disk footprint is the clone file itself and the linked-clone backing chain is untouched. An online snapshot is written through QMP's snapshot-save into the primary disk, covering every disk the machine has; an offline one is written with qemu-img to each disk in turn. Snapshots are named, listed and deleted per machine. When an online snapshot is restored, the daemon drops its agent connection before resuming, because the rewound guest replays serial bytes the host already consumed, and reconnects on next use.

Containers snapshot with the same verbs and the same semantics. The per-container scratch disk holds the snapshot, the image's read-only root is outside it, and each snapshot records the image digest it was taken against. Lab containers explains the pin.

Lab-wide snapshots

vmlab snapshot create <name> with no --vm captures every VM and container in the lab under one name, and restore with no --vm restores them all. Consistency across machines is best-effort: each machine is captured in turn, not at one coordinated instant, so two machines mid-conversation may land a few moments apart. A test that depends on cross-machine consistency should quiesce the guests first.

What a snapshot does not hold

Shares, volumes and workspaces are host state

A shared folder's contents, a container volume's contents, and a dev machine's workspace all live on the host. A restore never rolls any of them back. Only what is on the machine's own disk, and in its RAM for an online snapshot, returns to the captured state.

Shares stay snapshot-compatible on both transports: SMB carries no device state, and a virtiofs share's daemon transfers its session state through the snapshot's migration stream, so an online restore finds its open handles intact. The files, though, are whatever they are on the host now. The same holds for a container's volumes.

Snapshots and a dev workspace

A dev machine holds a workspace: a guest-local working copy of a host directory that is canonical, kept in step both ways by vmlab's syncer. A restore rewinds that guest copy by hundreds of files at once, and a naive bidirectional syncer cannot tell that apart from the developer having edited hundreds of files. It would carry the old versions onto the canonical copy, silently. Because vmlab performs the restore, it can bracket it, and the bracket has two asymmetric halves.

Capture flushes, and refuses with no escape

Before a capture, the syncer flushes the workspace so the snapshot is coherent with the host tree. If the guest still holds work the canonical copy has never seen, the capture refuses, naming the outstanding paths, the first twenty and then how many more. Any of these refuses it: a standing conflict halt, a pass that could not finish because the guest stopped answering, a pending rescan or re-seed, paths the flush did not carry, and a workspace that has never completed a pass at all. A stopped machine is judged from its ledger, and refuses on the two states the ledger still records: a halt, and an owed re-seed.

There is no flag to override this, because there is no case for one. A snapshot of a tree the host has never seen is a snapshot that restores somewhere meaningless, holding a version of the repository that exists nowhere else. The fix is to let the flush finish or to resolve the halt, which is what you wanted anyway. A named skip, such as a socket in the tree or a root-owned build artefact, is permanent and normal and does not refuse.

Restore takes the syncer off, rewinds, and re-seeds

A restore suspends the syncer before anything is rolled back, so no pass already scanning can finish against a guest rewound underneath it. It then restores the machine and puts the syncer back owing a re-seed: a host-only, digest-based reconcile that carries the guest tree back to the canonical copy. Each word matters.

The re-seed replaces the stat-walk the syncer would otherwise run on a watch discontinuity, rather than following one: the walk asks what the guest did while nobody was looking, and here vmlab already knows. That a re-seed is owed rides the ledger in the lab's .vmlab/, because a restore does not need a running machine; a stopped dev machine restored now re-seeds when it next starts.

The one escape flag

A restore refuses while a conflict halt stands on the workspace, because a restore discards the guest side of every halted path by design, and each of those paths is a file you were going to be asked about. Refusing outright would be obstruction, since wanting to throw the guest copy away is often why you restore, so the refusal has one escape: --discard-guest-changes, or restore_discarding_workspace from a script. Passing it throws away the guest copy of every conflicting path and lets the restore proceed. A restore that is refused leaves the machine exactly as it was.

Snapshots are not a workspace backup

A dev machine's source lives on the host, which is what survives destroy and what a restore re-converges the guest from. A snapshot holds the guest copy of the workspace as it was, and a restore replaces it with the host's current tree. Every surface that takes or restores a snapshot repeats this sentence, because a developer who believes a snapshot holds their edits has believed something this design deliberately does not offer.

Headroom

Linked clones grow as guests write, and internal snapshots grow with them. The supervisor watches free space on the filesystems holding .vmlab/ and the store and emits host.disk_low below the threshold set by disk_low_percent in the host configuration, which a handler can act on as Events and handlers describes.