Back to Microsandbox

Snapshots

docs/sdk/rust/snapshots.mdx

0.6.742.4 KB
Original Source

Capture a stopped sandbox's writable upper layer into a self-describing, content-addressed artifact on disk, then list, verify, save, load, or boot a fresh sandbox from it. See Snapshots for concepts and walkthroughs; this page is the Rust SDK reference.

<div className="msb-glance"> <p className="msb-gl"><span className="msb-dot static"></span>Static · Snapshot<span className="msb-ct">10</span></p> <a className="msb-row" href="#snapshotbuilder"><span className="msb-rn">Snapshot::builder()</span><span className="msb-rg">configure a new snapshot</span></a> <a className="msb-row" href="#snapshotcreate"><span className="msb-rn">Snapshot::create()</span><span className="msb-rg">create from a config</span></a> <a className="msb-row" href="#snapshotopen"><span className="msb-rn">Snapshot::open()</span><span className="msb-rg">open an artifact</span></a> <a className="msb-row" href="#snapshotget"><span className="msb-rn">Snapshot::get()</span><span className="msb-rg">handle from the index</span></a> <a className="msb-row" href="#snapshotlist"><span className="msb-rn">Snapshot::list()</span><span className="msb-rg">indexed snapshots</span></a> <a className="msb-row" href="#snapshotlist_dir"><span className="msb-rn">Snapshot::list_dir()</span><span className="msb-rg">artifacts in a directory</span></a> <a className="msb-row" href="#snapshotremove"><span className="msb-rn">Snapshot::remove()</span><span className="msb-rg">delete an artifact</span></a> <a className="msb-row" href="#snapshotreindex"><span className="msb-rn">Snapshot::reindex()</span><span className="msb-rg">rebuild the index</span></a> <a className="msb-row" href="#snapshotsave"><span className="msb-rn">Snapshot::save()</span><span className="msb-rg">bundle to an archive</span></a> <a className="msb-row" href="#snapshotload"><span className="msb-rn">Snapshot::load()</span><span className="msb-rg">unpack an archive</span></a> <p className="msb-gl"><span className="msb-dot instance"></span>Instance · Snapshot<span className="msb-ct">5</span></p> <a className="msb-row" href="#snap-digest"><span className="msb-rn">snap.digest()</span><span className="msb-rg">content identity</span></a> <a className="msb-row" href="#snap-path"><span className="msb-rn">snap.path()</span><span className="msb-rg">artifact directory</span></a> <a className="msb-row" href="#snap-manifest"><span className="msb-rn">snap.manifest()</span><span className="msb-rg">parsed manifest</span></a> <a className="msb-row" href="#snap-size_bytes"><span className="msb-rn">snap.size_bytes()</span><span className="msb-rg">upper-layer size</span></a> <a className="msb-row" href="#snap-verify"><span className="msb-rn">snap.verify()</span><span className="msb-rg">recheck integrity</span></a> <p className="msb-gl"><span className="msb-dot instance"></span>Instance · SnapshotHandle<span className="msb-ct">11</span></p> <a className="msb-row" href="#h-digest"><span className="msb-rn">h.digest()</span><span className="msb-rg">manifest digest</span></a> <a className="msb-row" href="#h-name"><span className="msb-rn">h.name()</span><span className="msb-rg">name alias</span></a> <a className="msb-row" href="#h-parent_digest"><span className="msb-rn">h.parent_digest()</span><span className="msb-rg">parent snapshot</span></a> <a className="msb-row" href="#h-scope"><span className="msb-rn">h.scope()</span><span className="msb-rg">snapshot scope</span></a> <a className="msb-row" href="#h-image_ref"><span className="msb-rn">h.image_ref()</span><span className="msb-rg">source image</span></a> <a className="msb-row" href="#h-format"><span className="msb-rn">h.format()</span><span className="msb-rg">upper format</span></a> <a className="msb-row" href="#h-size_bytes"><span className="msb-rn">h.size_bytes()</span><span className="msb-rg">indexed size</span></a> <a className="msb-row" href="#h-created_at"><span className="msb-rn">h.created_at()</span><span className="msb-rg">creation time</span></a> <a className="msb-row" href="#h-path"><span className="msb-rn">h.path()</span><span className="msb-rg">artifact directory</span></a> <a className="msb-row" href="#h-open"><span className="msb-rn">h.open()</span><span className="msb-rg">read the artifact</span></a> <a className="msb-row" href="#h-remove"><span className="msb-rn">h.remove()</span><span className="msb-rg">delete this snapshot</span></a> <p className="msb-gl"><span className="msb-dot static"></span>Sandbox entry points<span className="msb-ct">2</span></p> <a className="msb-row" href="#from_snapshot"><span className="msb-rn">.from_snapshot()</span><span className="msb-rg">boot from a snapshot</span></a> <a className="msb-row" href="#h-snapshot"><span className="msb-rn">h.snapshot()</span><span className="msb-rg">snapshot a stopped sandbox</span></a> <p className="msb-gl"><span className="msb-dot builder"></span>Builder · SnapshotBuilder<span className="msb-ct">8</span></p> <div className="msb-chiprow"> <a className="msb-chip" href="#from_sandbox">.from_sandbox()</a> <a className="msb-chip" href="#dest_dir">.dest_dir()</a> <a className="msb-chip" href="#label">.label()</a> <a className="msb-chip" href="#force">.force()</a> <a className="msb-chip" href="#record_integrity">.record_integrity()</a> <a className="msb-chip" href="#resumable">.resumable()</a> <a className="msb-chip" href="#build">.build()</a> <a className="msb-chip" href="#create">.create()</a> </div> <p className="msb-gl"><span className="msb-dot type"></span>Types</p> <div className="msb-chiprow"> <a className="msb-typepill" href="#snapshothandle">SnapshotHandle</a> <a className="msb-typepill" href="#snapshotconfig">SnapshotConfig</a> <a className="msb-typepill" href="#snapshotformat">SnapshotFormat</a> <a className="msb-typepill" href="#snapshotscope">SnapshotScope</a> <a className="msb-typepill" href="#saveopts">SaveOpts</a> <a className="msb-typepill" href="#snapshotverifyreport">SnapshotVerifyReport</a> <a className="msb-typepill" href="#upperverifystatus">UpperVerifyStatus</a> <a className="msb-typepill" href="#manifest">Manifest</a> <a className="msb-typepill" href="#imageref">ImageRef</a> <a className="msb-typepill" href="#upperlayer">UpperLayer</a> <a className="msb-typepill" href="#upperintegrity">UpperIntegrity</a> </div> </div> <Note> Snapshots are **local-only** and **disk-only** today: they capture a sandbox that is stopped or crashed, and every operation runs against the default local backend. Cloud snapshots and qcow2 backing chains are deferred. </Note> <p className="msb-label" id="typical-flow">Typical flow</p>
rust
use microsandbox::{Sandbox, Snapshot};

// 1. stop the sandbox you want to capture
let sb = Sandbox::get("api").await?;
sb.stop().await?;

// 2. capture its writable upper layer
let snap = Snapshot::builder("after-pip-install")
    .from_sandbox("api")           // sandbox to capture
    .record_integrity()            // hash the upper layer
    .create()
    .await?;
println!("{} ({} bytes)", snap.digest(), snap.size_bytes());

// 3. boot a fresh sandbox from it
let restored = Sandbox::builder("api-restored")
    .from_snapshot("after-pip-install")
    .create()
    .await?;

Static methods

<span className="msb-recv">Snapshot::</span><span className="msb-hn">builder()</span>

rust
fn builder(name: impl Into<String>) -> SnapshotBuilder

Start configuring a new snapshot named name, resolved under the default snapshots directory (~/.microsandbox/snapshots/<name>/) or under dest_dir() when set. The source sandbox is set with from_sandbox(), which is required; the other setters cover labels and whether to record content integrity before capturing. See SnapshotBuilder for all options.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>name</code><span className="msb-type">impl Into&lt;String&gt;</span></div> <div className="msb-param-desc">Bare snapshot name. Must not be empty, contain <code>/</code>, or start with <code>.</code>.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshotbuilder">SnapshotBuilder</a></div> <div className="msb-param-desc">Builder for configuring the snapshot.</div> </div> </div> <Accordion title="Example">
rust
let snap = Snapshot::builder("baseline")
    .from_sandbox("api")
    .create()
    .await?;
</Accordion>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">create()</span>

rust
async fn create(config: SnapshotConfig) -> MicrosandboxResult<Snapshot>

Create a snapshot artifact from a stopped sandbox. Writes the snapshot.json descriptor and the captured upper.ext4 into the artifact directory atomically (the descriptor is renamed into place last), then best-effort upserts a row into the local index. Index failures are logged but do not fail the call; the artifact is the source of truth. Most callers use the builder's create() instead of constructing a SnapshotConfig by hand.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>config</code><a className="msb-type" href="#snapshotconfig">SnapshotConfig</a></div> <div className="msb-param-desc">Name, source sandbox, labels, and integrity flag.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div> <div className="msb-param-desc">The created artifact handle.</div> </div> </div> <Accordion title="Example">
rust
let snap = Snapshot::create(
    Snapshot::builder("baseline").from_sandbox("api").build()?
).await?;
</Accordion>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">open()</span>

rust
async fn open(path_or_name: impl AsRef<str>) -> MicrosandboxResult<Snapshot>
<Accordion title="Example">
rust
let snap = Snapshot::open("baseline").await?;
println!("{}", snap.manifest().image.reference);
</Accordion>

Open an existing artifact by path or bare name. Bare names (no path separator, not starting with . or ~) resolve under the default snapshots directory; anything else is treated as a path. This is a fast metadata operation: it verifies the manifest structure, recomputes the manifest digest, and checks that the upper file exists with the recorded size. It does not read the full upper contents; use verify() for that.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>path_or_name</code><span className="msb-type">impl AsRef&lt;str&gt;</span></div> <div className="msb-param-desc">Bare snapshot name or filesystem path to an artifact directory.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div> <div className="msb-param-desc">The opened artifact handle.</div> </div> </div>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">get()</span>

rust
async fn get(name_or_digest: &str) -> MicrosandboxResult<SnapshotHandle>
<Accordion title="Example">
rust
let h = Snapshot::get("after-pip-install").await?;
println!("{} from {}", h.digest(), h.image_ref());
</Accordion>

Look up a lightweight SnapshotHandle in the local index by name, digest (sha256:/sha512: prefix), or path.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>name_or_digest</code><span className="msb-type">&amp;str</span></div> <div className="msb-param-desc">Snapshot name, manifest digest, or artifact path.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshothandle">SnapshotHandle</a></div> <div className="msb-param-desc">Handle backed by the matching index row.</div> </div> </div>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">list()</span>

rust
async fn list() -> MicrosandboxResult<Vec<SnapshotHandle>>
<Accordion title="Example">
rust
for h in Snapshot::list().await? {
    println!("{:?} - {}", h.name(), h.digest());
}
</Accordion>

List indexed snapshots from the local DB cache, newest first. External-path artifacts booted by full path aren't in the index and won't appear here; use list_dir to enumerate artifacts on disk directly.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshothandle">Vec&lt;SnapshotHandle&gt;</a></div> <div className="msb-param-desc">Indexed snapshot handles, ordered by creation time descending.</div> </div> </div>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">list_dir()</span>

rust
async fn list_dir(dir: impl AsRef<Path>) -> MicrosandboxResult<Vec<Snapshot>>

Walk a directory and parse each subdirectory's manifest. Does not touch the index. Skips entries that don't look like snapshot artifacts (no snapshot.json) and malformed artifacts.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>dir</code><span className="msb-type">impl AsRef&lt;Path&gt;</span></div> <div className="msb-param-desc">Directory to scan for artifacts.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Vec&lt;Snapshot&gt;</a></div> <div className="msb-param-desc">One handle per valid artifact found.</div> </div> </div>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">remove()</span>

rust
async fn remove(path_or_name: &str, force: bool) -> MicrosandboxResult<()>
<Accordion title="Example">
rust
Snapshot::remove("after-pip-install", false).await?;
</Accordion>

Remove a snapshot artifact (by digest, name, or path) and its index row. Refuses if the snapshot has indexed children unless force is set. The artifact directory is deleted on success and the parent's child count is decremented.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>path_or_name</code><span className="msb-type">&amp;str</span></div> <div className="msb-param-desc">Snapshot digest, name, or artifact path.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>force</code><span className="msb-type">bool</span></div> <div className="msb-param-desc">When <code>true</code>, remove even if the snapshot has indexed children.</div> </div> </div>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">reindex()</span>

rust
async fn reindex(dir: impl AsRef<Path>) -> MicrosandboxResult<usize>
<Accordion title="Example">
rust
let n = Snapshot::reindex("/data/snapshots").await?;
println!("indexed {n} snapshots");
</Accordion>

Rebuild the local index from the artifacts in dir. Upserts an index row for every artifact found, then recomputes parent-edge child counts in one pass so the cache stays honest about the current set of artifacts.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>dir</code><span className="msb-type">impl AsRef&lt;Path&gt;</span></div> <div className="msb-param-desc">Directory of artifacts to index.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">usize</span></div> <div className="msb-param-desc">Number of artifacts indexed.</div> </div> </div> <Accordion title="Example">
rust
let n = Snapshot::reindex("/data/snapshots").await?;
println!("indexed {n} snapshots");
</Accordion>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">save()</span>

<div className="msb-tags"><span className="msb-tag is-static">static</span><span className="msb-tag is-async">async</span></div>
rust
async fn save(name_or_path: &str, out: &Path, opts: SaveOpts) -> MicrosandboxResult<()>

Bundle a snapshot into a .tar.zst archive (or plain .tar) at out. The head snapshot is verified before bundling. The recorded manifest is archived as-is, so create the snapshot with record_integrity() when the archive will cross a trust boundary. See SaveOpts to also include ancestors and the OCI image cache.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>name_or_path</code><span className="msb-type">&amp;str</span></div> <div className="msb-param-desc">Snapshot name or artifact path to save.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>out</code><span className="msb-type">&amp;Path</span></div> <div className="msb-param-desc">Output archive path. Parent directories are created if missing.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#saveopts">SaveOpts</a></div> <div className="msb-param-desc">Bundling options. <code>SaveOpts::default()</code> writes the head snapshot only, zstd-compressed.</div> </div> </div> <Accordion title="Example">
rust
use microsandbox::snapshot::SaveOpts;
use std::path::Path;

Snapshot::save(
    "baseline",
    Path::new("/tmp/baseline.tar.zst"),
    SaveOpts { with_parents: true, with_image: true, ..Default::default() },
).await?;
</Accordion>

<span className="msb-recv">Snapshot::</span><span className="msb-hn">load()</span>

<div className="msb-tags"><span className="msb-tag is-static">static</span><span className="msb-tag is-async">async</span></div>
rust
async fn load(archive_path: &Path, dest: Option<&Path>) -> MicrosandboxResult<SnapshotHandle>
<Accordion title="Example">
rust
use std::path::Path;

let h = Snapshot::import(Path::new("/tmp/baseline.tar.zst"), None).await?;
println!("imported {}", h.digest());
</Accordion>

Unpack a snapshot archive (.tar.zst or .tar, detected from magic bytes) into the snapshots directory (or dest), routing any bundled image-cache entries into the global cache and registering everything found in the index. Recorded integrity is verified as artifacts land. Returns a handle for the head snapshot.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>archive_path</code><span className="msb-type">&amp;Path</span></div> <div className="msb-param-desc">Archive to unpack.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>dest</code><span className="msb-type">Option&lt;&amp;Path&gt;</span></div> <div className="msb-param-desc">Destination directory. <code>None</code> uses the default snapshots directory.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshothandle">SnapshotHandle</a></div> <div className="msb-param-desc">Handle for the head (last-listed) snapshot.</div> </div> </div> <Accordion title="Example">
rust
use std::path::Path;

let h = Snapshot::load(Path::new("/tmp/baseline.tar.zst"), None).await?;
println!("loaded {}", h.digest());
</Accordion>

Instance methods

Methods on an opened Snapshot artifact.

<span className="msb-recv">snap.</span><span className="msb-hn">digest()</span>

rust
fn digest(&self) -> &str

Canonical content digest of this snapshot's manifest (sha256:hex). This is the snapshot's identity.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">&amp;str</span></div> <div className="msb-param-desc">Manifest digest in <code>sha256:hex</code> form.</div> </div> </div>

<span className="msb-recv">snap.</span><span className="msb-hn">path()</span>

rust
fn path(&self) -> &Path

Path to the artifact directory holding the canonical snapshot.json descriptor and the captured upper file.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">&amp;Path</span></div> <div className="msb-param-desc">Artifact directory path.</div> </div> </div>

<span className="msb-recv">snap.</span><span className="msb-hn">manifest()</span>

rust
fn manifest(&self) -> &Manifest
<Accordion title="Example">
rust
let snap = Snapshot::open("baseline").await?;
let m = snap.manifest();
println!("{} @ {}", m.image.reference, m.image.manifest_digest);
</Accordion>

The parsed Manifest: schema, format, fstype, image reference, parent, creation time, labels, and upper-layer metadata.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#manifest">&amp;Manifest</a></div> <div className="msb-param-desc">Parsed snapshot manifest.</div> </div> </div>

<span className="msb-recv">snap.</span><span className="msb-hn">size_bytes()</span>

rust
fn size_bytes(&self) -> u64

Apparent size of the captured upper layer in bytes (the ext4 virtual size; sparse on disk).

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">u64</span></div> <div className="msb-param-desc">Upper-layer apparent size in bytes.</div> </div> </div>

<span className="msb-recv">snap.</span><span className="msb-hn">verify()</span>

rust
async fn verify(&self) -> MicrosandboxResult<SnapshotVerifyReport>
<Accordion title="Example">
rust
use microsandbox::snapshot::UpperVerifyStatus;

let snap = Snapshot::open("baseline").await?;
match snap.verify().await?.upper {
    UpperVerifyStatus::Verified { algorithm, .. } => println!("ok via {algorithm}"),
    UpperVerifyStatus::NotRecorded => println!("no integrity hash recorded"),
}
</Accordion>

Recompute the upper layer's content hash and compare it against the manifest. Walks data extents only, so a multi-GiB sparse file with a little data verifies in milliseconds. Returns NotRecorded when the manifest has no integrity descriptor; errors with SnapshotIntegrity on mismatch.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshotverifyreport">SnapshotVerifyReport</a></div> <div className="msb-param-desc">Digest, path, and upper-layer verification status.</div> </div> </div>

SnapshotHandle methods

Accessors and lifecycle on a SnapshotHandle (an index row). Returned by Snapshot::get(), Snapshot::list(), and Snapshot::load().

<span className="msb-recv">h.</span><span className="msb-hn">digest()</span>

rust
fn digest(&self) -> &str

Manifest digest (sha256:hex), the canonical identity.

<span className="msb-recv">h.</span><span className="msb-hn">name()</span>

rust
fn name(&self) -> Option<&str>

Name alias, or None for digest-only entries.

<span className="msb-recv">h.</span><span className="msb-hn">parent_digest()</span>

rust
fn parent_digest(&self) -> Option<&str>

The parent snapshot's digest, or None for a root. Always None today; populated once chained snapshots land.


<span className="msb-recv">h.</span><span className="msb-hn">scope()</span>

<div className="msb-tags"><span className="msb-tag is-instance">instance</span></div>
rust
fn scope(&self) -> SnapshotScope

Snapshot payload scope: SnapshotScope::Disk for a disk-only snapshot, Resumable once resumable snapshots land. Always Disk today.


<span className="msb-recv">h.</span><span className="msb-hn">image_ref()</span>

rust
fn image_ref(&self) -> &str

Image reference the snapshot was taken from.

<span className="msb-recv">h.</span><span className="msb-hn">format()</span>

rust
fn format(&self) -> SnapshotFormat

On-disk format of the upper layer.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshotformat">SnapshotFormat</a></div> <div className="msb-param-desc">Upper-layer format (<code>Raw</code> today).</div> </div> </div>

<span className="msb-recv">h.</span><span className="msb-hn">size_bytes()</span>

rust
fn size_bytes(&self) -> Option<u64>

Apparent size of the upper file at index time, if recorded.

<span className="msb-recv">h.</span><span className="msb-hn">created_at()</span>

rust
fn created_at(&self) -> chrono::NaiveDateTime

Snapshot creation time, parsed from the manifest.

<span className="msb-recv">h.</span><span className="msb-hn">path()</span>

rust
fn path(&self) -> &Path

Local artifact directory path.

<span className="msb-recv">h.</span><span className="msb-hn">open()</span>

rust
async fn open(&self) -> MicrosandboxResult<Snapshot>
<Accordion title="Example">
rust
let h = Snapshot::get("baseline").await?;
let snap = h.open().await?;
snap.verify().await?;
</Accordion>

Open the underlying artifact metadata, upgrading this lightweight handle to a full Snapshot. Equivalent to Snapshot::open(self.path()).

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div> <div className="msb-param-desc">The opened artifact.</div> </div> </div>

<span className="msb-recv">h.</span><span className="msb-hn">remove()</span>

rust
async fn remove(&self, force: bool) -> MicrosandboxResult<()>
<Accordion title="Example">
rust
let h = Snapshot::get("baseline").await?;
h.remove(false).await?;
</Accordion>

Remove this snapshot. Delegates to Snapshot::remove(self.digest(), force).

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>force</code><span className="msb-type">bool</span></div> <div className="msb-param-desc">When <code>true</code>, remove even if the snapshot has indexed children.</div> </div> </div>

Sandbox entry points

Snapshot-related methods that live on the sandbox builder and handle. See Sandbox for the full sandbox API.

<span className="msb-recv">.</span><span className="msb-hn">from_snapshot()</span>

rust
fn from_snapshot(self, path_or_name: impl Into<String>) -> Self
<Accordion title="Example">
rust
let sb = Sandbox::builder("api-restored")
    .from_snapshot("after-pip-install")
    .create()
    .await?;
</Accordion>

SandboxBuilder setter. Boot a fresh sandbox from a snapshot artifact. The snapshot already pins the image reference and digest, so this is mutually exclusive with image() and image_with(). The artifact is opened and its integrity verified at create() time, not here.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>path_or_name</code><span className="msb-type">impl Into&lt;String&gt;</span></div> <div className="msb-param-desc">Bare name resolved under the default snapshots directory, or a path to an artifact directory.</div> </div> </div>

<span className="msb-recv">h.</span><span className="msb-hn">snapshot()</span>

rust
async fn snapshot(&self, name: &str) -> MicrosandboxResult<Snapshot>

SandboxHandle method. Snapshot this sandbox under a bare name in the default snapshots directory (~/.microsandbox/snapshots/<name>/). The sandbox must be stopped or crashed; running sandboxes are rejected with SnapshotSandboxRunning. Local handles only. To place the artifact elsewhere, use Snapshot::save() / Snapshot::load() or move the self-contained artifact directory.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>name</code><span className="msb-type">&amp;str</span></div> <div className="msb-param-desc">Bare snapshot name.</div> </div> </div> <p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div> <div className="msb-param-desc">The created artifact handle.</div> </div> </div>

<span className="msb-recv">h.</span><span className="msb-hn">snapshot_to()</span>

rust
async fn snapshot_to(&self, path: impl AsRef<Path>) -> MicrosandboxResult<Snapshot>
<Accordion title="Example">
rust
let h = Sandbox::get("api").await?;
h.stop().await?;
let snap = h.snapshot_to("/data/snapshots/baseline").await?;
</Accordion>

SnapshotBuilder

Builder for a SnapshotConfig. Obtained via Snapshot::builder(name). A source sandbox is required (from_sandbox); the other setters are optional. Every setter returns Self, so calls chain.

rust
let snap = Snapshot::builder("after-pip-install")
    .from_sandbox("api")           // sandbox to capture
    .label("stage", "post-deps")
    .force()                       // overwrite if it exists
    .record_integrity()            // hash the upper layer
    .create()
    .await?;

<span className="msb-recv">.</span><span className="msb-hn">from_sandbox()</span>

<div className="msb-tags"><span className="msb-tag is-builder">builder</span></div>
rust
fn from_sandbox(self, source_sandbox: impl Into<String>) -> Self

Set the sandbox to capture. Required; build() and create() fail without it.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>source_sandbox</code><span className="msb-type">impl Into&lt;String&gt;</span></div> <div className="msb-param-desc">Name of the source sandbox. Must be stopped or crashed, and rooted on an OCI image.</div> </div> </div>

<span className="msb-recv">.</span><span className="msb-hn">dest_dir()</span>

<div className="msb-tags"><span className="msb-tag is-builder">builder</span></div>
rust
fn dest_dir(self, dest_dir: impl Into<PathBuf>) -> Self

Create the artifact under this parent directory instead of the default snapshots store. The artifact directory is dest_dir/<name>; the name stays the snapshot's identity either way.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>dest_dir</code><span className="msb-type">impl Into&lt;PathBuf&gt;</span></div> <div className="msb-param-desc">Parent directory to create the artifact in (e.g. a larger volume).</div> </div> </div>

<span className="msb-recv">.</span><span className="msb-hn">label()</span>

rust
fn label(self, key: impl Into<String>, value: impl Into<String>) -> Self

Add a user label. Can be called multiple times. Labels are sorted by key in the manifest's canonical form.

<p className="msb-label">Parameters</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><code>key</code><span className="msb-type">impl Into&lt;String&gt;</span></div> <div className="msb-param-desc">Label key.</div> </div> <div className="msb-param"> <div className="msb-param-key"><code>value</code><span className="msb-type">impl Into&lt;String&gt;</span></div> <div className="msb-param-desc">Label value.</div> </div> </div>

<span className="msb-recv">.</span><span className="msb-hn">force()</span>

rust
fn force(self) -> Self

Overwrite an existing artifact with the same name. Without this, creation fails with SnapshotAlreadyExists if the artifact directory exists.

<span className="msb-recv">.</span><span className="msb-hn">record_integrity()</span>

rust
fn record_integrity(self) -> Self

Compute and record an upper-layer content-integrity hash during creation. Recorded integrity is what verify() checks and what save/load rely on when crossing a trust boundary.


<span className="msb-recv">.</span><span className="msb-hn">resumable()</span>

<div className="msb-tags"><span className="msb-tag is-builder">builder</span></div>
rust
fn resumable(self) -> Self

Request a resumable snapshot (disk plus VM state). Accepted by the builder, but create() currently fails with Unsupported; resumable snapshots have not landed yet.

<span className="msb-recv">.</span><span className="msb-hn">build()</span>

rust
fn build(self) -> MicrosandboxResult<SnapshotConfig>

Materialize the SnapshotConfig without creating the snapshot. Errors with InvalidConfig if from_sandbox was not called. For capturing, use create instead; it calls build internally.

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#snapshotconfig">SnapshotConfig</a></div> <div className="msb-param-desc">Validated snapshot configuration.</div> </div> </div>

<span className="msb-recv">.</span><span className="msb-hn">create()</span>

rust
async fn create(self) -> MicrosandboxResult<Snapshot>

Build and execute the snapshot in one step. Equivalent to Snapshot::create(self.build()?).

<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div> <div className="msb-param-desc">The created artifact handle.</div> </div> </div>

Types

SnapshotHandle

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Returned by <a href="#snapshotget">Snapshot::get()</a> · <a href="#snapshotlist">Snapshot::list()</a> · <a href="#snapshotload">Snapshot::load()</a></p>

A lightweight handle backed by a local index row. Use open() to read the artifact metadata, and Snapshot::verify() for explicit content verification. All accessors are listed under SnapshotHandle methods.

MethodTypeDescription
digest()&strManifest digest (sha256:hex)
name()Option<&str>Name alias; None for digest-only entries
parent_digest()Option<&str>Parent snapshot digest, or None for a root
scope()SnapshotScopeSnapshot payload scope (Disk today)
image_ref()&strSource image reference
format()SnapshotFormatOn-disk upper format
size_bytes()Option<u64>Upper file size at index time
created_at()chrono::NaiveDateTimeCreation time from the manifest
path()&PathLocal artifact directory
open()Result<Snapshot>Open the underlying artifact
remove(force)Result<()>Remove this snapshot

SnapshotConfig

<p className="msb-backref">Used by <a href="#snapshotcreate">Snapshot::create()</a> · returned by <a href="#build">build()</a></p>

Inputs to create a snapshot. A type alias for SnapshotSpec. Usually built via SnapshotBuilder rather than constructed directly.

FieldTypeDescription
nameStringBare snapshot name; always the artifact directory's basename
dest_dirOption<PathBuf>Parent directory for the artifact; None = the default snapshots directory
source_sandboxStringName of the source sandbox; must be stopped
labelsVec<(String, String)>User-supplied labels
forceboolOverwrite an existing artifact with the same name
record_integrityboolCompute and record upper-layer integrity at creation
resumableboolRequest a resumable snapshot; returns an unsupported-feature error today

SnapshotFormat

<p className="msb-backref">Used by <a href="#h-format">format()</a> · <a href="#manifest">Manifest.format</a></p>

On-disk format of the captured upper layer. Today only Raw is produced; the variant exists so qcow2 chains drop in later without a schema migration.

ValueDescription
RawRaw ext4 image, sparse on disk
Qcow2qcow2 with optional backing chain (future)

SnapshotScope

<div className="msb-tags"><span className="msb-tag is-type">enum</span></div> <p className="msb-backref">Used by <a href="#h-scope">scope()</a> · <a href="#manifest">Manifest.scope</a></p>

Snapshot payload scope. Parsing accepts every known scope so older runtimes can still list and inspect artifacts they cannot restore; create and restore paths enforce support. Re-exported as microsandbox::snapshot::SnapshotScope.

ValueDescription
DiskDisk-only snapshot; captures the writable filesystem state
ResumableReserved for future memory/device-state capture

SaveOpts

<div className="msb-tags"><span className="msb-tag is-type">struct</span></div> <p className="msb-backref">Used by <a href="#snapshotsave">Snapshot::save()</a></p>

Options for Snapshot::save(). Implements Default; SaveOpts::default() writes the head snapshot only, zstd-compressed.

FieldTypeDescription
with_parentsboolWalk the parent chain and include each ancestor in the archive
with_imageboolBundle the OCI image artifacts (EROFS layers, fsmeta, VMDK descriptor) from the global cache so the archive boots offline
plain_tarboolSkip zstd compression and write a plain .tar. Default: zstd

SnapshotVerifyReport

<p className="msb-backref">Returned by <a href="#snap-verify">verify()</a></p>

Result of explicit snapshot verification.

FieldTypeDescription
digestStringSnapshot manifest digest
pathPathBufArtifact directory
upperUpperVerifyStatusUpper-layer content verification result

UpperVerifyStatus

<p className="msb-backref">Used by <a href="#snapshotverifyreport">SnapshotVerifyReport.upper</a></p>

Upper-layer content verification result.

VariantFieldsDescription
NotRecorded-No content integrity descriptor was recorded in the manifest
Verified- algorithm: String
  • digest: String | Recorded integrity matched the computed digest |

Manifest

<p className="msb-backref">Returned by <a href="#snap-manifest">manifest()</a></p>

The snapshot artifact manifest, the source of truth for an artifact, serialized as the snapshot.json descriptor (DESCRIPTOR_FILENAME). Re-exported as microsandbox::snapshot::Manifest. Its SHA-256 digest over the canonical byte form is the snapshot's identity. Field order is load-bearing (it determines the canonical byte layout) and must not be reordered.

FieldTypeDescription
schemau32Manifest schema version; readers reject unknown values
artifactStringArtifact kind; always "snapshot"
scopeSnapshotScopePayload scope; only disk snapshots are created today
formatSnapshotFormatOn-disk format of the upper layer
fstypeStringFilesystem type inside the upper (e.g. ext4)
imageImageRefImage the snapshot was taken from
parentOption<String>Parent snapshot digest, or None for a root
created_atStringRFC 3339 creation timestamp
labelsBTreeMap<String, String>User-supplied labels, sorted by key in canonical form
upperUpperLayerThe captured upper layer
source_sandboxOption<String>Best-effort name of the source sandbox (informational)

ImageRef

<p className="msb-backref">Used by <a href="#manifest">Manifest.image</a></p>

Reference to the OCI image the snapshot was taken from. Re-exported as microsandbox::snapshot::ImageRef.

FieldTypeDescription
referenceStringHuman-readable image reference (e.g. docker.io/library/python:3.12)
manifest_digestStringDigest of the OCI manifest, in sha256:hex form

UpperLayer

<p className="msb-backref">Used by <a href="#manifest">Manifest.upper</a></p>

Captured upper-layer file metadata. Re-exported as microsandbox::snapshot::UpperLayer.

FieldTypeDescription
fileStringFilename inside the artifact directory (e.g. upper.ext4)
size_bytesu64Apparent size in bytes (ext4 virtual size; sparse on disk)
integrityOption<UpperIntegrity>Optional content integrity descriptor; None on local hot paths

UpperIntegrity

<p className="msb-backref">Used by <a href="#upperlayer">UpperLayer.integrity</a></p>

Content integrity descriptor for the captured upper layer.

FieldTypeDescription
algorithmStringDigest algorithm name (e.g. msb-sparse-sha256-v1)
digestStringAlgorithm output, in sha256:hex form for current algorithms