Every foundation port given at genesis became a per-node setting of the module
that binds it, except the package registry's: that one was fixed by rewriting
the builder's manifest when the installer registered it. Registering the builder
again from the catalogue undid it, and the forge's own module, when it took the
bootstrap forge over, came up on the catalogue's port — which on a machine where
a predecessor holds 3000 points the builder at the predecessor's forge.
So the rewrite is gone, and the port is recorded twice as a setting, both from
the one input:
- the forge's module is registered at genesis — not assigned, nothing of it runs
— so the controller has something to hold `{"ports": {"3000": <given>}}`
against. Assigning the forge later raises it on the port this machine was
given, and its container, its filter rule, its opening, what it serves and
what consumers are told all read it from there.
- the builder is given `{"serves": {"port": <given>}}`, which merges into the
binding it carries in place of one nothing can resolve yet.
A genesis on the catalogue's port records nothing and registers nothing, so it
does exactly what it did before.
novox/hq 04-ISSUES/085, ADR 0100
136 lines
5.2 KiB
Go
136 lines
5.2 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Defends novox/hq 04-ISSUES/085: the port given for the package registry at genesis is a setting
|
|
// of a module and not text in a manifest, so registering that manifest again does not put the
|
|
// catalogue's number back.
|
|
|
|
// theBuildersBinding is the resource the builder carries in place of a binding nothing can resolve
|
|
// yet, exactly as the catalogue's manifest has it — settable, with the port as its only default.
|
|
const theBuildersBinding = `{
|
|
"module": "builder",
|
|
"resources": [
|
|
{
|
|
"id": "package-binding",
|
|
"type": "file",
|
|
"path": "/var/lib/mesh/builder/package-registry.json",
|
|
"mode": "0600",
|
|
"merge": "json",
|
|
"protected": ["provision", "from", "as"],
|
|
"content": "{\"provision\": \"package-registry\", \"from\": \"gitea\", \"at\": \"127.0.0.1\", \"as\": \"mesh-builder\", \"serves\": {\"scheme\": \"http\", \"port\": 3000, \"npm-path\": \"/api/packages/novox/npm/\"}}\n"
|
|
}
|
|
]
|
|
}`
|
|
|
|
func recording(t *testing.T) (*controlRecorder, controlPlane) {
|
|
t.Helper()
|
|
t.Setenv("TMPDIR", t.TempDir())
|
|
c := &controlRecorder{settings: map[string]string{}}
|
|
return c, controlPlane{container: "temp-mesh-controller", run: c.run, timeout: time.Second}
|
|
}
|
|
|
|
func TestTheBuildersPackageRegistryPortIsASettingAndNotTheManifest(t *testing.T) {
|
|
c, control := recording(t)
|
|
o := Options{Node: "anchor", Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
|
|
if _, err := installModule(context.Background(), o, control, BuilderModule,
|
|
[]byte(theBuildersBinding), quietly); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := c.settings["builder-settings.json"]; got != `{"serves":{"port":3100}}` {
|
|
t.Errorf("the builder was told %q about the package registry's port", got)
|
|
}
|
|
// The manifest reaches the mesh as the catalogue wrote it. A port rewritten into it here is a
|
|
// port the next registration from the catalogue silently takes back.
|
|
if got := c.settings["builder-module.json"]; got != theBuildersBinding {
|
|
t.Errorf("the installer changed the builder's manifest:\n%s", got)
|
|
}
|
|
set, push := c.index("settings set builder"), c.index("push anchor")
|
|
if set < 0 || push < 0 || set > push {
|
|
t.Fatalf("the port was not set before the push that raises the builder: %v", c.told)
|
|
}
|
|
}
|
|
|
|
func TestTheBuilderOnTheDefaultPackagesPortIsToldNothing(t *testing.T) {
|
|
c, control := recording(t)
|
|
o := Options{Node: "anchor", Wait: time.Second}
|
|
if _, err := installModule(context.Background(), o, control, BuilderModule,
|
|
[]byte(theBuildersBinding), quietly); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c.index("settings") >= 0 {
|
|
t.Errorf("a genesis on the catalogue's packages port set a setting: %v", c.told)
|
|
}
|
|
}
|
|
|
|
// aCatalogueWith writes a checkout holding one module's manifest, which is all the installer reads
|
|
// a catalogue for.
|
|
func aCatalogueWith(t *testing.T, module, manifest string) string {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
at := filepath.Join(dir, catalogueDir, module)
|
|
if err := os.MkdirAll(at, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(at, "module.json"), []byte(manifest), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return dir
|
|
}
|
|
|
|
const theForgesManifest = `{"module": "gitea", "version": "1"}`
|
|
|
|
func TestThePackagesPortIsTheForgeModulesSettingOnThisNode(t *testing.T) {
|
|
c, control := recording(t)
|
|
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, theForgesManifest),
|
|
Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
|
|
if err := recordTheForgesPort(context.Background(), o, control, quietly); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := c.settings["gitea-settings.json"]; got != `{"ports":{"3000":3100}}` {
|
|
t.Errorf("the forge module was told %q about its port", got)
|
|
}
|
|
// Registered so there is something to hold the setting against, and never assigned: the forge
|
|
// module cannot run until the base it stands on has been built.
|
|
add, set := c.index("module add"), c.index("settings set gitea")
|
|
if add < 0 || set < 0 || add > set {
|
|
t.Fatalf("the forge's setting was recorded against a module the mesh does not know: %v", c.told)
|
|
}
|
|
if c.index("assign") >= 0 {
|
|
t.Errorf("genesis assigned the forge module: %v", c.told)
|
|
}
|
|
if !strings.Contains(c.told[set], "--node anchor") {
|
|
t.Errorf("the forge's port was set for the whole mesh, not this machine: %s", c.told[set])
|
|
}
|
|
}
|
|
|
|
func TestAGenesisOnTheCataloguesPackagesPortRegistersNoForge(t *testing.T) {
|
|
c, control := recording(t)
|
|
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, theForgesManifest),
|
|
Wait: time.Second}
|
|
if err := recordTheForgesPort(context.Background(), o, control, quietly); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(c.told) != 0 {
|
|
t.Errorf("a genesis on the defaults told the mesh something new: %v", c.told)
|
|
}
|
|
}
|
|
|
|
func TestAForgeManifestTheCatalogueDoesNotHaveIsNamed(t *testing.T) {
|
|
_, control := recording(t)
|
|
o := Options{Node: "anchor", Catalogue: t.TempDir(),
|
|
Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
|
|
err := recordTheForgesPort(context.Background(), o, control, quietly)
|
|
if err == nil || !strings.Contains(err.Error(), ForgeModule) ||
|
|
!strings.Contains(err.Error(), "package registry") {
|
|
t.Errorf("a missing forge manifest was not explained: %v", err)
|
|
}
|
|
}
|