Documentation
¶
Overview ¶
Package rootfs is the Linux raw-Firecracker implementation of image.Store. It pulls user images and seals them into squashfs rootfs files, injecting the in-VM hpcc-agent so the host-side vsock client has something to talk to once the microVM boots.
On disk each prepared artifact is one regular file under CacheDir named "<algo>-<hex>.sqsh" (e.g. "sha256-abc123…ef.sqsh"). Colons in the user digest are not portable in filenames on every host filesystem worth caring about, so we encode them as a dash and reverse the mapping when listing. The ".sqsh" suffix is part of the contract — it lets ad-hoc tooling tell prepared rootfs files apart from anything else an operator might drop into CacheDir, and lets GetExistingImages skip strays without parsing them.
PullImage builds the prepared rootfs in three streaming stages: (1) crane.Pull fetches the user image and we sanity-check its digest matches expectedDigest. (2) mutate.Extract gives us a flattened tarball with whiteouts already applied. (3) we stream the tarball through the in-tree squashfs writer (github.com/aarani/hpcc/squashfs), mapping each tar entry to a squashfs Create* call. No staging directory on the host; no shell-outs to `tar` or `mkfs.*`; no temp spool for the layer tar.
The agent injection and standard-mountpoint setup happen inline against the same squashfs writer — /.hpcc/agent is written from the bytes the worker has on hand, and /proc /sys /dev /tmp /run are created (if the user's tar didn't already include them) so the agent's setupInit can mount tmpfses on top of them without first needing to mkdir on a read-only rootfs.
Why squashfs rather than ext4? Read-only by design, naturally streaming-writable from a tar without a staging dir, and the host has no GPL e2fsprogs / squashfs-tools shell-out in the hot path. The kernel mounts the result read-only as /dev/vda inside the guest. See docs/plan/phase-4-distributed.md §4.3 and §4.14.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrTarEntryCountExceeded = errors.New("rootfs: tar entry count exceeded cap")
ErrTarEntryCountExceeded is returned when streamTarToSquashfs sees more tar entries than maxTarEntryCount.
var ErrTarTotalBytesExceeded = errors.New("rootfs: tar total bytes exceeded cap")
ErrTarTotalBytesExceeded is returned when streamTarToSquashfs sees more logical file content than maxTarTotalBytes — either a single header declares a size past the cap, or cumulative copies cross it.
Functions ¶
This section is empty.
Types ¶
type AgentBinaries ¶
AgentBinaries lists the host filesystem paths of the per-arch hpcc-agent binaries the worker has built (or shipped). The Store reads from these when laying down the agent inside the rootfs at /.hpcc/agent before the squashfs image is sealed. Windows is absent on purpose — that path goes through cdimage instead.
type Store ¶
type Store struct {
// CacheDir is where prepared rootfs files live. One file per
// user-image digest; the file path is the artifact handed to
// the Firecracker driver.
CacheDir string
// Agent is the per-arch hpcc-agent binaries to inject as PID 1
// inside the prepared rootfs.
Agent AgentBinaries
}
Store implements image.Store on top of an on-disk rootfs cache. The zero value is not valid: CacheDir must be a writable directory, and Agent must cover every architecture for which images will be pulled.
func (*Store) GetExistingImages ¶
GetExistingImages enumerates the user-image digests of every prepared rootfs file in CacheDir. Files whose name doesn't match the "<algo>-<hex>.sqsh" shape are skipped — operators sometimes stage scratch files or the in-progress output of a crashed build alongside finished artifacts, and treating those as catalogue entries would surface bogus digests in the worker's heartbeat.
A missing CacheDir is not an error: a fresh worker host hasn't prepared anything yet, and the empty result is the right answer.
func (*Store) PathFor ¶
PathFor returns the absolute on-disk path of the prepared rootfs for userDigest, whether or not the file has been built yet. The raw Firecracker runtime calls this to find the squashfs image to attach as /dev/vda inside the microVM.
func (*Store) PullImage ¶
PullImage pulls imagePath, verifies it matches expectedDigest, streams its flattened layer tar through the squashfs writer (injecting /.hpcc/agent and standard mountpoints inline), and publishes the result as CacheDir/<algo>-<hex>.sqsh.
The build runs against a "<final>.tmp" sibling and atomically renames into place on success — partial files left behind by a crash never look like a finished artifact to GetExistingImages.
func (*Store) UntagImage ¶
UntagImage removes the prepared rootfs for userDigest. A missing file is not an error — eviction can race against a crash that left no artifact behind, and against catalogue/disk drift in either direction. The caller treats this as best-effort cleanup so the blob becomes reclaimable; the in-memory catalogue entry is the authoritative "do we have this digest" signal.