image

package
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package image resolves OCI images and serves their flattened rootfs, backed by primordium's content-addressable store (concurrency-safe, GC'd).

go-containerregistry pulls the manifest/config; the in-tree flatten package (a fixed fork of mutate.Extract) squashes the layers, resolving plain AND opaque whiteouts and repairing hardlinks whose target a higher layer deleted or overwrote; the flattened tar is converted into an uncompressed EROFS filesystem image, sector-padded, and cached by content hash under a per-(digest,codec,generation) identifier, so amd64/arm64 variants coexist. The cached blob doubles as a raw disk image: warm boots attach it to the microVM as a read-only virtio-blk device (RootfsFile pins it against GC for the VM's lifetime) and the guest MOUNTS it under a tmpfs-upper overlay rather than unpacking it; a cold pull stages the conversion to disk, commits it, then attaches.

The store lives under dirs.CacheDir()/images/<version> (i.e. ~/Library/Caches/ossein/images/<version> on darwin) — the version segment lets a future layout change ship beside the old cache.

Index

Constants

View Source
const (
	PullAlways  = "always"  // always re-resolve from the registry
	PullMissing = "missing" // resolve offline if seen before; else hit the registry
	PullNever   = "never"   // offline only; error if never resolved locally
)

Pull policies (Docker semantics). Default is PullMissing.

Variables

View Source
var (
	// ErrUnsupportedPlatform indicates a platform ossein cannot run
	// (anything other than linux/amd64 or linux/arm64).
	ErrUnsupportedPlatform = errors.New("unsupported platform")

	// ErrCache indicates a failure in the local content-addressed image cache
	// (locating, creating, or writing under the cache directory).
	ErrCache = errors.New("image cache failure")

	// ErrResolve indicates the image could not be pulled or resolved from its
	// registry.
	ErrResolve = errors.New("image resolution failure")
)

Functions

func CanonicalPlatform

func CanonicalPlatform(requested string) (platform, arch string, err error)

CanonicalPlatform validates and canonicalizes a Docker-style platform string to "linux/amd64" or "linux/arm64" — the only two ossein supports — and returns the bare arch ("amd64"/"arm64"). Empty means the host (arm64). amd64 on our arm64 host is what triggers Rosetta downstream.

Types

type Cache

type Cache interface {
	// AcquireFile returns the blob for identifier as a complete, immutable,
	// GC-pinned file on disk, calling fetch to completion on a miss (staged
	// to disk, not RAM). ossein always passes a NIL digest — the rootfs hash
	// is only known after flattening. The pin must be Released once the VM
	// no longer uses the file.
	AcquireFile(identifier string, dgst digest.Digest, fetch content.FetchFunc) (*cache.PinnedFile, error)
	// Invalidate drops identifier's index entry, so the next AcquireFile
	// re-fetches and re-hashes instead of verifying against the recorded
	// digest. RootfsFile needs it to recover from a stale entry (a surviving
	// index entry whose blob was reclaimed).
	Invalidate(identifier string) error
	// GarbageCollect reclaims cached blobs over the quota.
	GarbageCollect() (cache.GCStats, error)
	// Close flushes and releases the cache.
	Close() error
}

Cache is the content-addressable blob cache ossein needs: identifier → cached blob with fetch-on-miss, plus GC and Close. primordium's *content.Store satisfies it, so NewCache returns one directly — no wrapper.

The signatures deliberately use primordium types: this is a swap seam (the one place a different storage backend would plug in), not a full storage abstraction. Everything else in this package depends on Cache, not on *content.Store.

func NewCache

func NewCache() (Cache, error)

NewCache opens the image cache under <cache-dir>/images/<cacheLayoutVersion> (the app name segment comes from dirs.SetAppName, called once in main).

type Image

type Image struct {
	Ref      string
	Digest   string // manifest digest hex
	Config   v1.Config
	Platform v1.Platform
	// contains filtered or unexported fields
}

Image is a resolved image: manifest/config metadata plus a handle to fetch the flattened rootfs on demand.

func Import added in v0.2.0

func Import(store Cache, ref, platformStr string, src v1.Image) (*Image, error)

Import records src — an image that exists only locally (a build's output) — under ref for platformStr, exactly as a registry resolution would be, and returns it bound to the cache. After Import, `ossein run ref` resolves offline under the default pull policy, and the returned Image's RootfsFile flattens and caches the rootfs like a pull does (callers wanting a warm cache drive it to completion). The resolution is marked local: a later GC of the blob is reported as "rebuild", never re-fetched from a registry that never had it. ref must parse as an image reference; the digest is src's manifest digest.

func Resolve

func Resolve(ctx context.Context, store Cache, ref, platformStr, pull string) (*Image, error)

Resolve returns a bound *Image for ref at platform (empty = host), honoring the pull policy. It does NOT flatten the rootfs — that happens lazily via Rootfs. ctx bounds all registry traffic, including a lazy rootfs re-fetch triggered later by Rootfs (resolveSource captures this ctx).

PullAlways  — always hit the registry (remote.Get), then cache the resolution.
PullMissing — if ref@platform was resolved before, use the cached digest+config
              OFFLINE (no network); the rootfs blob is fetched lazily by Rootfs
              only if it turns out to be absent — by the pinned digest, so the
              cached resolution holds even if the tag has moved upstream (tags
              are only re-resolved on PullAlways). First-ever ref hits the
              registry. This is the default and skips the ~800 ms resolve on a
              warm run.
PullNever   — offline only: use the cached resolution; error if there is none.

Any other pull value is an error. The content-cache key is the manifest digest + codec: equivalent refs (debian == docker.io/library/debian:latest) and both arches coexist; a moved tag yields a new digest and the stale blob falls to GC. The codec segment makes a codec change (gzip→zstd) a clean miss rather than serving undecodable bytes.

func (*Image) RootfsFile

func (i *Image) RootfsFile() (*cache.PinnedFile, error)

RootfsFile returns the flattened rootfs blob as a complete, immutable, GC-pinned file (flattening and caching on miss), sized to a 512-byte multiple so it can be attached to the microVM as a raw read-only virtio-blk disk. The caller must Release the pin once the VM no longer needs the file.

Healing (previously healingReader): blob GC deletes cached blobs but never the index, so an identifier can survive with a digest whose blob is gone. The next acquire then re-flattens and verifies against the RECORDED digest, and any drift in how those bytes are produced (a codec bump, a flatten change) makes that verification fail forever — retries reproduce it, and --pull=always re-resolves the tag to the same identifier. Keyed on fault.ErrWriteFailure rather than a specific mismatch: every reason the store could not persist the blob leaves the same useless entry behind. Dropping it here turns a permanent failure into a one-boot one.

Directories

Path Synopsis
Package flatten squashes an OCI image's layer stack into one plain tar stream.
Package flatten squashes an OCI image's layer stack into one plain tar stream.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL