Installation sets up the builder, so a raised mesh can produce

Genesis ended with a mesh that runs and cannot make anything: every module in
the catalogue names artifacts and nothing had built them, so the first thing
anybody had to do was install a builder by hand.

The installer already carries one — it is what built the control plane — so
this is the same two acts the control plane goes through, in the same order:
publish it, so the mesh names it by a digest its own registry assigned rather
than a local identity nothing else can fetch, then install it as an ordinary
module pinned to that. And then the part only it needs, a broker account, issued
before the push so it arrives with the declaration rather than after it.

Verified on a bare machine: the install ends with a builder running, and that
mesh then built the shared base images and a module on top of them with nobody
helping it.
This commit is contained in:
2026-09-14 12:31:43 +02:00
parent 3dfe574e46
commit 8eeb28f00b
4 changed files with 138 additions and 10 deletions
+29 -2
View File
@@ -52,6 +52,7 @@ const (
StepPublish Step = "publish"
StepControlPlane Step = "control-plane"
StepRetire Step = "retire"
StepBuilder Step = "builder"
)
// Steps in the order they happen, so a failure can say "step 2 of 11".
@@ -67,7 +68,7 @@ const (
// mesh made, out of a repository and a commit it can name, and can therefore make again.
var Steps = []Step{
StepPreflight, StepLoad, StepBuild, StepBundle, StepApply, StepVerify,
StepEnrol, StepRegistry, StepPublish, StepControlPlane, StepRetire,
StepEnrol, StepRegistry, StepPublish, StepControlPlane, StepRetire, StepBuilder,
}
// Error is a failure, named by the step it happened in.
@@ -182,6 +183,12 @@ type Result struct {
ImageTags []string `json:"image-tags,omitempty"`
// ImageHeld is true when the machine already held it and nothing was loaded.
ImageHeld bool `json:"image-already-held,omitempty"`
// BuilderPublished is where the builder's image ended up, and BuilderInstalled whether it is
// a module on this machine. A mesh without them runs and cannot produce.
BuilderPublished string `json:"builder-image,omitempty"`
BuilderInstalled bool `json:"builder-installed,omitempty"`
BuilderAccount bool `json:"builder-account-issued,omitempty"`
// Built is what the genesis build produced, and BuiltFrom is the commit it actually built.
//
// Reported because they are the difference between a mesh that can rebuild its control plane
@@ -500,7 +507,7 @@ func Run(ctx context.Context, o Options, d Deps, say func(string)) (Result, erro
return result, failed(StepControlPlane, err)
}
// ---- 10. retire -----------------------------------------------------------------------
// ---- 11. retire -----------------------------------------------------------------------
say("retire — the temporary control plane is dropped from the bundle")
retired, err := RetireTheTemporaryControlPlane(ctx, o, sys, rewritten.Bundle, d.Run, say)
result.TemporaryRetired = retired.Gone || retired.Already
@@ -509,8 +516,28 @@ func Run(ctx context.Context, o Options, d Deps, say func(string)) (Result, erro
return result, failed(StepRetire, err)
}
// ---- 12. builder ----------------------------------------------------------------------
//
// **Last, and part of installing rather than after it.** What the steps above produce is a mesh
// that runs and cannot make anything — every module in the catalogue names artifacts and
// nothing has built them. The builder is carried in this installer, because it is what built
// the control plane; putting it in the registry and installing it as a module is what turns a
// mesh that runs into a mesh that can produce.
say("builder — the mesh gets the thing that makes everything else")
// The PERMANENT control plane, not the temporary one: by here the temporary is gone, and the
// module this installs is assigned through the thing that will still be running afterwards.
permanentControl := controlPlane{container: ControlPlaneModule, run: d.Run, timeout: o.Timeout}
builder, err := InstallBuilder(ctx, o, d, permanentControl, loaded.ID, say)
result.BuilderPublished = builder.Published.Reference
result.BuilderInstalled = builder.Installed.Assigned || builder.Installed.Known
result.BuilderAccount = builder.Account
if err != nil {
return result, failed(StepBuilder, err)
}
say("\nthis machine is a mesh of one node, and the control plane it runs is a module " +
"pinned to an image its own registry serves.")
say("it holds a builder, so it can make the rest of the catalogue rather than be handed it.")
say("what remains is somebody else's: adding nodes, and assigning what they should run.")
return result, nil