Documentation
¶
Overview ¶
Package snapshot pushes and pulls cocoon VM snapshots as OCI artifacts.
A snapshot in epoch is an OCI 1.1 image manifest with artifactType `application/vnd.cocoonstack.snapshot.v1+json`. The manifest carries:
- A config blob (mediaType vnd.cocoonstack.snapshot.config.v1+json) containing structured cocoon VM metadata (cpu, memory, image ref, ...).
- One layer blob per file inside `cocoon snapshot export -o -` tar output, with the OCI standard `org.opencontainers.image.title` annotation set to the original filename so the puller can reassemble the tar and feed it to `cocoon snapshot import`.
- Optional `cocoonstack.snapshot.baseimage` annotation when the operator supplies one with `epoch push --base-image <ref>`.
epoch never reads cocoon's filesystem directly. Push streams the snapshot from `cocoon snapshot export <name> -o -` stdout; pull writes back via `cocoon snapshot import <name>` stdin. The cocoon binary is the only point of contact between epoch and cocoon's local storage layout.
Index ¶
- Constants
- func FetchSnapshotConfig(ctx context.Context, dl Downloader, name string, desc manifest.Descriptor) (*manifest.SnapshotConfig, error)
- func ResolveCocoonBinary(envValue string) (string, error)
- func Stream(ctx context.Context, raw []byte, dl Downloader, opts StreamOptions) error
- func StreamParsed(ctx context.Context, m *manifest.OCIManifest, dl Downloader, ...) error
- type CocoonRunner
- type Downloader
- type ExecCocoon
- func (e *ExecCocoon) Export(ctx context.Context, name string) (io.ReadCloser, func() error, error)
- func (e *ExecCocoon) ImageImport(ctx context.Context, name string) (io.WriteCloser, func() error, error)
- func (e *ExecCocoon) Import(ctx context.Context, opts ImportOptions) (io.WriteCloser, func() error, error)
- type ImportOptions
- type PullOptions
- type Puller
- type PushOptions
- type PushResult
- type Pusher
- type StreamOptions
- type Uploader
Constants ¶
const ( // CocoonBinaryEnv lets users override the cocoon binary used by epoch's // snapshot push/pull (defaults to looking up `cocoon` on $PATH). CocoonBinaryEnv = "EPOCH_COCOON_BINARY" )
Variables ¶
This section is empty.
Functions ¶
func FetchSnapshotConfig ¶
func FetchSnapshotConfig(ctx context.Context, dl Downloader, name string, desc manifest.Descriptor) (*manifest.SnapshotConfig, error)
FetchSnapshotConfig downloads and parses the snapshot config blob referenced by the given descriptor. Exported so the in-process tag-detail API can reuse it via the same Downloader adapter that snapshot.StreamParsed already uses, instead of duplicating the parse/stream/decode dance.
Returns an error when desc.MediaType is not manifest.MediaTypeSnapshotConfig — that should never happen for a tag the catalog has classified as a snapshot, so callers can treat it as corrupt state and surface it.
func ResolveCocoonBinary ¶
ResolveCocoonBinary picks the cocoon binary path from $EPOCH_COCOON_BINARY, falling back to looking up `cocoon` on $PATH. Returns an error if neither is reachable.
func Stream ¶
func Stream(ctx context.Context, raw []byte, dl Downloader, opts StreamOptions) error
Stream classifies the manifest as a snapshot, fetches its config blob, and writes the cocoon-import tar (snapshot.json envelope + every layer entry) to opts.Writer. It is the function shared between snapshot.Puller (which writes to cocoon's stdin) and epoch's server-side /dl/{name} handler (which writes to the HTTP response body).
Stream does not invoke cocoon — it only reassembles the tar. The caller is responsible for piping the bytes to wherever they should land.
func StreamParsed ¶
func StreamParsed(ctx context.Context, m *manifest.OCIManifest, dl Downloader, opts StreamOptions) error
StreamParsed is the same as Stream but accepts an already-parsed manifest. Callers that have already classified and parsed the manifest (e.g. the /dl/ handler) use this to avoid a redundant JSON unmarshal.
Types ¶
type CocoonRunner ¶
type CocoonRunner interface {
// Export runs `cocoon snapshot export <name> -o -` and returns a reader
// for the resulting tar stream plus a wait function the caller invokes
// once the stream is fully consumed.
Export(ctx context.Context, name string) (io.ReadCloser, func() error, error)
// Import runs `cocoon snapshot import <name>` (with optional --description)
// and returns a writer for the tar stream plus a wait function. The caller
// closes the writer to signal end-of-stream and then calls wait.
Import(ctx context.Context, opts ImportOptions) (io.WriteCloser, func() error, error)
}
CocoonRunner abstracts how snapshot.Pusher and snapshot.Puller talk to the local `cocoon` CLI. The default implementation ExecCocoon runs `cocoon` as a subprocess; tests can substitute a fake.
type Downloader ¶
type Downloader interface {
GetManifest(ctx context.Context, name, tag string) ([]byte, string, error)
GetBlob(ctx context.Context, name, digest string) (io.ReadCloser, error)
}
Downloader is the registry-side surface needed by Puller.
type ExecCocoon ¶
type ExecCocoon struct {
// Binary is the resolved cocoon binary path. Use [ResolveCocoonBinary]
// to populate it from $EPOCH_COCOON_BINARY or $PATH.
Binary string
// Stderr receives the cocoon subprocess stderr. Defaults to os.Stderr
// when nil.
Stderr io.Writer
}
ExecCocoon is the default CocoonRunner backed by an actual `cocoon` binary on $PATH (or the path in $EPOCH_COCOON_BINARY).
func (*ExecCocoon) Export ¶
func (e *ExecCocoon) Export(ctx context.Context, name string) (io.ReadCloser, func() error, error)
Export runs `cocoon snapshot export <name> -o -` and returns its stdout stream and a wait function.
func (*ExecCocoon) ImageImport ¶
func (e *ExecCocoon) ImageImport(ctx context.Context, name string) (io.WriteCloser, func() error, error)
ImageImport runs `cocoon image import <name>` and returns its stdin pipe and a wait function. Used by the cloudimg package; lives here so the snapshot package owns the single `cocoon` exec helper.
func (*ExecCocoon) Import ¶
func (e *ExecCocoon) Import(ctx context.Context, opts ImportOptions) (io.WriteCloser, func() error, error)
Import runs `cocoon snapshot import <name>` and returns its stdin pipe and a wait function. The caller writes the tar stream, then closes the pipe, then calls wait.
type ImportOptions ¶
ImportOptions configures `cocoon snapshot import`.
type PullOptions ¶
type PullOptions struct {
// Name is the OCI repository name. Required.
Name string
// Tag is the OCI tag. Defaults to "latest".
Tag string
// LocalName overrides the cocoon-side snapshot name on import.
// Empty means reuse Name.
LocalName string
// Description is forwarded to `cocoon snapshot import --description`.
Description string
// Progress receives one-line status updates. May be nil.
Progress func(string)
}
PullOptions configures a snapshot pull.
type Puller ¶
type Puller struct {
Downloader Downloader
Cocoon CocoonRunner
}
Puller fetches a snapshot OCI artifact and pipes it into `cocoon snapshot import`.
func (*Puller) Pull ¶
func (p *Puller) Pull(ctx context.Context, opts PullOptions) error
Pull downloads a snapshot artifact from the registry, reassembles its layers into a tar stream, and feeds it to `cocoon snapshot import`.
Errors during streaming close the cocoon stdin pipe so the import process observes EOF and exits cleanly; the original streaming error wins over the downstream wait error.
type PushOptions ¶
type PushOptions struct {
// Name is the OCI repository name. Required.
Name string
// Tag is the OCI tag. Defaults to "latest".
Tag string
// BaseImage is the optional cocoonstack.snapshot.baseimage annotation
// value (an OCI ref like "ghcr.io/cocoonstack/cocoon/ubuntu:24.04").
// When empty the annotation is omitted.
BaseImage string
// Source identifies the producer in the manifest annotations
// (org.opencontainers.image.source). Optional.
Source string
// Revision is the org.opencontainers.image.revision annotation. Optional.
Revision string
// Progress receives one-line status updates. May be nil.
Progress func(string)
}
PushOptions configures a snapshot push.
type PushResult ¶
type PushResult struct {
Name string
Tag string
ManifestDigest string // sha256:<hex>
ManifestBytes []byte
TotalSize int64
LayerCount int
}
PushResult summarizes a successful snapshot push.
type Pusher ¶
type Pusher struct {
Uploader Uploader
Cocoon CocoonRunner
}
Pusher uploads cocoon VM snapshots into an OCI registry.
func (*Pusher) Push ¶
func (p *Pusher) Push(ctx context.Context, opts PushOptions) (*PushResult, error)
Push streams a snapshot from `cocoon snapshot export` and writes an OCI snapshot artifact to the registry.
The data flow is:
- start `cocoon snapshot export <name> -o -`
- read tar entries from its stdout, hashing each one to a temp file and uploading as a content-addressable blob
- translate the snapshot.json envelope into a snapshot config blob (mediaType vnd.cocoonstack.snapshot.config.v1+json) and upload it
- assemble an OCI image manifest with artifactType vnd.cocoonstack.snapshot.v1+json and PUT it under name:tag
type StreamOptions ¶
type StreamOptions struct {
// Name is the OCI repository name used to fetch layer blobs. Required.
Name string
// LocalName overrides the snapshot name written into the rebuilt
// snapshot.json envelope. Empty falls back to Name so the importer
// reuses the registry repository name.
LocalName string
// Writer is the destination for the cocoon-import-shaped tar stream.
// Required.
Writer io.Writer
// Progress receives one-line status updates per layer. May be nil.
Progress func(string)
}
StreamOptions configures Stream.
type Uploader ¶
type Uploader interface {
BlobExists(ctx context.Context, name, digest string) (bool, error)
PutBlob(ctx context.Context, name, digest string, body io.Reader, size int64) error
PutManifest(ctx context.Context, name, tag string, data []byte, contentType string) error
}
Uploader is the registry-side surface needed by Pusher. The HTTP `registryclient.Client` satisfies this interface; an in-process implementation could too.