From 2f0b7c974153d4a876987ce0c92cdbea0679469b Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 22:00:49 +0100 Subject: [PATCH] Route-proxy and the overlay name the assigner's new places: the contracts' go/ path and the state assignments (issue 1966) Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- modules/mesh-wireguard/go/overlay/provided.go | 6 ++--- modules/route-proxy/README.md | 4 +-- .../cmd/route-provider/provider.go | 2 +- modules/route-proxy/cmd/route-proxy/bus.go | 24 ++++++++--------- .../route-proxy/cmd/route-proxy/names_test.go | 2 +- modules/route-proxy/cmd/route-proxy/plans.go | 2 +- .../route-proxy/cmd/route-proxy/reach_test.go | 26 +++++++++---------- .../cmd/route-proxy/routes_test.go | 2 +- modules/route-proxy/go.mod | 4 +-- modules/route-proxy/module.json | 2 +- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/modules/mesh-wireguard/go/overlay/provided.go b/modules/mesh-wireguard/go/overlay/provided.go index d89d7a1..d3d8730 100644 --- a/modules/mesh-wireguard/go/overlay/provided.go +++ b/modules/mesh-wireguard/go/overlay/provided.go @@ -9,13 +9,13 @@ import ( // The modules the mesh provides itself (issue 1126): no repository holds them, so the indexer reads none; their // manifests are built in code, here, and always win over any other. Today the private network alone, built by nobody -// and run inside each node's own composition. One predicate for every part that judges or composes a placement: the -// placement's check, the seat's holder, the composer's input and the grants part. +// and run inside each node's own composition. One predicate for every part that judges or composes an assignment: the +// assignment's check, the seat's holder, the composer's input and the grants part. // ProvidedModules is every module the mesh provides itself, sorted. func ProvidedModules() []string { return []string{Name} } -// ProvidedByMesh says whether the mesh provides module itself, so a placement may name it with no repository holding it. +// ProvidedByMesh says whether the mesh provides module itself, so an assignment may name it with no repository holding it. func ProvidedByMesh(module string) bool { return module == Name } // ProvidedManifest is a provided module's manifest, as its readers parse it, and its raw JSON; an error for a module the diff --git a/modules/route-proxy/README.md b/modules/route-proxy/README.md index e8144c7..c3acb94 100644 --- a/modules/route-proxy/README.md +++ b/modules/route-proxy/README.md @@ -42,13 +42,13 @@ migration scaffolding still listed there. |---|---|---| | `provides` | `route` (scope `mesh`, answered by the helper) | a module on any node may require it | | `serves.route` | `{}` | a route hands back a name, not a credential — the consumer already knows the name it asked for | -| `reads` | `mesh-provisioner.plans`, `mesh-provisioner.provisions`, `mesh-delivery-assigner.placement` | the plans are where the routes are; the helper reads both; the placement says who is inside | +| `reads` | `mesh-provisioner.plans`, `mesh-provisioner.provisions`, `mesh-delivery-assigner.assignments` | the plans are where the routes are; the helper reads both; the assignments say who is inside | | `emits` | `route.served`, `route.withdrawn`, `route.refused` | what it serves, said as it changes (the contract's `Event`) | | `listens` | `80` and `443`, both `from: anywhere` | the one machine with a public opening; the firewall opens these for free (ADR 0045) | Until the bus answers, the proxy routes nothing and says so on its log; it refuses to start without its broker credential (`MESH_BROKER_FILE`). Who is inside the private network, and so may be served an internal-only name, is -every node's address on it as the seat mesh-placement decides it (mesh-sdk `delivery.InsideAddresses`); until that +every node's address on it as the seat mesh-module-assigner decides it (mesh-sdk `delivery.InsideAddresses`); until that is read, an internal-only name is served to this machine alone. ## Which issuer: Let's Encrypt, stated here (novox/hq ADR 0226) diff --git a/modules/route-proxy/cmd/route-provider/provider.go b/modules/route-proxy/cmd/route-provider/provider.go index a71d891..efb6761 100644 --- a/modules/route-proxy/cmd/route-provider/provider.go +++ b/modules/route-proxy/cmd/route-provider/provider.go @@ -5,7 +5,7 @@ package main // name from the entry in this module's bucket, the one its machine's client fills its files from. // // **It composes nothing.** A route's public name is the label its consumer chose joined to the node's public domain, -// which only placement holds, so the seat mesh-provisioner composes it and carries it in the +// which only the assignments hold, so the seat mesh-provisioner composes it and carries it in the // consumer's plan entry (`names`); the helper copies it into the entry's values unchanged. There is no credential for // a route and nothing to make. The proxy itself serves the same plans' entries (cmd/route-proxy plans.go), the one // source of routes (issue 774, research 072 row 34). diff --git a/modules/route-proxy/cmd/route-proxy/bus.go b/modules/route-proxy/cmd/route-proxy/bus.go index f3b4491..f36a2ef 100644 --- a/modules/route-proxy/cmd/route-proxy/bus.go +++ b/modules/route-proxy/cmd/route-proxy/bus.go @@ -10,7 +10,7 @@ import ( "github.com/nats-io/nats.go" - "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient" + "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/announce" "git.novox.be/novox/mesh-sdk/go/process" @@ -18,9 +18,9 @@ import ( "route-proxy/contract" ) -// placementRead is the seat mesh-module-assigner's state placement as this module's manifest reads it (`reads`); no seat's +// assignmentsRead is the seat mesh-module-assigner's state assignments as this module's manifest reads it (`reads`); no seat's // client names a holder (novox/hq ADR 0625 §4), so the name is kept here and held to the manifest by TestTheReadIsTheManifests. -const placementRead = "mesh-delivery-assigner.placement" +const assignmentsRead = "mesh-delivery-assigner.assignments" // plansRead is the seat mesh-provisioner's state plans as this module's manifest reads it (`reads`; TestTheReadIsTheManifests). const plansRead = "mesh-provisioner.plans" @@ -40,11 +40,11 @@ func keptStates() []announce.State { // **The routes are the seat mesh-provisioner's plans, alone** (issue 774, research 072 row 34): every plan's entry // naming this proxy as a route's provider, followed, so a route added or withdrawn reaches a running proxy without a // restart, and said on the bus as it changes (contract.EventServed, EventWithdrawn, EventRefused). **Who is inside** -// is every node's address on the private network as the seat mesh-placement decides it (the module assigner's +// is every node's address on the private network as the seat mesh-module-assigner decides it (the module assigner's // client, InsideAddresses), which is who may be served an internal name; until it is read, an internal name is // served to this machine alone. -// follow connects with the credential in path, follows the plans and the placement, and retries the connection for +// follow connects with the credential in path, follows the plans and the assignments, and retries the connection for // as long as it takes: until the bus answers, the proxy routes nothing, and says so. func follow(path string, held *table) { for { @@ -80,8 +80,8 @@ func followOnce(path string, held *table) error { } } // Who is inside first, so the first table is served to the machines it is meant for. - if err := followInside(conn.Read(placementRead), held); err != nil { - log.Printf("cannot follow %s, so an internal name is served to this machine alone: %v", placementRead, err) + if err := followInside(conn.Read(assignmentsRead), held); err != nil { + log.Printf("cannot follow %s, so an internal name is served to this machine alone: %v", assignmentsRead, err) } if err := followPlans(conn.Read(plansRead), newPlanned(account.Node, say), held, say); err != nil { conn.Close() @@ -164,25 +164,25 @@ func sortedNames(m map[string]contract.Event) []string { return out } -// followInside follows the seat mesh-placement's state and serves an internal name to every node's address on the +// followInside follows the seat mesh-module-assigner's state and serves an internal name to every node's address on the // private network it decides, each time it changes (the module assigner client's InsideAddresses; research 072 rows 33 and 34: // the membership that carried them went with the assignments stream). A key that does not read keeps who is inside // as it was. -func followInside(placement planWatch, held *table) error { +func followInside(assignments planWatch, held *table) error { keys := meshmoduleassignerclient.NewKeys() var read atomic.Bool apply := func() { inside, err := sourcesOf(meshmoduleassignerclient.InsideAddresses(keys.All())) if err != nil { - log.Printf("the placement says an address that is not one, so who is inside stays as it was: %v", err) + log.Printf("the assignments say an address that is not one, so who is inside stays as it was: %v", err) return } held.setInside(inside) log.Printf("internal names are served to %d machine(s)", len(inside)) } - err := placement.Watch("", func(c stdio.StateChange) error { + err := assignments.Watch("", func(c stdio.StateChange) error { if _, err := keys.Put(c.Key, c.Value, c.Revision, c.Op == "delete" || c.Op == "purge"); err != nil { - log.Printf("the placement's key %s does not read, so who is inside stays as it was: %v", c.Key, err) + log.Printf("the assignments key %s does not read, so who is inside stays as it was: %v", c.Key, err) return nil } if read.Load() { diff --git a/modules/route-proxy/cmd/route-proxy/names_test.go b/modules/route-proxy/cmd/route-proxy/names_test.go index d061969..a42b9ab 100644 --- a/modules/route-proxy/cmd/route-proxy/names_test.go +++ b/modules/route-proxy/cmd/route-proxy/names_test.go @@ -19,7 +19,7 @@ func TestTheReadIsTheManifests(t *testing.T) { if err := json.Unmarshal(raw, &m); err != nil { t.Fatal(err) } - for _, read := range []string{placementRead, plansRead} { + for _, read := range []string{assignmentsRead, plansRead} { if !slices.Contains(m.Reads, read) { t.Errorf("the proxy follows %s, its manifest reads %v", read, m.Reads) } diff --git a/modules/route-proxy/cmd/route-proxy/plans.go b/modules/route-proxy/cmd/route-proxy/plans.go index e648440..c749af4 100644 --- a/modules/route-proxy/cmd/route-proxy/plans.go +++ b/modules/route-proxy/cmd/route-proxy/plans.go @@ -6,7 +6,7 @@ package main // **A route is a provision, in route-proxy's own contract.** A module that must be reachable requires `route`; the // seat mesh-provisioner composes its plan on its node, and the plan's entry for the route names this proxy as its provider and // carries what the module contributes, composed (its names joined to the node's domains, the machine port its -// placement assigned its endpoint, never the software's own), and where the module's machine is on the private +// the assignments gave its endpoint, never the software's own), and where the module's machine is on the private // network, as one opaque payload the seat never reads (mesh-sdk catalogue.PlanProvision.Contributed). The proxy decodes each contribution with its contract (contract.DecodeRequest) // and serves every entry naming it. There is no file and no second source: a route the plans do not name is not // served, and a route the contract refuses is said refused (contract.EventRefused), never served half. diff --git a/modules/route-proxy/cmd/route-proxy/reach_test.go b/modules/route-proxy/cmd/route-proxy/reach_test.go index 1f58fe5..d373331 100644 --- a/modules/route-proxy/cmd/route-proxy/reach_test.go +++ b/modules/route-proxy/cmd/route-proxy/reach_test.go @@ -15,8 +15,8 @@ import ( "strings" "testing" - "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient" - seat "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner" + "git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient" + seat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner" stdio "git.novox.be/novox/mesh-sdk/go" "route-proxy/contract" @@ -208,8 +208,8 @@ func contributed(at string, each ...string) string { // loopback on this machine and at the plan's address on another; an entry routing elsewhere, carrying nothing, naming // no address or a route the contract refuses is not served, and is said refused. A change is served as it comes and // said served or withdrawn, a plan that cannot be read keeps what it gave, and a deleted one withdraws it. The -// placement says only who is inside: an internal-only name is served to the machines it decides addresses for. -func TestThePlansAreServedAndThePlacementSaysWhoIsInside(t *testing.T) { +// the assignments say only who is inside: an internal-only name is served to the machines it decides addresses for. +func TestThePlansAreServedAndTheAssignmentsSayWhoIsInside(t *testing.T) { const route = `{"provision":"route","provider":"anchor","provider-module":"route-proxy",` gitea := route + contributed("10.10.0.7", "web", `{"name":"git.example","internal-name":"git.anchor.internal","port":3000}`, @@ -304,29 +304,29 @@ func TestThePlansAreServedAndThePlacementSaysWhoIsInside(t *testing.T) { held = behind(t) if code, _ := askFrom(held, "admin.anchor.internal", "10.10.0.7:1"); code != http.StatusNotFound { - t.Errorf("before the placement is read, a machine of the mesh was served an internal-only name: %d", code) + t.Errorf("before the assignments are read, a machine of the mesh was served an internal-only name: %d", code) } - laptop, err := meshmoduleassignerclient.PlacementValues(seat.Placement{V: meshmoduleassignerclient.Version, Node: "laptop", Decided: seat.NodeDecided{Address: "10.10.0.7"}}) + laptop, err := meshmoduleassignerclient.AssignmentsValues(seat.Assignments{V: meshmoduleassignerclient.Version, Node: "laptop", Decided: seat.NodeDecided{Address: "10.10.0.7"}}) if err != nil { t.Fatal(err) } - placement := &fakePlans{current: map[string]string{}} + assignments := &fakePlans{current: map[string]string{}} for k, v := range laptop { - placement.current[k] = string(v) + assignments.current[k] = string(v) } - if err := followInside(placement, held); err != nil { + if err := followInside(assignments, held); err != nil { t.Fatal(err) } if code, _ := askFrom(held, "admin.anchor.internal", "10.10.0.7:1"); code == http.StatusNotFound { - t.Error("a machine the placement decides an address for was refused the internal-only route") + t.Error("a machine the assignments decide an address for was refused the internal-only route") } if code, _ := askFrom(held, "admin.anchor.internal", "10.10.0.8:1"); code != http.StatusNotFound { - t.Error("a machine the placement does not name was served the internal-only route") + t.Error("a machine the assignments do not name was served the internal-only route") } - if err := placement.handle(stdio.StateChange{Key: "laptop.node", Op: "put", Value: json.RawMessage(`{`)}); err != nil { + if err := assignments.handle(stdio.StateChange{Key: "laptop.node", Op: "put", Value: json.RawMessage(`{`)}); err != nil { t.Fatal(err) } if code, _ := askFrom(held, "admin.anchor.internal", "10.10.0.7:1"); code == http.StatusNotFound { - t.Error("an unreadable placement key changed who is inside") + t.Error("an unreadable assignments key changed who is inside") } } diff --git a/modules/route-proxy/cmd/route-proxy/routes_test.go b/modules/route-proxy/cmd/route-proxy/routes_test.go index d5554a5..cf6b894 100644 --- a/modules/route-proxy/cmd/route-proxy/routes_test.go +++ b/modules/route-proxy/cmd/route-proxy/routes_test.go @@ -158,7 +158,7 @@ func TestARouteWithNoInternalNameGetsNoAlias(t *testing.T) { // 3000, published at 20000, and grafana's 3000 on another machine, published at 20012, answered 502): over loopback // when the plan is the one of this proxy's own node, which is the only thing that works without a private network, and // at the address the entry gives for its machine otherwise. The plans here are written as the seat mesh-provisioner -// carries them; that the port is the placement's and not the software's own is the composition's, proved by the +// carries them; that the port is the assignments' and not the software's own is the composition's, proved by the // node-engine's composer, not here. func TestAPlanEntryIsDialledAtTheMachinePortItCarries(t *testing.T) { for _, c := range []struct { diff --git a/modules/route-proxy/go.mod b/modules/route-proxy/go.mod index ed31ae5..51ccfeb 100644 --- a/modules/route-proxy/go.mod +++ b/modules/route-proxy/go.mod @@ -3,8 +3,8 @@ module route-proxy go 1.26.0 require ( - git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient v0.0.0-00010101000000-000000000000 - git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/go/clients/meshmoduleassignerclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/provisioning/go/seats/meshprovisioner v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-sdk/go v0.0.0-00010101000000-000000000000 diff --git a/modules/route-proxy/module.json b/modules/route-proxy/module.json index 668ab88..b4055ab 100644 --- a/modules/route-proxy/module.json +++ b/modules/route-proxy/module.json @@ -265,7 +265,7 @@ ] }, "reads": [ - "mesh-delivery-assigner.placement", + "mesh-delivery-assigner.assignments", "mesh-provisioner.plans", "mesh-provisioner.provisions" ]