Let a replicated mesh seat be held on several nodes in CheckPlacements, so the seed of today's placement is not refused (issue 1126)

This commit is contained in:
2026-10-27 02:04:01 +01:00
parent b0cbc4e6ac
commit 8e81d87610
2 changed files with 17 additions and 1 deletions
+7 -1
View File
@@ -371,7 +371,8 @@ func (p Placement) Held() []catalogue.Held {
// CheckPlacements is the catalogue's own check of every placement file (ADR 0549 §1), over the placements by node, the
// modules the catalogue holds and the nodes enrolled. It returns every refusal, in node order, never only the first: a
// placement naming a node not enrolled or a module the catalogue does not hold; two modules of one node on the same host
// port; a pin, binding or holding naming a provider that is not placed where it says; a seat of scope mesh held twice;
// port; a pin, binding or holding naming a provider that is not placed where it says; a seat of scope mesh held twice, unless the seat is replicated (catalogue.Seat's Replicated, ADR 0223), which
// is held once per node;
// two nodes with one address on the private network; more than one hub.
// A host port a manifest declares without a number and a requirement left unbound are the composition's to find (its
// ForeseenPorts and Unbound), which the catalogue's composition check reads.
@@ -442,6 +443,11 @@ func CheckPlacements(placements map[string]Placement, held func(module string) b
continue
}
seat := h.Claim + "/" + h.Kind
if s, known := catalogue.SeatNamed(h.Claim); known && s.Replicated {
// A replicated mesh seat (ADR 0223) is held on several nodes at once, each answering the same thing;
// it is still held once on each node.
seat += "/" + node
}
if other, twice := meshSeats[seat]; twice {
refusals = append(refusals, fmt.Sprintf("the seat %s, held once for the mesh, is held on %s and %s", h.Claim, other, node))
}
+10
View File
@@ -148,6 +148,16 @@ func TestPlacement(t *testing.T) {
if r := CheckPlacements(map[string]Placement{"g14": g14, "novox": novox}, held, enrolled); len(r) != 0 {
t.Fatalf("a sound placement is refused: %v", r)
}
// A replicated mesh seat (ADR 0223) is held on two nodes; a seat that is not replicated is refused there.
for seat, refused := range map[string]bool{"mesh-dns-resolver": false, "mesh-broker": true} {
a := Placement{Node: "ace", Modules: []PlacedModule{{Module: "dns"}}, Holds: []Holding{{Claim: seat, Scope: "mesh", Module: "dns"}}}
b := a
b.Node = "novox"
r := CheckPlacements(map[string]Placement{"ace": a, "novox": b}, held, enrolled)
if (len(r) != 0) != refused {
t.Errorf("%s on two nodes: refusals %v, want refused %v", seat, r, refused)
}
}
clash := g14
clash.Modules = append([]PlacedModule{{Module: "ghost", Ports: map[string]int{"80": 18080}}}, g14.Modules...)
clash.Modules[2] = PlacedModule{Module: "app", Ports: map[string]int{"8080": 18080}, Bindings: map[string]Provider{"postgres": {Node: "ace", Module: "postgres"}}}