Assign around what a machine already holds
The other half of ADR 0038, and what 04-ISSUES/028 was actually about. A module can now avoid colliding with another module; until this it could not avoid colliding with the mesh itself. The substrate is not a module. A node raises it from the bundle it carries before any mesh exists, so the control plane had never heard of the store, the broker, or its own container — and handed a database module 5432, which the store already had. So the machine says. The host records what each resource binds, distinguishing what it carried from what the mesh sent — a distinction that already existed so the two never remove each other — and reports the carried ones. The node states and this context writes, which is the shape of every message between them. What the declaration binds, not what is open. A machine's open ports are a moving target, and assigning around them would mean a port that was free when it was asked for and taken when it was used. Replaced whole each time rather than merged: a machine that gave a port back must be believed about that too, and a set that only grows keeps a port reserved for something no longer there. Tested against a real database, and the tests bite — removing the check hands the module 20000, which the machine had said it holds.
This commit is contained in:
@@ -149,3 +149,65 @@ func contains(s, what string) bool {
|
||||
return false
|
||||
})()
|
||||
}
|
||||
|
||||
// **The bug this whole thing is for** (novox/hq 04-ISSUES/028). The mesh keeps its own store on a
|
||||
// machine, from the bundle, before there is any mesh to ask. A database module assigned there was
|
||||
// handed 5432 — the port the store already had — and found out from a container runtime.
|
||||
func TestAModuleIsNotGivenAPortTheMachineAlreadyHolds(t *testing.T) {
|
||||
inv, node := aNodeWithModules(t, "some-service")
|
||||
ctx := t.Context()
|
||||
|
||||
// What the machine says it raised for itself: the store, the broker, the control plane.
|
||||
if err := inv.RecordCarried(ctx, node, []int{5432, 5671, 8080, 20000, 20001}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, err := inv.PortFor(ctx, node, "some-service", 5432, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, held := range []int{5432, 5671, 8080, 20000, 20001} {
|
||||
if got.Machine == held {
|
||||
t.Fatalf("it was given %d, which the machine already holds", held)
|
||||
}
|
||||
}
|
||||
if got.Machine != 20002 {
|
||||
t.Errorf("expected the lowest free one, 20002, and got %d", got.Machine)
|
||||
}
|
||||
}
|
||||
|
||||
// A port the protocol fixes, already held by something the mesh did not put there, is refused —
|
||||
// and refused here rather than by a container runtime on the machine.
|
||||
func TestAFixedPortTheMachineAlreadyHoldsIsRefused(t *testing.T) {
|
||||
inv, node := aNodeWithModules(t, "mailu")
|
||||
ctx := t.Context()
|
||||
if err := inv.RecordCarried(ctx, node, []int{25}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := inv.PortFor(ctx, node, "mailu", 25, true)
|
||||
if err == nil {
|
||||
t.Fatal("a module was given a port something on the machine already holds")
|
||||
}
|
||||
if !contains(err.Error(), "already runs") {
|
||||
t.Errorf("the refusal does not say the machine itself has it: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// A machine that gave a port back is believed about that too.
|
||||
func TestWhatAMachineNoLongerHoldsIsAvailableAgain(t *testing.T) {
|
||||
inv, node := aNodeWithModules(t, "a-service")
|
||||
ctx := t.Context()
|
||||
if err := inv.RecordCarried(ctx, node, []int{20000}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := inv.RecordCarried(ctx, node, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := inv.PortFor(ctx, node, "a-service", 1234, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Machine != 20000 {
|
||||
t.Errorf("a port the machine gave back was still reserved: got %d", got.Machine)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user