Merge b6/registry into the registry milestone's join: the console reads through the assigner's client, with the seat name mesh-module-assigner (issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -18,7 +18,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
"git.novox.be/novox/mesh-sdk/go/membership"
|
||||
"log"
|
||||
"regexp"
|
||||
@@ -355,7 +354,7 @@ func (c *Conn) Credential() Credential { return c.cred }
|
||||
|
||||
// Follow reads a module's membership on this machine once and follows it live, so its tools are
|
||||
// served where the mesh issued them (ADR 0175). It is read from the grants part's state memberships, its key
|
||||
// `<node>.<module>` (novox/hq ADR 0571 clause 7 and 10, mesh-sdk buscompose.GrantsMembershipsBucket), and nowhere else:
|
||||
// `<node>.<module>` (novox/hq ADR 0571 clause 7 and 10, mesh-sdk membership.GrantsBucket), and nowhere else:
|
||||
// the old assignments stream is not read and its subject is not heard.
|
||||
func (c *Conn) Follow(module string) {
|
||||
c.mu.Lock()
|
||||
@@ -434,10 +433,10 @@ func (c *Conn) watchGrants(module string, say bool) bool {
|
||||
c.Logf(format, a...)
|
||||
}
|
||||
}
|
||||
key := buscompose.MembershipKey(c.node, module)
|
||||
key := membership.GrantsKey(c.node, module)
|
||||
// First the key's direct get, which the account is granted alone: a bus that refuses it, or a state not there yet,
|
||||
// answers at once, where binding the bucket would wait out its bound on a refusal.
|
||||
bucket := buscompose.GrantsMembershipsBucket
|
||||
bucket := membership.GrantsBucket
|
||||
probe, err := c.nc.Request("$JS.API.DIRECT.GET.KV_"+bucket+".$KV."+bucket+"."+key, nil, GrantsPatience)
|
||||
if err != nil || probe.Header.Get("Status") == "503" {
|
||||
why := "it did not answer"
|
||||
@@ -457,7 +456,7 @@ func (c *Conn) watchGrants(module string, say bool) bool {
|
||||
kv, err := js.KeyValue(ctx, bucket)
|
||||
if err != nil {
|
||||
logf("[mesh-tools] the grants part's memberships (%s) cannot be read (%v); %s has no membership "+
|
||||
"until it can be", buscompose.GrantsMembershipsBucket, err, module)
|
||||
"until it can be", membership.GrantsBucket, err, module)
|
||||
return false
|
||||
}
|
||||
w, err := kv.Watch(context.Background(), key)
|
||||
|
||||
@@ -17,8 +17,10 @@ package console
|
||||
// session — so a tool that arrived a minute ago is found without the client reconnecting.
|
||||
|
||||
import (
|
||||
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
meshcatalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
@@ -30,6 +32,7 @@ import (
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/announce"
|
||||
"github.com/novox/mesh-tools/node-tools/internal/bus"
|
||||
"github.com/novox/mesh-tools/node-tools/internal/firstview"
|
||||
)
|
||||
|
||||
// IndexKept is how long what the mesh answered is kept before it is asked again: long enough that
|
||||
@@ -149,7 +152,7 @@ type index struct {
|
||||
// called missing while it is here (2026-10-05).
|
||||
Unheard []unheard
|
||||
// Placed is the state seat-holders as the seat mesh-module-assigner's holder wrote it (novox/hq ADR 0571 clause 4), by its
|
||||
// keys `<seat>` and `<seat>.<node>`, read with delivery.HoldersOf; PlacedWhy says why it could not be read.
|
||||
// keys `<seat>` and `<seat>.<node>`, read with assigner.HoldersOf; PlacedWhy says why it could not be read.
|
||||
Placed map[string][]byte
|
||||
PlacedWhy string
|
||||
// Replaces is what each verb and tool replaces (novox/hq ADR 0245):
|
||||
@@ -337,7 +340,7 @@ func indexOn(conn *bus.Conn, src Source, held announce.Known, before func(announ
|
||||
}
|
||||
l.NotAnswering = append(l.NotAnswering, recordsWhy...)
|
||||
if x.PlacedWhy != "" {
|
||||
l.NotAnswering = append(l.NotAnswering, delivery.SeatHoldersRead+" (who holds which seat by placement could not be read: "+
|
||||
l.NotAnswering = append(l.NotAnswering, assigner.SeatHoldersRead+" (who holds which seat by placement could not be read: "+
|
||||
x.PlacedWhy+")")
|
||||
}
|
||||
for _, u := range x.Unheard {
|
||||
@@ -357,7 +360,7 @@ func indexOn(conn *bus.Conn, src Source, held announce.Known, before func(announ
|
||||
}
|
||||
|
||||
// Source is where the console reads the four states of the indexer and the assigner it indexes the mesh by: the assigner's
|
||||
// placement and seat-holders, the indexer's modules and manifests, by `<owner>.<state>` (delivery.PlacementRead and the
|
||||
// placement and seat-holders, the indexer's modules and manifests, by `<owner>.<state>` (assigner.PlacementRead and the
|
||||
// rest). The tool runner's is its first views (firstview.Views), never the owners' state (novox/hq ADR 0615 §1).
|
||||
type Source interface {
|
||||
// State is every current value of a state by key; an error says why it cannot be told yet.
|
||||
@@ -366,16 +369,16 @@ type Source interface {
|
||||
Entry(name, key string) ([]byte, error)
|
||||
}
|
||||
|
||||
// seatHoldersOn reads the state seat-holders whole (novox/hq ADR 0571 clause 4), as delivery.SeatHoldersRead.
|
||||
// seatHoldersOn reads the state seat-holders whole (novox/hq ADR 0571 clause 4), as assigner.SeatHoldersRead.
|
||||
func seatHoldersOn(src Source) (map[string][]byte, error) {
|
||||
return src.State(delivery.SeatHoldersRead)
|
||||
return src.State(assigner.SeatHoldersRead)
|
||||
}
|
||||
|
||||
// The indexer's states the console reads (novox/hq ADR 0571 clauses 4 and 5): every module, and each manifest by its
|
||||
// digest, by the names a reader's manifest declares.
|
||||
var (
|
||||
modulesRead = delivery.IndexerModule + ".modules"
|
||||
manifestsRead = delivery.IndexerModule + ".manifests"
|
||||
modulesRead = firstview.ModulesRead
|
||||
manifestsRead = firstview.ManifestsRead
|
||||
)
|
||||
|
||||
// manifestFacts is what the console takes of a manifest: the tools it declares and what each replaces. A manifest's
|
||||
@@ -388,20 +391,20 @@ type manifestFacts struct {
|
||||
var manifestsKept sync.Map // digest → manifestFacts
|
||||
|
||||
// recordsOn is every module the indexer holds, with where the placement seat places it and whether it declares tools,
|
||||
// and every machine placement names (delivery.ModuleNames, delivery.MachineNames). What cannot be read is said, one line
|
||||
// and every machine placement names (moduleNames, assigner.MachineNames). What cannot be read is said, one line
|
||||
// per state, for the listing's not answering.
|
||||
func recordsOn(src Source) (recorded []recordedModule, machines []string, why []string) {
|
||||
placements, err := src.State(delivery.PlacementRead)
|
||||
placements, err := src.State(assigner.PlacementRead)
|
||||
if err != nil {
|
||||
why = append(why, delivery.PlacementRead+" (where modules are placed could not be read, so what is missing cannot "+
|
||||
why = append(why, assigner.PlacementRead+" (where modules are placed could not be read, so what is missing cannot "+
|
||||
"be said: "+err.Error()+")")
|
||||
}
|
||||
machines = delivery.MachineNames(placements)
|
||||
machines = assigner.MachineNames(placements)
|
||||
on := map[string][]string{}
|
||||
// The placement's keys in either form, a node key and its module keys or the form before (research 072 row 37).
|
||||
assembled, err := delivery.PlacementsOf(placements)
|
||||
assembled, err := assigner.PlacementsOf(placements)
|
||||
if err != nil {
|
||||
why = append(why, delivery.PlacementRead+" (not every key is a placement: "+err.Error()+")")
|
||||
why = append(why, assigner.PlacementRead+" (not every key is a placement: "+err.Error()+")")
|
||||
}
|
||||
for _, node := range machines {
|
||||
for _, m := range assembled[node].Modules {
|
||||
@@ -412,13 +415,13 @@ func recordsOn(src Source) (recorded []recordedModule, machines []string, why []
|
||||
if err != nil {
|
||||
return nil, machines, append(why, modulesRead+" (which modules there are could not be read: "+err.Error()+")")
|
||||
}
|
||||
names, err := delivery.ModuleNames(modules)
|
||||
names, err := moduleNames(modules)
|
||||
if err != nil {
|
||||
return nil, machines, append(why, modulesRead+" ("+err.Error()+")")
|
||||
}
|
||||
for _, name := range names {
|
||||
r := recordedModule{Module: name, On: on[name]}
|
||||
if m, err := delivery.DecodeModule(modules[name]); err == nil && m.Manifest != "" {
|
||||
if m, err := meshcatalogclient.DecodeModule(modules[name]); err == nil && m.Manifest != "" {
|
||||
facts, err := manifestOf(src, m.Manifest)
|
||||
if err != nil {
|
||||
why = append(why, name+" (its manifest could not be read, so whether it answers tools is not known: "+err.Error()+")")
|
||||
@@ -431,6 +434,21 @@ func recordsOn(src Source) (recorded []recordedModule, machines []string, why []
|
||||
return recorded, machines, why
|
||||
}
|
||||
|
||||
// moduleNames is every module the indexer holds, sorted, from its state `modules` as a reader holds its keys (key to
|
||||
// value; a deleted key absent). A key that is not a module's is refused, naming it.
|
||||
func moduleNames(keys map[string][]byte) ([]string, error) {
|
||||
out := make([]string, 0, len(keys))
|
||||
for k := range keys {
|
||||
module, err := meshcatalogclient.ParseModulesKey(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, module)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// manifestOf is what the console takes of the manifest of a digest, read from the indexer's manifests once.
|
||||
func manifestOf(src Source, digest string) (manifestFacts, error) {
|
||||
if kept, ok := manifestsKept.Load(digest); ok {
|
||||
@@ -443,12 +461,12 @@ func manifestOf(src Source, digest string) (manifestFacts, error) {
|
||||
if entry == nil {
|
||||
return manifestFacts{}, fmt.Errorf("the indexer holds no manifest %s", digest)
|
||||
}
|
||||
m, err := delivery.DecodeManifest(entry)
|
||||
m, err := meshcatalogclient.DecodeManifest(entry)
|
||||
if err != nil {
|
||||
return manifestFacts{}, err
|
||||
}
|
||||
var facts manifestFacts
|
||||
if err := json.Unmarshal([]byte(m.JSON), &facts); err != nil {
|
||||
if err := json.Unmarshal([]byte(m.Manifest), &facts); err != nil {
|
||||
return manifestFacts{}, err
|
||||
}
|
||||
manifestsKept.Store(digest, facts)
|
||||
@@ -456,19 +474,19 @@ func manifestOf(src Source, digest string) (manifestFacts, error) {
|
||||
}
|
||||
|
||||
// placedHolders is who holds seat (on node, for a seat held per machine) by placement, or none.
|
||||
func (x *index) placedHolders(seat, node string) []delivery.SeatHolder {
|
||||
func (x *index) placedHolders(seat, node string) []meshmoduleassigner.SeatHoldersHoldersItem {
|
||||
if len(x.Placed) == 0 {
|
||||
return nil
|
||||
}
|
||||
hs, err := delivery.HoldersOf(x.Placed, seat, node)
|
||||
hs, err := assigner.HoldersOf(x.Placed, seat, node)
|
||||
if err != nil || len(hs) > 0 || node != "" {
|
||||
return hs
|
||||
}
|
||||
// A seat held per machine, asked without one: every node's key of it.
|
||||
var all []delivery.SeatHolder
|
||||
var all []meshmoduleassigner.SeatHoldersHoldersItem
|
||||
for key := range x.Placed {
|
||||
if s, n, ok := strings.Cut(key, "."); ok && s == seat {
|
||||
if more, err := delivery.HoldersOf(x.Placed, seat, n); err == nil {
|
||||
if more, err := assigner.HoldersOf(x.Placed, seat, n); err == nil {
|
||||
all = append(all, more...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ package console
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -78,7 +78,7 @@ func (s *Surface) seatsAnswer() map[string]any {
|
||||
for _, st := range catalogue.Seats() {
|
||||
holders := x.placedHolders(st.Name, "")
|
||||
if holders == nil {
|
||||
holders = []delivery.SeatHolder{}
|
||||
holders = []meshmoduleassigner.SeatHoldersHoldersItem{}
|
||||
}
|
||||
tools := st.Serves
|
||||
if tools == nil {
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
seatplacement "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
"github.com/nats-io/nats.go/micro"
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/announce"
|
||||
@@ -61,13 +62,15 @@ func TestARuntimeThatAnswersLateIsFoundAndOneThatNeverDoesIsNamed(t *testing.T)
|
||||
map[string][]string{"laptop": {"slack", "nextcloud-client"}, "sleeper": {"nap", "nextcloud-client"},
|
||||
"desktop": {"nextcloud-client"}, "bench": nil})
|
||||
// Who holds which seat, by placement (ADR 0571 clause 4), as the seat mesh-module-assigner's holder composes it.
|
||||
placedKV := mesh.Bucket(t, delivery.SeatHoldersBucket)
|
||||
for key, sh := range delivery.SeatHoldersOf(map[string]delivery.Placement{"bench": {Node: "bench",
|
||||
Holds: []delivery.Holding{{Claim: "mesh-wants", Scope: "mesh", Module: "mesh-delivery-assigner"}}}}) {
|
||||
raw, _ := json.Marshal(sh)
|
||||
if _, err := placedKV.Put(key, raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
placedKV := mesh.Bucket(t, assigner.SeatHoldersBucket)
|
||||
holdersKey, err := assigner.SeatHoldersKey("mesh-wants", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw, _ := json.Marshal(seatplacement.SeatHolders{V: assigner.Version, Seat: "mesh-wants", Scope: "mesh",
|
||||
Holders: []seatplacement.SeatHoldersHoldersItem{{Module: "mesh-delivery-assigner", Node: "bench"}}})
|
||||
if _, err := placedKV.Put(holdersKey, raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
consoleMembership := mt.MembershipOf("node-tools", "laptop-console", false, nil)
|
||||
consoleMembership.State = mt.ConsoleReads()
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"fmt"
|
||||
conditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
|
||||
condseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
||||
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -25,7 +26,14 @@ import (
|
||||
// The owners and their first-view tools (the tools' addresses are `<owner>.<tool>`).
|
||||
const (
|
||||
Indexer = "mesh-delivery-indexer"
|
||||
Assigner = "mesh-delivery-assigner"
|
||||
Assigner = assigner.Module
|
||||
)
|
||||
|
||||
// The names the console reads the indexer's two states by (`<owner>.<state>`), as a manifest's `reads` names them; the
|
||||
// assigner's two are its client's (assigner.PlacementRead, assigner.SeatHoldersRead).
|
||||
const (
|
||||
ModulesRead = Indexer + ".modules"
|
||||
ManifestsRead = Indexer + ".manifests"
|
||||
)
|
||||
|
||||
// Spec is one first view the runner holds.
|
||||
@@ -39,7 +47,7 @@ var Specs = []Spec{
|
||||
{Indexer, "modules", "modules"},
|
||||
}
|
||||
|
||||
// Name is the name a state is read by, `<owner>.<state>`: delivery.PlacementRead, delivery.SeatHoldersRead and the indexer's.
|
||||
// Name is the name a state is read by, `<owner>.<state>`: assigner.PlacementRead, assigner.SeatHoldersRead and the indexer's.
|
||||
func (s Spec) Name() string { return s.Owner + "." + s.State }
|
||||
|
||||
// Views is the four followers.
|
||||
@@ -207,8 +215,8 @@ func conditionOf(f views.Finding) (string, []byte, error) {
|
||||
key := conditions.Key(scopeModule, f.ID, f.Kind)
|
||||
v := condseat.FindingsByKeyValue{V: 1, Key: key, Kind: f.Kind, Observer: f.Observer, Severity: conditions.Warning,
|
||||
Subject: condseat.Subject{Scope: scopeModule, ID: f.ID}, Summary: f.Summary, Headline: f.Headline,
|
||||
Explanation: f.Explanation, Source: f.Observer + "." + f.Kind, At: f.At.UTC().Format(time.RFC3339),
|
||||
Evidence: []condseat.Evidence{{At: f.At.UTC().Format(time.RFC3339), Said: f.Summary}}}
|
||||
Explanation: f.Explanation, Source: f.Observer + "." + f.Kind, At: f.At.UTC(),
|
||||
Evidence: []condseat.Evidence{{At: f.At.UTC(), Said: f.Summary}}}
|
||||
if err := conditions.CheckFinding(v); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
@@ -44,7 +44,10 @@ func TestTheRunnersConsumerCarriesTheOwnersViewsFamiliesWhenTheOwnersAreDownThen
|
||||
filters := map[string][]string{}
|
||||
families := 0
|
||||
for _, c := range manifest.Consumes {
|
||||
emitter, event, _ := strings.Cut(c, ".views.")
|
||||
emitter, event, isView := strings.Cut(c, ".views.")
|
||||
if !isView { // the seat mesh-catalog's events: the seat list's, on EVENTS (cmd/node-tools/seatlist.go)
|
||||
continue
|
||||
}
|
||||
stream := streamOf[emitter]
|
||||
if stream == "" {
|
||||
t.Fatalf("the manifest consumes %s, whose views stream the test does not know", c)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/bus"
|
||||
@@ -166,3 +167,18 @@ func TestTheRunnerHoldsTheFourStatesFromTheOwnersFirstViewsAndTheirEvents(t *tes
|
||||
t.Errorf("the gap was not said in the log: %v", logs)
|
||||
}
|
||||
}
|
||||
|
||||
// The four first views are read by the names the seats' clients give the states, and the console reads the indexer's
|
||||
// two by the names here.
|
||||
func TestTheFirstViewsAreNamedAsTheClientsNameTheirStates(t *testing.T) {
|
||||
want := map[string]bool{assigner.PlacementRead: true, assigner.SeatHoldersRead: true, ModulesRead: true, ManifestsRead: true}
|
||||
for _, s := range Specs {
|
||||
if !want[s.Name()] {
|
||||
t.Errorf("the first view %s is read by no name a client gives", s.Name())
|
||||
}
|
||||
delete(want, s.Name())
|
||||
}
|
||||
if len(want) > 0 {
|
||||
t.Errorf("no first view reads %v", want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ package meshtest
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
|
||||
seatplacement "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
|
||||
meshcatalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
|
||||
meshcatalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-sdk/go/membership"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -88,8 +90,8 @@ func New(t *testing.T) *Mesh {
|
||||
js, _ := nc.JetStream()
|
||||
_ = js.DeleteStream("EVENTS")
|
||||
// The grants part's state memberships, where a runtime reads what is issued it (ADR 0571 clause 10).
|
||||
_ = js.DeleteKeyValue(buscompose.GrantsMembershipsBucket)
|
||||
if _, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: buscompose.GrantsMembershipsBucket, History: 1}); err != nil {
|
||||
_ = js.DeleteKeyValue(membership.GrantsBucket)
|
||||
if _, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: membership.GrantsBucket, History: 1}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := js.AddStream(&nats.StreamConfig{Name: "EVENTS", Subjects: []string{"mesh.mod.*.event.>"}}); err != nil {
|
||||
@@ -100,7 +102,7 @@ func New(t *testing.T) *Mesh {
|
||||
}
|
||||
|
||||
// Issue writes a membership where the grants part keeps it, its state memberships, key `<node>.<module>` (novox/hq ADR
|
||||
// 0571 clause 7 and 10; mesh-sdk buscompose.GrantsMembershipsBucket), the one place a runtime reads it. It writes with
|
||||
// 0571 clause 7 and 10; mesh-sdk membership.GrantsBucket), the one place a runtime reads it. It writes with
|
||||
// mesh-sdk's encoder, the grants part's own, never json of this package's type: a value built here by hand agreed with
|
||||
// the reader's mistake and hid that the part wrote another shape (issue 774).
|
||||
func (m *Mesh) Issue(t *testing.T, mem bus.Membership) {
|
||||
@@ -120,13 +122,13 @@ func (m *Mesh) IssueInGrantsWrapped(t *testing.T, mem bus.Membership, published
|
||||
|
||||
func (m *Mesh) putGrants(t *testing.T, mem bus.Membership, body []byte) {
|
||||
t.Helper()
|
||||
kv, err := m.js.KeyValue(buscompose.GrantsMembershipsBucket)
|
||||
kv, err := m.js.KeyValue(membership.GrantsBucket)
|
||||
if err != nil {
|
||||
if kv, err = m.js.CreateKeyValue(&nats.KeyValueConfig{Bucket: buscompose.GrantsMembershipsBucket, History: 1}); err != nil {
|
||||
if kv, err = m.js.CreateKeyValue(&nats.KeyValueConfig{Bucket: membership.GrantsBucket, History: 1}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if _, err := kv.Put(buscompose.MembershipKey(mem.Node, mem.Module), body); err != nil {
|
||||
if _, err := kv.Put(membership.GrantsKey(mem.Node, mem.Module), body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -134,7 +136,7 @@ func (m *Mesh) putGrants(t *testing.T, mem bus.Membership, body []byte) {
|
||||
// DropGrants deletes the grants part's state memberships, as a bus that has not made it yet holds none; Issue makes it again.
|
||||
func (m *Mesh) DropGrants(t *testing.T) {
|
||||
t.Helper()
|
||||
if err := m.js.DeleteKeyValue(buscompose.GrantsMembershipsBucket); err != nil {
|
||||
if err := m.js.DeleteKeyValue(membership.GrantsBucket); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -150,14 +152,22 @@ func sdkMembership(t *testing.T, mem bus.Membership) membership.Membership {
|
||||
return out
|
||||
}
|
||||
|
||||
// The indexer's two states the console reads, and their buckets (the test bed's own names: the indexer's client names
|
||||
// no holder).
|
||||
const (
|
||||
indexer = "mesh-delivery-indexer"
|
||||
ModulesBucket = indexer + "_modules"
|
||||
ManifestsBucket = indexer + "_manifests"
|
||||
)
|
||||
|
||||
// ConsoleReads are the states a console's runtime reads to say what the mesh holds (novox/hq ADR 0571 clauses 4, 5):
|
||||
// placement, the indexer's modules and manifests, and the seat holders.
|
||||
func ConsoleReads() []bus.StateIssued {
|
||||
return []bus.StateIssued{
|
||||
{Name: delivery.PlacementRead, Bucket: delivery.PlacementBucket},
|
||||
{Name: delivery.IndexerModule + ".modules", Bucket: delivery.ModulesBucket},
|
||||
{Name: delivery.IndexerModule + ".manifests", Bucket: delivery.ManifestsBucket},
|
||||
{Name: delivery.SeatHoldersRead, Bucket: delivery.SeatHoldersBucket},
|
||||
{Name: assigner.PlacementRead, Bucket: assigner.PlacementBucket},
|
||||
{Name: indexer + ".modules", Bucket: ModulesBucket},
|
||||
{Name: indexer + ".manifests", Bucket: ManifestsBucket},
|
||||
{Name: assigner.SeatHoldersRead, Bucket: assigner.SeatHoldersBucket},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,20 +183,20 @@ func (m *Mesh) Placed(t *testing.T, tools map[string][]string, on map[string][]s
|
||||
}
|
||||
return b
|
||||
}
|
||||
modules, manifests, placement := kv(delivery.ModulesBucket), kv(delivery.ManifestsBucket), kv(delivery.PlacementBucket)
|
||||
kv(delivery.SeatHoldersBucket)
|
||||
modules, manifests, placement := kv(ModulesBucket), kv(ManifestsBucket), kv(assigner.PlacementBucket)
|
||||
kv(assigner.SeatHoldersBucket)
|
||||
for module, declared := range tools {
|
||||
manifest, _ := json.Marshal(map[string]any{"module": module, "tools": declared})
|
||||
digest := delivery.ManifestDigest(manifest)
|
||||
raw, err := delivery.EncodeManifest(delivery.Manifest{Module: module, JSON: string(manifest)})
|
||||
digest := meshcatalogclient.ManifestDigest(manifest)
|
||||
raw, err := meshcatalogclient.EncodeManifest(meshcatalog.ManifestsByDigestValue{Module: module, Manifest: string(manifest), V: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := manifests.Put(digest, raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw, err = delivery.EncodeModule(delivery.Module{None: "not built here", Manifest: digest, Repository: "novox/" + module,
|
||||
Commit: strings.Repeat("a", 40)})
|
||||
raw, err = meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{None: "not built here", Manifest: digest, Repository: "novox/" + module,
|
||||
Commit: strings.Repeat("a", 40), V: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -195,12 +205,12 @@ func (m *Mesh) Placed(t *testing.T, tools map[string][]string, on map[string][]s
|
||||
}
|
||||
}
|
||||
for node, placed := range on {
|
||||
p := delivery.Placement{V: delivery.Version, Node: node}
|
||||
p := seatplacement.Placement{V: assigner.Version, Node: node}
|
||||
for _, module := range placed {
|
||||
p.Modules = append(p.Modules, delivery.PlacedModule{Module: module})
|
||||
p.Modules = append(p.Modules, seatplacement.PlacedModule{Module: module})
|
||||
}
|
||||
// As the seat writes it: its node key and a key per module (research 072 row 37).
|
||||
values, err := delivery.PlacementValues(p)
|
||||
values, err := assigner.PlacementValues(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/provider"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
provisions "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient/provider"
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/bus"
|
||||
)
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
provisions "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient/provider"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/provider"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/bus"
|
||||
mt "github.com/novox/mesh-tools/node-tools/internal/meshtest"
|
||||
|
||||
@@ -63,7 +63,7 @@ func TestALedgerIsWrittenOnlyOnItsModulesLedgerConnection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, b := range []string{"m_records", buscompose.GrantsMembershipsBucket} {
|
||||
for _, b := range []string{"m_records", membership.GrantsBucket} {
|
||||
if _, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: b}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -76,8 +76,8 @@ func TestALedgerIsWrittenOnlyOnItsModulesLedgerConnection(t *testing.T) {
|
||||
raw, _ := json.Marshal(mem)
|
||||
var sdk membership.Membership
|
||||
_ = json.Unmarshal(raw, &sdk)
|
||||
grants, _ := js.KeyValue(ctx, buscompose.GrantsMembershipsBucket)
|
||||
if _, err := grants.Put(ctx, buscompose.MembershipKey("anchor", "m"), membership.EncodeGrantsMembership(sdk)); err != nil {
|
||||
grants, _ := js.KeyValue(ctx, membership.GrantsBucket)
|
||||
if _, err := grants.Put(ctx, membership.GrantsKey("anchor", "m"), membership.EncodeGrantsMembership(sdk)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user