The only complete written-down copy of how a mesh is stood up was an integration test in the lab. That is why every bootstrap gap kept being found late: an install procedure that lives as a test fixture is exercised by whoever writes tests, never by whoever installs. This is that procedure. A separate binary, not a mesh-host subcommand. mesh-host says of itself that it connects to nothing and listens on nothing and that what it applies comes from a file, and that sentence is what makes an always-running root daemon auditable. An installer loads images and interrogates a control plane. Same tier, different program. The control plane's image is carried, not built and not fetched. The forge that holds its source runs on the mesh, so a bootstrap that had to fetch it would need a mesh in order to raise one. Embedding breaks that cycle the way the carried bundle breaks "copy it onto a machine and run it". The image id is read out of the saved tar before the runtime is asked anything, which is what makes the load idempotent: the installer can ask whether the machine already holds exactly this. Five steps, each idempotent and each saying whether it found or changed something, because this is run over and over by somebody getting a machine working. It stops at a running substrate with a control plane that replies — enrolment, the module catalogue and assignment are the next stage and are deliberately absent. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
169 lines
5.7 KiB
Go
169 lines
5.7 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-host/internal/declaration"
|
|
)
|
|
|
|
func substrate(t *testing.T) *declaration.Declaration {
|
|
t.Helper()
|
|
out, err := Rewrite(theRealBundle(t), held)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return out.Declaration
|
|
}
|
|
|
|
// **A container that is up is not a control plane that replies**, and this project has paid for
|
|
// that distinction more than once. A runtime reports a container running from the moment its
|
|
// process starts — before it has opened a database, and before it has failed to.
|
|
func TestAContainerThatIsUpIsNotAControlPlaneThatReplies(t *testing.T) {
|
|
previous := answerEvery
|
|
answerEvery = time.Millisecond
|
|
defer func() { answerEvery = previous }()
|
|
|
|
runtime := &asked{answer: func(_ string, args []string) (string, error) {
|
|
switch args[0] {
|
|
case "inspect":
|
|
return "true running\n", nil
|
|
case "exec":
|
|
// Up, and saying nothing. The program inside is not answering.
|
|
return "", errors.New("exit status 1")
|
|
}
|
|
return "", fmt.Errorf("unexpected command: %v", args)
|
|
}}
|
|
|
|
_, err := Verify(context.Background(), substrate(t), runtime.run,
|
|
time.Second, 0, func(string) {})
|
|
if err == nil {
|
|
t.Fatal("every container was running, nothing answered, and the substrate was reported up")
|
|
}
|
|
for _, wanted := range []string{"mesh-control", "Running is not replying", "docker logs"} {
|
|
if !strings.Contains(err.Error(), wanted) {
|
|
t.Errorf("the failure does not mention %q:\n%v", wanted, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Exit zero and silence is not an answer either. A program that returns nothing has not been asked
|
|
// anything, and treating it as success is the same fault one level down.
|
|
func TestAControlPlaneThatSaysNothingHasNotAnswered(t *testing.T) {
|
|
previous := answerEvery
|
|
answerEvery = time.Millisecond
|
|
defer func() { answerEvery = previous }()
|
|
|
|
runtime := &asked{answer: func(_ string, args []string) (string, error) {
|
|
if args[0] == "inspect" {
|
|
return "true running\n", nil
|
|
}
|
|
return " \n", nil
|
|
}}
|
|
|
|
if _, err := Verify(context.Background(), substrate(t), runtime.run,
|
|
time.Second, 0, func(string) {}); err == nil {
|
|
t.Fatal("a control plane that exited zero without saying anything was accepted")
|
|
}
|
|
}
|
|
|
|
// The substrate answering is the whole point, and what it said is reported rather than asserted.
|
|
func TestASubstrateThatIsUpAndAnsweringIsAccepted(t *testing.T) {
|
|
runtime := &asked{answer: func(_ string, args []string) (string, error) {
|
|
if args[0] == "inspect" {
|
|
return "true running\n", nil
|
|
}
|
|
return "1 node, 0 waiting\n", nil
|
|
}}
|
|
|
|
verified, err := Verify(context.Background(), substrate(t), runtime.run,
|
|
time.Second, 0, func(string) {})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Three long-running containers: the store, the broker and the control plane. The run-once and
|
|
// scheduled shapes are excluded on purpose — a step that has exited is not a fault.
|
|
want := []string{"mesh-store", "mesh-broker", "mesh-control"}
|
|
if len(verified.Running) != len(want) {
|
|
t.Fatalf("confirmed %v running, want %v", verified.Running, want)
|
|
}
|
|
for i := range want {
|
|
if verified.Running[i] != want[i] {
|
|
t.Errorf("confirmed %v running, want %v", verified.Running, want)
|
|
}
|
|
}
|
|
if verified.Answered != "1 node, 0 waiting" {
|
|
t.Errorf("the control plane's reply is reported as %q", verified.Answered)
|
|
}
|
|
}
|
|
|
|
// A control plane that is still opening its stores is waited for, not refused. Refusing on the
|
|
// first attempt would make a correct bootstrap fail for being observed too early.
|
|
func TestAControlPlaneThatIsStillStartingIsWaitedFor(t *testing.T) {
|
|
previous := answerEvery
|
|
answerEvery = time.Millisecond
|
|
defer func() { answerEvery = previous }()
|
|
|
|
attempts := 0
|
|
runtime := &asked{answer: func(_ string, args []string) (string, error) {
|
|
if args[0] == "inspect" {
|
|
return "true running\n", nil
|
|
}
|
|
attempts++
|
|
if attempts < 3 {
|
|
return "", errors.New("exit status 1")
|
|
}
|
|
return "1 node\n", nil
|
|
}}
|
|
|
|
if _, err := Verify(context.Background(), substrate(t), runtime.run,
|
|
time.Second, time.Second, func(string) {}); err != nil {
|
|
t.Fatalf("a control plane that answered on the third ask was refused: %v", err)
|
|
}
|
|
}
|
|
|
|
// A container that exited is named with what it IS, so somebody can go and read its logs rather
|
|
// than being told only that something is not what it should be.
|
|
func TestAContainerThatExitedIsNamedWithItsState(t *testing.T) {
|
|
runtime := &asked{answer: func(_ string, args []string) (string, error) {
|
|
if args[0] == "inspect" && args[len(args)-1] == "mesh-broker" {
|
|
return "false exited\n", nil
|
|
}
|
|
if args[0] == "inspect" {
|
|
return "true running\n", nil
|
|
}
|
|
return "", fmt.Errorf("unexpected command: %v", args)
|
|
}}
|
|
|
|
_, err := Verify(context.Background(), substrate(t), runtime.run,
|
|
time.Second, 0, func(string) {})
|
|
if err == nil {
|
|
t.Fatal("a container that had exited was reported as part of a running substrate")
|
|
}
|
|
if !strings.Contains(err.Error(), "mesh-broker") || !strings.Contains(err.Error(), "exited") {
|
|
t.Errorf("the failure does not say which container is in what state: %v", err)
|
|
}
|
|
}
|
|
|
|
// The control plane is asked by running the binary in its own image directly, because the image is
|
|
// `FROM scratch` and has no shell for a command line to be interpreted by.
|
|
func TestTheControlPlaneIsAskedByRunningItsOwnBinary(t *testing.T) {
|
|
runtime := &asked{answer: func(_ string, args []string) (string, error) {
|
|
if args[0] == "inspect" {
|
|
return "true running\n", nil
|
|
}
|
|
return "1 node\n", nil
|
|
}}
|
|
if _, err := Verify(context.Background(), substrate(t), runtime.run,
|
|
time.Second, 0, func(string) {}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !runtime.ran("docker exec mesh-control " + controlPlaneBinary + " status") {
|
|
t.Errorf("the control plane was never asked anything: %v", runtime.commands)
|
|
}
|
|
}
|