diff --git a/go/compose/frombus/frombus.go b/go/compose/frombus/frombus.go index 88cf235..979502c 100644 --- a/go/compose/frombus/frombus.go +++ b/go/compose/frombus/frombus.go @@ -246,15 +246,17 @@ func input(ctx context.Context, r Reader, mesh Mesh, s Scope, refuse func(module // The module the mesh provides itself (the private network) has no repository the indexer reads: its manifest comes // with mesh-sdk and always wins, as the controller's providedModules and the grants part have it. - provided, err := json.Marshal(overlay.Manifest()) - if err != nil { - return compose.Input{}, err + for _, name := range delivery.ProvidedModules() { + raw, err := json.Marshal(overlay.Manifest()) + if err != nil { + return compose.Input{}, err + } + var private catalogue.Manifest + if err := json.Unmarshal(raw, &private); err != nil { + return compose.Input{}, fmt.Errorf("frombus: the manifest mesh-sdk provides for %s: %w", name, err) + } + in.Catalogue[name] = private } - var private catalogue.Manifest - if err := json.Unmarshal(provided, &private); err != nil { - return compose.Input{}, fmt.Errorf("frombus: the private network's manifest mesh-sdk provides: %w", err) - } - in.Catalogue[overlay.Name] = private var missing []string for _, node := range nodesOf(placements, records) { diff --git a/go/delivery/placement.go b/go/delivery/placement.go index e6fce9b..60f6e32 100644 --- a/go/delivery/placement.go +++ b/go/delivery/placement.go @@ -413,7 +413,7 @@ func CheckPlacements(placements map[string]Placement, held func(module string) b } hostPorts := map[int]string{} for _, m := range p.Modules { - if !held(m.Module) { + if !held(m.Module) && !ProvidedByMesh(m.Module) { // the mesh provides the private network itself refusals = append(refusals, fmt.Sprintf("%s: the indexer holds no module %s", node, m.Module)) } for _, port := range sortedKeys(m.Ports) { diff --git a/go/delivery/placement_test.go b/go/delivery/placement_test.go index 94cb097..e861328 100644 --- a/go/delivery/placement_test.go +++ b/go/delivery/placement_test.go @@ -155,6 +155,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) } + // Issue 1126: the private network is the mesh's own module, held by no repository the indexer reads, and placed on + // every node by the seed; the check takes it whatever the indexer holds. + wired := Placement{Node: "novox", Modules: []PlacedModule{{Module: "mesh-wireguard"}}} + if r := CheckPlacements(map[string]Placement{"novox": wired}, func(string) bool { return false }, enrolled); len(r) != 0 || + !ProvidedByMesh("mesh-wireguard") || ProvidedByMesh("postgres") { + t.Errorf("the private network placed with no repository holding it is refused: %v", r) + } + if m, _, err := ProvidedManifest("mesh-wireguard"); err != nil || m.Module != "mesh-wireguard" { + t.Errorf("the provided manifest = %+v, %v", m, err) + } // 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"}}} diff --git a/go/delivery/provided.go b/go/delivery/provided.go new file mode 100644 index 0000000..712453e --- /dev/null +++ b/go/delivery/provided.go @@ -0,0 +1,37 @@ +package delivery + +import ( + "encoding/json" + "fmt" + + "git.novox.be/novox/mesh-sdk/go/catalogue" + "git.novox.be/novox/mesh-sdk/go/overlay" +) + +// The modules the mesh provides itself (issue 1126): no repository holds them, so the indexer reads none; their +// manifests come with mesh-sdk, built in code, and always win over any other. Today the private network alone +// (overlay.Name), built by nobody and run inside each node's own composition. One predicate for every part that judges +// or composes a placement: CheckPlacements, the seat's holder, the composer's input (frombus) and the grants part. + +// ProvidedModules is every module the mesh provides itself, sorted. +func ProvidedModules() []string { return []string{overlay.Name} } + +// ProvidedByMesh says whether the mesh provides module itself, so a placement may name it with no repository holding it. +func ProvidedByMesh(module string) bool { return module == overlay.Name } + +// ProvidedManifest is a provided module's manifest, as its readers parse it, and its raw JSON; an error for a module the +// mesh does not provide or a manifest its own reader refuses. +func ProvidedManifest(module string) (catalogue.Manifest, []byte, error) { + if !ProvidedByMesh(module) { + return catalogue.Manifest{}, nil, fmt.Errorf("delivery: the mesh provides no module %s", module) + } + raw, err := json.Marshal(overlay.Manifest()) + if err != nil { + return catalogue.Manifest{}, nil, err + } + m, err := catalogue.ParseManifestForInputs(raw) + if err != nil { + return catalogue.Manifest{}, raw, fmt.Errorf("delivery: the manifest mesh-sdk provides for %s is refused by its own reader: %w", module, err) + } + return m, raw, nil +}