mesh/merge-gate head 37947ca4eed1 merged into trunk d8e785bb4b4b — pass: the change touches no module of the mesh's graph
mesh/repo-check head 37947ca4eed1 merged into trunk d8e785bb4b4b — pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
The installer could not raise a first node: the old bundle's control plane had no MESH_BUS_NATS and crash-looped, and the NATS bundle was refused because rootsecrets only knew the previous broker's guest:guest@ template. One bundle now, the NATS one. rootsecrets makes the controller's bus account and puts it in both placeholders (the address and the bcrypt hash in the carried user list), kept with its hash so a re-run writes the same bundle. Preflight refuses a template naming no bus connection it knows, naming the placeholder, instead of waiting out the verify step. The broker step adopts the bus as the nats module and refuses, by name, a catalogue without it or a server that is not the foundation's container.
100 lines
3.6 KiB
Go
100 lines
3.6 KiB
Go
// Package examples checks the bundles shipped in this directory.
|
|
//
|
|
// **Nothing checked them before.** `foundation-first-node.lock` is what a machine becomes when
|
|
// there is no mesh to ask — the one declaration applied with nothing to verify it against — and
|
|
// it was edited by hand and read by nobody but a running host.
|
|
package examples
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/declaration"
|
|
)
|
|
|
|
func bundle(t *testing.T) *declaration.Declaration {
|
|
t.Helper()
|
|
raw, err := os.ReadFile("foundation-first-node.lock")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
d, err := declaration.ParseFileTrusted(raw)
|
|
if err != nil {
|
|
t.Fatalf("the bundle a first node applies does not parse: %v", err)
|
|
}
|
|
return d
|
|
}
|
|
|
|
// Defends novox/hq ADR 0028: the foundation supplies the control plane and nothing else.
|
|
//
|
|
// The object store was foundation for months on the strength of "it cannot grant itself a bucket",
|
|
// which answers half the test. The control plane never needed one, and nothing noticed because
|
|
// nothing counted what the bundle holds.
|
|
func TestTheBundleCarriesTheFoundationAndTheControlPlaneAndNothingElse(t *testing.T) {
|
|
var images []string
|
|
for _, r := range bundle(t).Resources {
|
|
c, ok := r.(*declaration.Container)
|
|
if !ok {
|
|
continue
|
|
}
|
|
// The registry the images come from is the lab's, and is not what this asserts.
|
|
name := c.Image
|
|
if i := strings.LastIndex(name, "/"); i >= 0 {
|
|
name = name[i+1:]
|
|
}
|
|
images = append(images, strings.SplitN(name, "@", 2)[0])
|
|
}
|
|
sort.Strings(images)
|
|
|
|
want := []string{"mesh-controller", "nats", "postgres"}
|
|
if strings.Join(images, ",") != strings.Join(want, ",") {
|
|
t.Fatalf("the bundle carries %v; expected exactly %v.\n\n"+
|
|
"Adding one is a change to what every first node becomes, and to ADR 0006's "+
|
|
"membership — take it deliberately, not by editing a lock file.", images, want)
|
|
}
|
|
}
|
|
|
|
// The control plane is in the bundle, and the design overlooked it once by reasoning about
|
|
// foundation services rather than counting containers (novox/hq 03-DESIGN/01-to-be/07).
|
|
func TestTheControlPlaneIsCarriedToo(t *testing.T) {
|
|
for _, r := range bundle(t).Resources {
|
|
if c, ok := r.(*declaration.Container); ok && strings.Contains(c.Image, "mesh-controller") {
|
|
return
|
|
}
|
|
}
|
|
t.Fatal("nothing in the bundle starts the control plane, so the machine would raise a " +
|
|
"foundation and stop")
|
|
}
|
|
|
|
// One genesis bundle, on the bus the mesh runs on (novox/hq ADR 0331 §2). Two bundles let every bed
|
|
// and README name the one that could not raise a mesh, for weeks (issue 146).
|
|
func TestThereIsOneGenesisBundle(t *testing.T) {
|
|
bundles, err := filepath.Glob("*.lock")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(bundles) != 1 || bundles[0] != "foundation-first-node.lock" {
|
|
t.Fatalf("examples/ holds %v; it holds one genesis bundle, foundation-first-node.lock", bundles)
|
|
}
|
|
}
|
|
|
|
// The control plane the bundle raises is given the bus, with the account the installer fills and
|
|
// the certificate it pins (ADR 0331 §4); without it, it crash-loops for ever (issue 146).
|
|
func TestTheControlPlaneIsGivenTheBus(t *testing.T) {
|
|
for _, r := range bundle(t).Resources {
|
|
c, ok := r.(*declaration.Container)
|
|
if !ok || !strings.Contains(c.Image, "mesh-controller") {
|
|
continue
|
|
}
|
|
if !strings.HasPrefix(c.Env["MESH_BUS_NATS"], "nats://controller:bootstrap@") || c.Env["MESH_BROKER_CERTIFICATE"] == "" {
|
|
t.Fatalf("the control plane is given the bus %q and the certificate %q",
|
|
c.Env["MESH_BUS_NATS"], c.Env["MESH_BROKER_CERTIFICATE"])
|
|
}
|
|
return
|
|
}
|
|
t.Fatal("nothing in the bundle starts the control plane")
|
|
}
|