mesh-provisioner-client reads the placement and the node's have through the placement and node-engine clients and the seats' types (B5e; ADR 0634 §1, §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:38:00 +01:00
parent 8fabdc4b91
commit 597910c291
3 changed files with 35 additions and 19 deletions
@@ -1,6 +1,10 @@
package main
import (
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
assignerclient "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
mesh "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
"bytes"
@@ -14,8 +18,6 @@ import (
"strings"
"time"
"git.novox.be/novox/mesh-sdk/go/delivery"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
@@ -40,6 +42,13 @@ import (
// the plans whole, for who binds a provider here (ADR 0373), and the seat mesh-module-assigner's placement, for which
// modules stay here: its bus account is granted no other.
// The holders whose states this module reads, each named once here (held equal to the manifest's `reads` by a unit row).
const (
assignerModule = "mesh-delivery-assigner"
engineHolder = "node-engine"
haveBucket = engineHolder + "_" + nodeengine.StateHave
)
// The buckets the client reads and writes, and the subject it reports on.
const (
// PlansBucket is where each module's provisioning plan on each node is read: the seat mesh-provisioner's
@@ -49,7 +58,7 @@ const (
// here while the seat mesh-provisioner holds no plan of it (nats on novox runs without a want), filled from its
// last plan, and leaves only when neither names it (issue 1126 B12; the controller's assignments mirror, read for
// this before, is frozen since the controller's end, ADR 0590).
PlacementBucket = delivery.PlacementBucket
PlacementBucket = assignerModule + "_" + mesh.StatePlacement
ConfigBucket = "mesh-config_resolved"
RegistryBucket = "mesh-provisioner_registry"
AppliedBucket = "mesh-provisioner_applied"
@@ -156,7 +165,7 @@ type state struct {
// seatPlans is the seat's plan by key, as an assignment's value reads.
seatPlans map[string][]byte
// placement is the seat mesh-module-assigner's keys as read, and placed the modules it names on this node.
placement *delivery.PlacementKeys
placement *assignerclient.Keys
placed map[string]bool
refused map[string]string // a module whose plan cannot be acted on, and why
config map[string]map[string]json.RawMessage
@@ -258,13 +267,13 @@ func (c *Client) Run(ctx context.Context) error {
// Its node's own have, one key: the node-engine moving to a new composition of the node's own fills every module
// again, since an apply may have left a filled file as the composition had it (issue 1945, live on 2026-10-25). A
// bucket not there yet (a node-engine before release 6) is said, and nothing waits for it.
if haveKV, err := c.JS.KeyValue(ctx, delivery.HaveBucket); err == nil {
ownKey, err := delivery.HaveNodeKey(c.Node)
if haveKV, err := c.JS.KeyValue(ctx, haveBucket); err == nil {
ownKey, err := engineclient.HaveNodeKey(c.Node)
if err != nil {
return err
}
kvs[delivery.HaveBucket] = haveKV
if err := watch(delivery.HaveBucket, ownKey); err != nil {
kvs[haveBucket] = haveKV
if err := watch(haveBucket, ownKey); err != nil {
return err
}
} else {
@@ -335,7 +344,7 @@ func (c *Client) Run(ctx context.Context) error {
config: map[string]map[string]json.RawMessage{}, applied: map[string]bool{},
reported: map[string][]byte{}, secrets: map[string]heldSecret{}, items: map[string]map[string]itemValue{},
recorded: map[string][]byte{}, assigned: map[string]bool{}, binds: map[string]binding{},
placement: delivery.NewPlacementKeys(), placed: map[string]bool{},
placement: assignerclient.NewKeys(), placed: map[string]bool{},
providing: map[string]bool{}, leftOut: map[string]string{}, bound: map[string]map[string][]byte{},
boundReady: map[string]bool{}, unplaced: map[string]bool{}, boundUsers: map[string]map[string]bool{}}
// Every current value first: nothing is filled from half of them.
@@ -356,7 +365,7 @@ func (c *Client) Run(ctx context.Context) error {
if u.socketUp {
continue // the first fill below tries every file
}
if u.bucket == delivery.HaveBucket {
if u.bucket == haveBucket {
// The composition the node runs now: the first fill below fills every module anyway.
if u.entry != nil {
s.ownComposed = ownComposedOf(u.entry)
@@ -411,7 +420,7 @@ func (c *Client) Run(ctx context.Context) error {
for _, m := range c.woken(s) {
dirty[m] = true
}
case u.bucket == delivery.HaveBucket:
case u.bucket == haveBucket:
if u.entry == nil {
break
}
@@ -500,7 +509,7 @@ func ownComposedOf(e jetstream.KeyValueEntry) string {
if e.Operation() != jetstream.KeyValuePut {
return ""
}
h, err := delivery.DecodeHaveNode(e.Value())
h, err := engineclient.DecodeHaveNode(e.Value())
if err != nil {
return ""
}
@@ -8,7 +8,10 @@ import (
"encoding/json"
"errors"
"fmt"
"git.novox.be/novox/mesh-sdk/go/delivery"
engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
assignerclient "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
mesh "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
"net"
"net/http"
"net/http/httptest"
@@ -82,7 +85,7 @@ func startBus(t *testing.T) *aBus {
}
b := &aBus{url: s.ClientURL(), domain: js, conn: nc, kv: map[string]jetstream.KeyValue{}}
for _, name := range []string{PlansBucket, PlacementBucket, ConfigBucket, RegistryBucket, AppliedBucket,
CollectBucket, delivery.HaveBucket} {
CollectBucket, haveBucket} {
kv, err := js.CreateKeyValue(context.Background(), jetstream.KeyValueConfig{Bucket: name})
if err != nil {
t.Fatal(err)
@@ -125,11 +128,11 @@ func (b *aBus) put(t *testing.T, bucket, key, value string) {
// place writes this node's placement as the seat mesh-module-assigner keeps it, naming exactly these modules.
func (b *aBus) place(t *testing.T, modules ...string) {
t.Helper()
p := delivery.Placement{V: 1, Node: node}
p := mesh.Placement{V: 1, Node: node}
for _, m := range modules {
p.Modules = append(p.Modules, delivery.PlacedModule{Module: m})
p.Modules = append(p.Modules, mesh.PlacedModule{Module: m})
}
keys := delivery.NewPlacementKeys()
keys := assignerclient.NewKeys()
ctx := context.Background()
have, _ := b.kv[PlacementBucket].Keys(ctx)
for _, k := range have {
@@ -807,11 +810,11 @@ func TestNatsTheNodesOwnHaveMovingFillsEveryModuleAgain(t *testing.T) {
b := startBus(t)
e := startEngine(t, map[string]string{dunstrc: "owned"})
own := func(digit string) {
raw, err := delivery.EncodeHaveNode(delivery.HaveNode{Composed: "sha256:" + strings.Repeat(digit, 64)})
raw, err := engineclient.EncodeHaveNode(nodeengine.HaveByNodeNodeValue{Composed: "sha256:" + strings.Repeat(digit, 64)})
if err != nil {
t.Fatal(err)
}
b.put(t, delivery.HaveBucket, node+".node", string(raw))
b.put(t, haveBucket, node+".node", string(raw))
}
own("a")
b.config(t, "dunst", "font-size", "13")
+4
View File
@@ -3,6 +3,10 @@ module mesh-provisioner-client
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-contracts/go/seats/nodeengine v0.0.0-00010101000000-000000000000
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/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174359-05b3e2e1b94f
github.com/nats-io/nats-server/v2 v2.11.17