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
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user