The packages port given at genesis is a node setting, not manifest text (hq issue 085) #21
@@ -24,7 +24,7 @@ const theBuildersBinding = `{
|
|||||||
"path": "/var/lib/mesh/builder/package-registry.json",
|
"path": "/var/lib/mesh/builder/package-registry.json",
|
||||||
"mode": "0600",
|
"mode": "0600",
|
||||||
"merge": "json",
|
"merge": "json",
|
||||||
"protected": ["provision", "from", "as"],
|
"protected": ["provision", "from", "at", "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"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -111,6 +111,40 @@ func TestThePackagesPortIsTheForgeModulesSettingOnThisNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// knowingControl is a control plane that already has the forge in its catalogue, as a mesh that
|
||||||
|
// has been running has.
|
||||||
|
type knowingControl struct{ controlRecorder }
|
||||||
|
|
||||||
|
func (k *knowingControl) run(ctx context.Context, name string, args ...string) (string, error) {
|
||||||
|
out, err := k.controlRecorder.run(ctx, name, args...)
|
||||||
|
if name == "docker" && args[0] == "exec" && len(args) > 4 &&
|
||||||
|
args[3] == "module" && args[4] == "list" {
|
||||||
|
return ForgeModule + " 1 assigned to anchor\n", nil
|
||||||
|
}
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestARerunDoesNotReplaceAForgeTheMeshAlreadyHas(t *testing.T) {
|
||||||
|
t.Setenv("TMPDIR", t.TempDir())
|
||||||
|
k := &knowingControl{controlRecorder{settings: map[string]string{}}}
|
||||||
|
control := controlPlane{container: "mesh-controller", run: k.run, timeout: time.Second}
|
||||||
|
// An older checkout than the mesh is running, which is what makes an overwrite here damage.
|
||||||
|
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, `{"module": "gitea"}`),
|
||||||
|
Ports: FoundationPorts{Packages: 3100}, Wait: time.Second}
|
||||||
|
if err := recordTheForgesPort(context.Background(), o, control, quietly); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Registering is an overwrite, and the manifest of a forge that is built and assigned is not
|
||||||
|
// this installer's to replace with whatever checkout it was pointed at.
|
||||||
|
if k.index("module add") >= 0 {
|
||||||
|
t.Errorf("a re-run replaced the registered forge's manifest: %v", k.told)
|
||||||
|
}
|
||||||
|
// The port is still recorded: a settings row needs the module row, and it is already there.
|
||||||
|
if got := k.settings["gitea-settings.json"]; got != `{"ports":{"3000":3100}}` {
|
||||||
|
t.Errorf("the forge's port was not recorded on a mesh that knows it: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAGenesisOnTheCataloguesPackagesPortRegistersNoForge(t *testing.T) {
|
func TestAGenesisOnTheCataloguesPackagesPortRegistersNoForge(t *testing.T) {
|
||||||
c, control := recording(t)
|
c, control := recording(t)
|
||||||
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, theForgesManifest),
|
o := Options{Node: "anchor", Catalogue: aCatalogueWith(t, ForgeModule, theForgesManifest),
|
||||||
|
|||||||
@@ -51,10 +51,15 @@ const (
|
|||||||
// a stand-in for, and which takes it over once the base exists.
|
// a stand-in for, and which takes it over once the base exists.
|
||||||
//
|
//
|
||||||
// Named here because the port given for the package registry is that module's setting on this node
|
// Named here because the port given for the package registry is that module's setting on this node
|
||||||
// and not this installer's private number (novox/hq 04-ISSUES/085): the forge's own container, its
|
// and not this installer's private number (novox/hq 04-ISSUES/085). What follows that setting is
|
||||||
// filter rule, its opening, what it says it serves and what consumers are told all read it from
|
// what the mesh derives from a module's ports: the forge's container mapping, its rule in the
|
||||||
// there, so taking the bootstrap forge over does not move the registry back to the catalogue's
|
// filter, its opening on an adopted node, and what it says it serves — so a consumer the mesh binds
|
||||||
// port.
|
// is told where the machine actually put the registry.
|
||||||
|
//
|
||||||
|
// What does NOT follow it, and is not this change's to fix: the address of itself the forge's
|
||||||
|
// runtime is given, which the catalogue writes as a literal (novox/hq 04-ISSUES/088), and the port
|
||||||
|
// in its route contribution. Both are already wrong for any machine port the mesh assigned, with a
|
||||||
|
// given port or without one.
|
||||||
const ForgeModule = "gitea"
|
const ForgeModule = "gitea"
|
||||||
|
|
||||||
// RaisePackageRegistry puts a working npm registry in front of the base build. It is idempotent:
|
// RaisePackageRegistry puts a working npm registry in front of the base build. It is idempotent:
|
||||||
@@ -131,9 +136,17 @@ func RaisePackageRegistry(ctx context.Context, o Options, d Deps, control contro
|
|||||||
// binds them, set where that module is registered and assigned; the forge is raised by hand here,
|
// binds them, set where that module is registered and assigned; the forge is raised by hand here,
|
||||||
// long before its module can be built, so there was no registration to hang it on and the number
|
// long before its module can be built, so there was no registration to hang it on and the number
|
||||||
// lived in rewritten manifest text instead. So the manifest is registered here — not assigned, and
|
// lived in rewritten manifest text instead. So the manifest is registered here — not assigned, and
|
||||||
// nothing of it runs — for the one thing registering buys: the controller will hold a setting
|
// nothing of it runs — for the one thing registering buys: a settings row needs the module row to
|
||||||
// against it. Whenever somebody later assigns the forge on this node, it comes up on the port this
|
// exist. Whenever somebody later assigns the forge on this node, it comes up on the port this
|
||||||
// machine was given rather than on the catalogue's, and so does the address its consumers are told.
|
// machine was given rather than on the catalogue's.
|
||||||
|
//
|
||||||
|
// **Registered only when the mesh does not already know it, which is the opposite of every other
|
||||||
|
// `module add` here.** The rest of the installer registers every run on purpose: the manifest is
|
||||||
|
// what changes between runs, and skipping it would pin the mesh to a previous image. This one
|
||||||
|
// changes nothing about the forge and wants nothing of the checkout's manifest — and registering
|
||||||
|
// is an overwrite, so a re-run of genesis pointed at an older catalogue would replace the manifest
|
||||||
|
// of a forge that is built and assigned, with a push a few lines later. The port is the only thing
|
||||||
|
// this is here to record, and the setting does not need the manifest to be this checkout's.
|
||||||
//
|
//
|
||||||
// A node given the catalogue's own port records nothing and registers nothing, so a genesis on the
|
// A node given the catalogue's own port records nothing and registers nothing, so a genesis on the
|
||||||
// defaults does exactly what it did before.
|
// defaults does exactly what it did before.
|
||||||
@@ -142,21 +155,29 @@ func recordTheForgesPort(ctx context.Context, o Options, control controlPlane,
|
|||||||
if o.Ports.orDefaults().Packages == DefaultPorts().Packages {
|
if o.Ports.orDefaults().Packages == DefaultPorts().Packages {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
manifest, err := readManifest(o.Catalogue, ForgeModule)
|
known, err := control.tell(ctx, "module", "list")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w\n"+
|
|
||||||
"This is the module that owns the forge genesis just raised. Without it the port this "+
|
|
||||||
"machine was given for the package registry is nobody's setting, and taking the forge "+
|
|
||||||
"over would put it back on the catalogue's port", err)
|
|
||||||
}
|
|
||||||
remote := "/" + ForgeModule + "-module.json"
|
|
||||||
if err := control.carrying(ctx, ForgeModule+"-module.json", manifest, remote); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := control.tell(ctx, "module", "add", remote); err != nil {
|
if mentions(known, ForgeModule) {
|
||||||
return err
|
say(" known " + ForgeModule + " — left as the mesh has it; only its port is set here")
|
||||||
|
} else {
|
||||||
|
manifest, err := readManifest(o.Catalogue, ForgeModule)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%w\n"+
|
||||||
|
"This is the module that owns the forge genesis just raised. Without it the port this "+
|
||||||
|
"machine was given for the package registry is nobody's setting, and taking the forge "+
|
||||||
|
"over would put it back on the catalogue's port", err)
|
||||||
|
}
|
||||||
|
remote := "/" + ForgeModule + "-module.json"
|
||||||
|
if err := control.carrying(ctx, ForgeModule+"-module.json", manifest, remote); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := control.tell(ctx, "module", "add", remote); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
say(" registered " + ForgeModule + " — registered, not assigned: nothing of it runs yet")
|
||||||
}
|
}
|
||||||
say(" registered " + ForgeModule + " — registered, not assigned: nothing of it runs yet")
|
|
||||||
return setFoundationSettings(ctx, o, control, ForgeModule, say)
|
return setFoundationSettings(ctx, o, control, ForgeModule, say)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,12 @@ const PortsSetting = "ports"
|
|||||||
// builder — which a later registration from the catalogue undid silently. Set as a node's setting
|
// builder — which a later registration from the catalogue undid silently. Set as a node's setting
|
||||||
// instead, it is held by the controller rather than by the manifest, so re-registering the builder
|
// instead, it is held by the controller rather than by the manifest, so re-registering the builder
|
||||||
// leaves it where it was.
|
// leaves it where it was.
|
||||||
|
//
|
||||||
|
// **A settings layer is the module's, not one resource's.** The controller lays it over every file
|
||||||
|
// of that module which merges as JSON, so `serves` lands in the package binding only because that
|
||||||
|
// binding is the builder's one mergeable file. A second mergeable file added to the builder would
|
||||||
|
// be given a `serves` key too, meaning nothing to whatever reads it. Worth knowing before adding
|
||||||
|
// one.
|
||||||
const ServesSetting = "serves"
|
const ServesSetting = "serves"
|
||||||
|
|
||||||
// setFoundationSettings tells the controller the ports this node gave a foundation module — and,
|
// setFoundationSettings tells the controller the ports this node gave a foundation module — and,
|
||||||
|
|||||||
Reference in New Issue
Block a user