Documentation
¶
Index ¶
- Variables
- type BuildKitProvider
- type BuildResult
- type BuildStack
- type Builder
- func (b *Builder) AnalyzeApp(ctx context.Context, state *build_v1alpha.BuilderAnalyzeApp) error
- func (b *Builder) BuildFromPrepared(ctx context.Context, state *build_v1alpha.BuilderBuildFromPrepared) error
- func (b *Builder) BuildFromTar(ctx context.Context, state *build_v1alpha.BuilderBuildFromTar) error
- func (b *Builder) PrepareUpload(ctx context.Context, state *build_v1alpha.BuilderPrepareUpload) error
- type Buildkit
- type ConfigInputs
- type ImageConfig
- type SagaBuilder
- func (s *SagaBuilder) AnalyzeApp(ctx context.Context, state *build_v1alpha.BuilderAnalyzeApp) error
- func (s *SagaBuilder) BuildFromPrepared(ctx context.Context, state *build_v1alpha.BuilderBuildFromPrepared) error
- func (s *SagaBuilder) BuildFromTar(ctx context.Context, state *build_v1alpha.BuilderBuildFromTar) error
- func (s *SagaBuilder) Init() error
- func (s *SagaBuilder) PrepareUpload(ctx context.Context, state *build_v1alpha.BuilderPrepareUpload) error
- func (s *SagaBuilder) Recover(ctx context.Context) error
- type StatusRegistry
- type StatusSender
- type StreamRegistry
- func (s *StreamRegistry) Cleanup(streamID string) error
- func (s *StreamRegistry) MarkStaged(streamID, path string)
- func (s *StreamRegistry) Register(streamID string, r io.Reader)
- func (s *StreamRegistry) Stage(streamID string) (string, error)
- func (s *StreamRegistry) StagedPath(streamID string) (string, bool)
- type TransformOptions
- func WithBuildArg(key, val string) TransformOptions
- func WithBuildArgs(args map[string]string) TransformOptions
- func WithCacheDir(dir string) TransformOptions
- func WithPhaseUpdates(fn func(phase string)) TransformOptions
- func WithStatusUpdates(fn func(ss *client.SolveStatus, sj []byte)) TransformOptions
Constants ¶
This section is empty.
Variables ¶
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)
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 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
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:
- Entry point registers an io.Reader with a generated stream ID and starts a saga carrying only the ID.
- The first saga action calls Stage to read the registered stream and extract its tar contents to a fresh subdirectory.
- 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