build

package
v0.11.1 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 2026 License: Apache-2.0 Imports: 51 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrStreamUnavailable = errors.New("stream unavailable")

ErrStreamUnavailable is returned by Stage when neither an active reader nor a previously staged path exists for the given stream ID. This is the expected failure when recovering a saga whose tar stream was lost in a crash before the first stage attempt.

Functions

This section is empty.

Types

type BuildKitProvider added in v0.11.1

type BuildKitProvider interface {
	Client(ctx context.Context) (*buildkitclient.Client, error)
	SocketPath() string
	IsRunning() bool
}

BuildKitProvider is the subset of *buildkit.Component the builder depends on. Abstracting it as an interface lets unit tests inject a fake daemon (e.g. one whose Client fails) instead of standing up a real containerd-managed buildkitd.

type BuildResult

type BuildResult struct {
	Entrypoint      string // The entrypoint (from stack or image ENTRYPOINT)
	Command         string // The command (from image CMD)
	ManifestDigest  string
	WorkingDir      string
	DetectionEvents []stackbuild.DetectionEvent
}

type BuildStack

type BuildStack struct {
	Stack   string
	CodeDir string
	Input   string

	Version     string
	OnBuild     []string
	AlpineImage string

	// EnvVars are user-configured environment variables to inject into the build.
	// For auto-stack builds, these are set on intermediate LLB states before
	// onBuild commands and asset precompilation steps.
	EnvVars map[string]string
}

type Builder

type Builder struct {
	Log *slog.Logger
	EAS *entityserver_v1alpha.EntityAccessClient

	TempDir     string
	Registry    string
	DNSHostname string // Cloud-provisioned DNS hostname for default route display
	DataPath    string

	Resolver  netresolve.Resolver
	LogWriter observability.LogWriter

	// BuildKit is the persistent BuildKit component for container image builds.
	// When set, uses the shared daemon instead of launching ephemeral sandboxes.
	BuildKit BuildKitProvider
	// contains filtered or unexported fields
}

func NewBuilder

func NewBuilder(log *slog.Logger, eas *entityserver_v1alpha.EntityAccessClient, appClient *app.Client, addonsClient *app_v1alpha.AddonsClient, res netresolve.Resolver, tmpdir string, logWriter observability.LogWriter, dnsHostname string, bk *buildkit.Component, dataPath string) *Builder

func (*Builder) AnalyzeApp added in v0.2.0

func (b *Builder) AnalyzeApp(ctx context.Context, state *build_v1alpha.BuilderAnalyzeApp) error

AnalyzeApp analyzes an app without building it, returning detected stack, services, and configuration.

func (*Builder) BuildFromPrepared added in v0.6.0

func (b *Builder) BuildFromPrepared(ctx context.Context, state *build_v1alpha.BuilderBuildFromPrepared) error

func (*Builder) BuildFromTar

func (b *Builder) BuildFromTar(ctx context.Context, state *build_v1alpha.BuilderBuildFromTar) error

func (*Builder) PrepareUpload added in v0.6.0

func (b *Builder) PrepareUpload(ctx context.Context, state *build_v1alpha.BuilderPrepareUpload) error

type Buildkit

type Buildkit struct {
	Client *client.Client

	Log *slog.Logger

	// RegistryURLOverride is used for fetching image configs when the push URL
	// is not accessible from the current host (e.g., in tests where push goes to
	// a docker network address but fetch needs localhost:port)
	RegistryURLOverride string
}

func (*Buildkit) BuildImage

func (b *Buildkit) BuildImage(
	ctx context.Context,
	dfs fsutil.FS,
	bs BuildStack,
	app, imageURL string,
	tos ...TransformOptions,
) (*BuildResult, error)

func (*Buildkit) Transform

func (b *Buildkit) Transform(ctx context.Context, dfs fsutil.FS, tos ...TransformOptions) (io.ReadCloser, chan struct{}, error)

type ConfigInputs added in v0.2.0

type ConfigInputs struct {
	// BuildResult contains entrypoint, working dir, and image entrypoint/cmd from the build
	BuildResult *BuildResult

	// AppConfig is the parsed app.toml configuration (may be nil)
	AppConfig *appconfig.AppConfig

	// ProcfileServices maps service names to commands from the Procfile (may be nil)
	ProcfileServices map[string]string

	// ExistingConfig is the current config to preserve manual env vars from
	ExistingConfig core_v1alpha.ConfigSpec

	// CliEnvVars are environment variables passed via CLI flags (e.g., miren deploy -e KEY=VALUE)
	// These are applied with source="manual" and take precedence over app.toml vars
	CliEnvVars []*build_v1alpha.EnvironmentVariable
}

ConfigInputs holds all the inputs needed to build an app version config.

type ImageConfig

type ImageConfig struct {
	Services map[string]string
}

type SagaBuilder added in v0.11.1

type SagaBuilder struct {
	// contains filtered or unexported fields
}

SagaBuilder is the saga-backed implementation of the build_v1alpha Builder RPC interface. It wraps the existing *Builder (which keeps shared collaborators like the entity client, app client, BuildKit component, and source cache locks), adds a per-instance saga executor + registry, and exposes BuildFromTar / BuildFromPrepared implementations that drive the build-from-tar saga end to end.

PrepareUpload and AnalyzeApp delegate straight through to the inner Builder. Prepare is just session management, not a build, and AnalyzeApp is read-only — neither benefits from saga durability.

func NewSagaBuilder added in v0.11.1

func NewSagaBuilder(inner *Builder, sagaStorage saga.Storage, log *slog.Logger) *SagaBuilder

NewSagaBuilder constructs a SagaBuilder over an existing Builder. The caller still owns the Builder's collaborators (clients, log writer, BuildKit component); SagaBuilder layers saga execution + crash recovery on top without forking the underlying state.

func (*SagaBuilder) AnalyzeApp added in v0.11.1

func (s *SagaBuilder) AnalyzeApp(ctx context.Context, state *build_v1alpha.BuilderAnalyzeApp) error

AnalyzeApp is read-only.

func (*SagaBuilder) BuildFromPrepared added in v0.11.1

func (s *SagaBuilder) BuildFromPrepared(ctx context.Context, state *build_v1alpha.BuilderBuildFromPrepared) error

BuildFromPrepared mirrors BuildFromTar but starts from an upload session whose source tree is already on disk. The session lookup stays out of the saga (it's a pre-flight check, not a step we'd want to retry on recovery), then MarkStaged tells the registry the path is ready so the saga's receive-tar action returns it directly.

func (*SagaBuilder) BuildFromTar added in v0.11.1

func (s *SagaBuilder) BuildFromTar(ctx context.Context, state *build_v1alpha.BuilderBuildFromTar) error

BuildFromTar is the saga-backed implementation of the RPC method. Stream registration, status sender registration, and saga start all key off the same generated stream ID so the saga's actions can find the live reader and status sink by ID alone.

func (*SagaBuilder) Init added in v0.11.1

func (s *SagaBuilder) Init() error

Init registers the build-from-tar saga definition with the executor. It must be called once at startup, before serving RPC requests, so new builds can run. It deliberately does not recover in-flight sagas: recovery resumes a build's image push, which needs the cluster registry and the cluster.local name mapping, and those are established late in boot (after the coordinator's own startup). Recovery is split into Recover and driven from the boot sequence once those dependencies exist. See MIR-1285.

func (*SagaBuilder) PrepareUpload added in v0.11.1

func (s *SagaBuilder) PrepareUpload(ctx context.Context, state *build_v1alpha.BuilderPrepareUpload) error

PrepareUpload is a session-management op, not a build, so it routes straight to the inner Builder.

func (*SagaBuilder) Recover added in v0.11.1

func (s *SagaBuilder) Recover(ctx context.Context) error

Recover resumes any incomplete sagas left over from a previous process. It must run only after a resumed build's runtime dependencies (the registry listener and the cluster.local name mapping) are ready; running it mid-boot resumes the image push before those exist, so the build fails and rolls back (MIR-1285). The error is returned for the caller to log; recovery failures are not fatal, since new build requests can still be served.

type StatusRegistry added in v0.11.1

type StatusRegistry struct {
	// contains filtered or unexported fields
}

StatusRegistry maps stream IDs (the same handles StreamRegistry uses) to live StatusSenders. Saga actions retrieve a sender by ID without caring whether anyone's currently listening — SenderFor returns noop when nothing's registered, which gives recovery the right behavior for free.

func NewStatusRegistry added in v0.11.1

func NewStatusRegistry() *StatusRegistry

func (*StatusRegistry) Register added in v0.11.1

func (s *StatusRegistry) Register(streamID string, sender StatusSender)

Register associates a sender with a stream ID. The SagaBuilder calls this before saga.Start and Unregister after, so a sender's lifetime is bounded by one saga execution.

func (*StatusRegistry) SenderFor added in v0.11.1

func (s *StatusRegistry) SenderFor(streamID string) StatusSender

SenderFor returns the registered sender or a noop. Always returns a usable StatusSender so callers can avoid nil checks.

func (*StatusRegistry) Unregister added in v0.11.1

func (s *StatusRegistry) Unregister(streamID string)

Unregister drops the live sender for an ID. Idempotent — calling twice (e.g., from both a defer and an error path) is fine.

type StatusSender added in v0.11.1

type StatusSender interface {
	// SendMessage emits a free-form progress message ("Reading
	// application data", "Launching builder", etc.).
	SendMessage(msg string)

	// SendPhase translates a buildkit phase name into a user-facing
	// progress message, matching the mapping the pre-saga path used.
	SendPhase(phase string)

	// SendBuildkit emits the raw buildkit JSON status payload so the
	// CLI can render live vertex/log output.
	SendBuildkit(payload []byte)

	// SendError emits a user-facing error message. Returning the error
	// from the action is what surfaces failure through the saga; this
	// is the channel for the human-readable explanation.
	SendError(format string, args ...any)

	// SendLog emits a structured log entry. Currently only the
	// pre-saga "warn" path for local storage migration uses this.
	SendLog(level, text string, fields ...*build_v1alpha.LogField)
}

StatusSender lets saga actions emit progress, log lines, and errors back to the client that started the build without holding a direct reference to the per-request RPC stream. The SagaBuilder wraps a concrete stream into a sender and registers it under the stream ID for the duration of a saga; actions look it up by the same ID they already carry through saga inputs.

During recovery the sender returned by StatusRegistry.SenderFor is a noop, which is the right default — nobody's listening for live progress when the original CLI invocation is long gone.

func NewRPCStatusSender added in v0.11.1

func NewRPCStatusSender(s *stream.SendStreamClient[*build_v1alpha.Status], log *slog.Logger) StatusSender

NewRPCStatusSender wraps an RPC status stream. Passing a nil stream returns a sender that no-ops cleanly so callers don't have to special- case the "client didn't request status updates" path.

type StreamRegistry added in v0.11.1

type StreamRegistry struct {
	// contains filtered or unexported fields
}

StreamRegistry bridges non-serializable tar streams into the saga world by staging them to durable filesystem paths. The pattern, per RFD-35:

  1. Entry point registers an io.Reader with a generated stream ID and starts a saga carrying only the ID.
  2. The first saga action calls Stage to read the registered stream and extract its tar contents to a fresh subdirectory.
  3. If the saga later resumes after a crash, the stream is gone but the staged path is durable — Stage returns the existing path without touching any reader.

Stage and Cleanup are idempotent. Cleanup is safe to call from action compensation (on failure) and from a terminal saga step (on success); running it twice is a no-op.

func NewStreamRegistry added in v0.11.1

func NewStreamRegistry(baseDir string, log *slog.Logger) *StreamRegistry

NewStreamRegistry creates a registry that stages streams under baseDir. Each registered stream gets its own subdirectory so Cleanup is a single RemoveAll.

func (*StreamRegistry) Cleanup added in v0.11.1

func (s *StreamRegistry) Cleanup(streamID string) error

Cleanup removes any staged directory and forgets the stream ID. Idempotent: safe to call from both action compensation (failure path) and a terminal cleanup action (success path), and safe to call when nothing was ever staged. Keeps the registry entry until RemoveAll succeeds so a transient filesystem error doesn't leak the path — the next call can retry with the same ID.

func (*StreamRegistry) MarkStaged added in v0.11.1

func (s *StreamRegistry) MarkStaged(streamID, path string)

MarkStaged records an externally-prepared path as already staged for streamID. Used by BuildFromPrepared, where the source is already on disk from a PrepareUpload session and the saga's receive-tar action just needs to discover that path. Refuses to overwrite an existing entry: re-marking is silently dropped (with a warn-log) so a stale session ID can't blow away a legitimately-staged directory and leak it on disk.

func (*StreamRegistry) Register added in v0.11.1

func (s *StreamRegistry) Register(streamID string, r io.Reader)

Register associates an io.Reader with a stream ID. The reader is held in memory until Stage consumes it or Cleanup drops it. Re-registering an ID with an active reader replaces it; re-registering after staging is a no-op so recovery flows don't accidentally restart staging.

func (*StreamRegistry) Stage added in v0.11.1

func (s *StreamRegistry) Stage(streamID string) (string, error)

Stage extracts the registered stream's tar contents to a per-stream subdirectory and returns the path. On recovery, if the original reader is gone but a staged path exists, returns that path unchanged. Returns ErrStreamUnavailable when neither is available.

func (*StreamRegistry) StagedPath added in v0.11.1

func (s *StreamRegistry) StagedPath(streamID string) (string, bool)

StagedPath returns the staged directory if Stage previously succeeded for this ID. Useful for diagnostics and tests; the saga path itself flows through Stage's return value.

type TransformOptions

type TransformOptions func(*transformOpt)

func WithBuildArg

func WithBuildArg(key, val string) TransformOptions

func WithBuildArgs

func WithBuildArgs(args map[string]string) TransformOptions

func WithCacheDir

func WithCacheDir(dir string) TransformOptions

func WithPhaseUpdates

func WithPhaseUpdates(fn func(phase string)) TransformOptions

func WithStatusUpdates

func WithStatusUpdates(fn func(ss *client.SolveStatus, sj []byte)) TransformOptions

Jump to

Keyboard shortcuts

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