The builder builds one module and stops, with no broker and no registry
This is how a mesh is raised: the installer carries this program and runs it once, before anything exists, to produce the control plane from the same repository and path every later rebuild will use. What raises the mesh is then the same thing that maintains it, rather than a second mechanism exercised once per new mesh — which is how often enough to rot. With nowhere to publish, an image stays in the machine's own runtime and is named by the digest of its own configuration: the same identity the installer has always used for the image it carried.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Local is what a build publishes into when there is nowhere to publish yet.
|
||||
//
|
||||
// **This exists for exactly one moment: raising a mesh** (novox/hq ADR 0073). The installer builds
|
||||
// the control plane on the machine that is about to run it, and at that moment there is no registry
|
||||
// — the registry is installed afterwards, by the control plane this build produces. So the artifact
|
||||
// stays where the build left it: in the machine's own container runtime.
|
||||
//
|
||||
// That is not a weaker kind of pinning. An image held locally is named by the digest of its own
|
||||
// configuration, which is content-addressed and unforgeable and requires nothing to have served it
|
||||
// — the same identity the installer has always used for the image it carried. What changes when a
|
||||
// registry exists is not that the artifact becomes exact, but that something other than this
|
||||
// machine can fetch it.
|
||||
//
|
||||
// It is deliberately unable to publish an archive. An archive has no local identity to fall back
|
||||
// on: it is bytes that only mean something once something serves them at a URL. A build that
|
||||
// produces one before there is anywhere to put it has produced nothing usable, and saying so is
|
||||
// better than returning a path on a disk that no other machine can read.
|
||||
type Local struct {
|
||||
// Run is how docker is invoked, so a test does not need one.
|
||||
Run Runner
|
||||
}
|
||||
|
||||
// PublishImage leaves the image where the build put it, and names it by its own configuration.
|
||||
//
|
||||
// The local tag is not returned: a tag is a name somebody can move, and every other reference in a
|
||||
// resolved manifest is exact. The digest is read back from the runtime rather than computed, for
|
||||
// the same reason the registry publisher reads it back from the registry — what matters is what
|
||||
// will be served for that reference, and only the thing serving it can say.
|
||||
func (l Local) PublishImage(ctx context.Context, localTag, repository string) (string, error) {
|
||||
out, err := l.Run(ctx, "", "docker", "image", "inspect", "--format", "{{.Id}}", localTag)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("cannot read back the image just built as %s: %w", localTag, err)
|
||||
}
|
||||
id := strings.TrimSpace(out)
|
||||
if !strings.HasPrefix(id, "sha256:") || len(id) != len("sha256:")+64 {
|
||||
// Refused rather than passed on. A bundle naming an image by anything a person could move
|
||||
// is refused by the machine applying it, and a value that is not an identity would fail
|
||||
// there instead — one step further from the thing that could explain it.
|
||||
return "", fmt.Errorf(
|
||||
"the container runtime named the image just built %q, which is not an image id: "+
|
||||
"sha256 and sixty-four hex characters", id)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// PublishArchive refuses, and says why rather than inventing somewhere to put it.
|
||||
func (l Local) PublishArchive(ctx context.Context, repository string, body []byte, digest string) (string, error) {
|
||||
return "", fmt.Errorf(
|
||||
"%s declares an archive, and this build has nowhere to publish one. An image can stay in "+
|
||||
"the machine's own runtime and still be named exactly; an archive is bytes that mean "+
|
||||
"nothing until something serves them. Build this once the mesh has a registry",
|
||||
repository)
|
||||
}
|
||||
Reference in New Issue
Block a user