Composer: find the store by the holder of any of its names, the old seat's too (ADR 0632 §2; issue 1966)
While the indexer holds distribution's new manifest, every node reads main's, which claims only mesh-artifact-store: a new engine must find the store there. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -1142,7 +1142,7 @@ func storeSought(in compose.Input) string {
|
||||
for _, n := range in.Nodes {
|
||||
nodes = append(nodes, n.Name)
|
||||
for _, a := range n.Assigned {
|
||||
if m, ok := in.Catalogue[a]; ok && claimsSeat(m, compose.StoreSeat) {
|
||||
if m, ok := in.Catalogue[a]; ok && claimsStore(m) {
|
||||
where = append(where, a+" on "+n.Name)
|
||||
}
|
||||
}
|
||||
@@ -1157,10 +1157,10 @@ func storeSought(in compose.Input) string {
|
||||
", none of it on the private network with a listen open to the mesh"
|
||||
}
|
||||
|
||||
// claimsSeat says whether m claims seat at the mesh's scope.
|
||||
func claimsSeat(m catalogue.Manifest, seat string) bool {
|
||||
// claimsStore says whether m claims a name of the store (resolution.StoreSeats) at the mesh's scope.
|
||||
func claimsStore(m catalogue.Manifest) bool {
|
||||
for _, cl := range m.Claims {
|
||||
if cs, ok := catalogue.SeatNamed(cl.Name); ok && cs.Name == seat && cl.At() == catalogue.ScopeMesh {
|
||||
if cs, ok := catalogue.SeatNamed(cl.Name); ok && slices.Contains(resolution.StoreSeats, cs.Name) && cl.At() == catalogue.ScopeMesh {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package compose
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -332,11 +333,18 @@ func (c *composer) namesInTheMesh() map[string]string {
|
||||
const StoreSeat = "container-image-registry"
|
||||
|
||||
// storeHolders are the modules holding the store's seat: the holdings on record, and only where none is on record every
|
||||
// module of the catalogue claiming it at the mesh's scope, as a seat holder's reach is read (replicatedHolders).
|
||||
// module of the catalogue claiming it at the mesh's scope, as a seat holder's reach is read (replicatedHolders). Any name
|
||||
// of the store counts (resolution.StoreSeats): until every counted engine states the new reading, the manifest every
|
||||
// node reads is the holder's old one, which claims only mesh-artifact-store (ADR 0632 §2), and an engine that finds the
|
||||
// store by the seat must find it there too.
|
||||
func (c *composer) storeHolders() map[string]catalogue.Manifest {
|
||||
isStore := func(claim string) bool {
|
||||
hs, ok := catalogue.SeatNamed(claim)
|
||||
return ok && slices.Contains(resolution.StoreSeats, hs.Name)
|
||||
}
|
||||
out := map[string]catalogue.Manifest{}
|
||||
for _, h := range c.in.Holdings {
|
||||
if hs, ok := catalogue.SeatNamed(h.Claim); ok && hs.Name == StoreSeat && h.Scope == catalogue.ScopeMesh && h.Module != "" {
|
||||
if isStore(h.Claim) && h.Scope == catalogue.ScopeMesh && h.Module != "" {
|
||||
if m, known := c.in.Catalogue[h.Module]; known {
|
||||
out[h.Module] = m
|
||||
}
|
||||
@@ -347,7 +355,7 @@ func (c *composer) storeHolders() map[string]catalogue.Manifest {
|
||||
}
|
||||
for name, m := range c.in.Catalogue {
|
||||
for _, cl := range m.Claims {
|
||||
if cs, ok := catalogue.SeatNamed(cl.Name); ok && cs.Name == StoreSeat && cl.At() == catalogue.ScopeMesh {
|
||||
if isStore(cl.Name) && cl.At() == catalogue.ScopeMesh {
|
||||
out[name] = m
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +318,36 @@ func TestTheStoreIsFoundByTheImageSeatsHolderAndItsListen(t *testing.T) {
|
||||
t.Errorf("${seat:%s:reach} is %q", seat, r.SeatReach[seat])
|
||||
}
|
||||
}
|
||||
// main's distribution, the manifest every node reads while the indexer holds the new one (ADR 0632 §2): it claims
|
||||
// only mesh-artifact-store and serves the retired provision; the engine finds the store by that claim and its listen.
|
||||
old := in
|
||||
old.Catalogue = map[string]catalogue.Manifest{}
|
||||
for k, v := range in.Catalogue {
|
||||
if k != "registry" {
|
||||
old.Catalogue[k] = v
|
||||
}
|
||||
}
|
||||
old.Catalogue["distribution"] = catalogue.Manifest{Module: "distribution", Version: "2",
|
||||
Provides: []catalogue.Offer{{Name: catalogue.ArtifactStoreProvision, Scope: catalogue.ScopeMesh}},
|
||||
Claims: []catalogue.Claim{{Name: "mesh-artifact-store", Scope: catalogue.ScopeMesh}},
|
||||
Serves: map[string]map[string]any{catalogue.ArtifactStoreProvision: {"port": 5000}},
|
||||
Listens: []catalogue.Listening{{Name: "registry", Port: 5000, Protocol: "tcp", From: catalogue.FromMesh}}}
|
||||
old.Nodes = append([]Node(nil), in.Nodes...)
|
||||
for i := range old.Nodes {
|
||||
if old.Nodes[i].Name == "anchor" {
|
||||
var kept []string
|
||||
for _, a := range old.Nodes[i].Assigned {
|
||||
if a != "registry" && a != "old" {
|
||||
kept = append(kept, a)
|
||||
}
|
||||
}
|
||||
old.Nodes[i].Assigned = append(kept, "distribution")
|
||||
old.Nodes[i].Ports = map[string]map[int]int{"distribution": {5000: 5400}}
|
||||
}
|
||||
}
|
||||
if got := placed(t, old, "laptop").Rendering.ArtifactStore; got != "anchor.internal:5400" {
|
||||
t.Errorf("main's distribution, claiming only mesh-artifact-store, is reached at %q, want anchor.internal:5400", got)
|
||||
}
|
||||
m := in.Catalogue["registry"]
|
||||
m.Listens = append(m.Listens, catalogue.Listening{Name: "other", Port: 5300, From: catalogue.FromMesh})
|
||||
in.Catalogue["registry"] = m
|
||||
|
||||
Reference in New Issue
Block a user