CAT-N1: the bus module's keeper, its own events stream, state and the seat's reading verbs in the manifest
The keeper is a process of the tools bundle on its own account (own secret broker-keeper, ADR 0436 §1): it hears the indexer's manifest-accepted, keeps what it heard in its old state asked and the persons' requests in requests (ADR 0595 §10), and says its nine events on its own stream broker-events, 30 days at 256 MiB (design 25 § 12.3, ADR 0620 §2). mesh-broker serves its four reading verbs; its acting verbs are the keeper's own work. The server gains a tcp check, which the keeper's tool check stands beside. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -157,3 +157,12 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// The seat mesh-broker's reading verbs, which this bundle serves (design 25 § 12.3): every entry, one entry, what the
|
||||
// bus holds against what was asked, and what no manifest asks for. Its acting verbs (create, apply, recreate, drop) are
|
||||
// the keeper's own work, on its own account alone (keeper.go), so no other account, the tool runner's included, holds
|
||||
// them.
|
||||
var ReadingVerbs = []string{"list", "show", "check", "orphans"}
|
||||
|
||||
// Events are the bus module's own events (ADR 0595 §6, ADR 0620 §2), on its own stream broker-events (BROKER_EVENTS).
|
||||
var Events = []string{"created", "refused", "drifted", "drift-cleared", "full", "full-cleared", "orphaned", "recreated", "dropped"}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -150,6 +151,78 @@ func TestTheBussManifestMountsItsProgramsIntoTheUpstreamImage(t *testing.T) {
|
||||
t.Errorf("the tools' credential is %q: the process nats-tools' own secret broker-nats-tools, under a word of the bundle's own (the runtime strips MESH_BROKER_FILE)", a.Env["NATS_TOOLS_CREDENTIAL"])
|
||||
}
|
||||
}
|
||||
// The bus module provides bus state (design 25 § 12.2-12.3, ADR 0595 §4-§6; CAT-N1): its keeper is a process of
|
||||
// its own on its own account (own secret broker-keeper, ADR 0436 §1), creating only bus state; it hears the indexer's
|
||||
// manifest-accepted, keeps what it heard in its own old state `asked` (ADR 0595 §10) and the persons' requests in
|
||||
// `requests`; its nine events are its own (ADR 0620 §2), on its own stream kept 30 days at 256 MiB; the seat's four
|
||||
// reading verbs are served, its four acting verbs are the keeper's own work and no other account's; its health is
|
||||
// the keeper's own tool, beside the server's tcp check.
|
||||
var nm struct {
|
||||
Claims []struct {
|
||||
Name string `json:"name"`
|
||||
Serves []string `json:"serves"`
|
||||
} `json:"claims"`
|
||||
Consumes []string `json:"consumes"`
|
||||
Invokes []string `json:"invokes"`
|
||||
Uses []string `json:"uses"`
|
||||
OwnSecrets map[string]json.RawMessage `json:"own-secrets"`
|
||||
Streams []struct {
|
||||
Name string `json:"name"`
|
||||
Events []string `json:"events"`
|
||||
MaxAgeDays int `json:"max-age-days"`
|
||||
MaxMiB int `json:"max-mib"`
|
||||
} `json:"streams"`
|
||||
State []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"state"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &nm); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(nm.Claims) != 1 || nm.Claims[0].Name != "mesh-broker" || !slices.Equal(nm.Claims[0].Serves, ReadingVerbs) {
|
||||
t.Errorf("claims are %+v: mesh-broker, serving its reading verbs %v alone", nm.Claims, ReadingVerbs)
|
||||
}
|
||||
if !slices.Equal(nm.Consumes, []string{"mesh-delivery-indexer.manifest-accepted"}) {
|
||||
t.Errorf("consumes %v: the indexer's manifest-accepted alone (ADR 0595 §4)", nm.Consumes)
|
||||
}
|
||||
for _, want := range []string{"mesh-delivery-indexer.indexer_bus_state", "seat:mesh-hand-acts.hand-act"} {
|
||||
if !slices.Contains(nm.Invokes, want) {
|
||||
t.Errorf("invokes %v lack %s", nm.Invokes, want)
|
||||
}
|
||||
}
|
||||
if !slices.Contains(nm.Uses, "operator-channel") {
|
||||
t.Errorf("uses %v: the operator channel, for the warrant of recreate and drop", nm.Uses)
|
||||
}
|
||||
if len(nm.Streams) != 1 || nm.Streams[0].Name != "broker-events" || !slices.Equal(nm.Streams[0].Events, Events) ||
|
||||
nm.Streams[0].MaxAgeDays != 30 || nm.Streams[0].MaxMiB != 256 {
|
||||
t.Errorf("streams are %+v: broker-events carrying %v, 30 days, 256 MiB", nm.Streams, Events)
|
||||
}
|
||||
for _, e := range Events {
|
||||
if slices.Contains(m.Emits, e) {
|
||||
t.Errorf("emits lists %s, which its stream carries: an event is named in one place (ADR 0363)", e)
|
||||
}
|
||||
}
|
||||
var states []string
|
||||
for _, s := range nm.State {
|
||||
states = append(states, s.Name)
|
||||
}
|
||||
if !slices.Equal(states, []string{"asked", "requests"}) {
|
||||
t.Errorf("state is %v: asked and requests, old sections (ADR 0595 §10)", states)
|
||||
}
|
||||
if _, ok := nm.OwnSecrets["broker-keeper"]; !ok {
|
||||
t.Error("own-secrets lack broker-keeper, the keeper's own account (ADR 0436 §1)")
|
||||
}
|
||||
keeper := byID["keeper"]
|
||||
bus, _ := keeper["bus"].(map[string]any)
|
||||
health, _ := keeper["health"].(map[string]any)
|
||||
if keeper["type"] != "process" || keeper["artifact"] != "tools" || fmt.Sprint(keeper["run"]) != "[./nats-tools keep]" ||
|
||||
fmt.Sprint(bus["state"]) != "[asked requests]" ||
|
||||
health["kind"] != "tool" || health["tool"] != "nats_keeper_health" {
|
||||
t.Errorf("the keeper is %v: a process of the tools bundle, run as keep, keeping asked and requests, judged by nats_keeper_health", keeper)
|
||||
}
|
||||
if h, _ := server["health"].(map[string]any); h["kind"] != "tcp" || h["endpoint"] != "bus" {
|
||||
t.Errorf("the server's health is %v: tcp on bus, the check the keeper's tool check stands beside", server["health"])
|
||||
}
|
||||
args, _ := server["args"].([]any)
|
||||
if len(args) != 2 || args[0] != "sh" || args[1] != "/opt/mesh-entrypoint/entrypoint.sh" {
|
||||
t.Errorf("args are %v: the entrypoint run through sh, so no execute bit is relied on", args)
|
||||
|
||||
+105
-6
@@ -24,14 +24,24 @@
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-broker",
|
||||
"scope": "mesh"
|
||||
"scope": "mesh",
|
||||
"serves": [
|
||||
"list",
|
||||
"show",
|
||||
"check",
|
||||
"orphans"
|
||||
]
|
||||
}
|
||||
],
|
||||
"bus-users": "/var/lib/nats-module/conf/accounts.conf",
|
||||
"core-credentials": true,
|
||||
"own-secrets": {
|
||||
"broker": "${dir:mesh-state}/broker",
|
||||
"broker-nats-tools": "${dir:tools-secret}/broker-nats-tools"
|
||||
"broker-nats-tools": "${dir:tools-secret}/broker-nats-tools",
|
||||
"broker-keeper": {
|
||||
"path": "${dir:keeper-state}/broker-keeper",
|
||||
"owner": "nats-keeper"
|
||||
}
|
||||
},
|
||||
"capabilities": [
|
||||
"container-runtime"
|
||||
@@ -43,16 +53,51 @@
|
||||
"bucket-expiry-set"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-hand-acts.hand-act"
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"mesh-delivery-indexer.indexer_bus_state"
|
||||
],
|
||||
"consumes": [
|
||||
"mesh-delivery-indexer.manifest-accepted"
|
||||
],
|
||||
"uses": [
|
||||
"operator-channel"
|
||||
],
|
||||
"streams": [
|
||||
{
|
||||
"name": "broker-events",
|
||||
"events": [
|
||||
"created",
|
||||
"refused",
|
||||
"drifted",
|
||||
"drift-cleared",
|
||||
"full",
|
||||
"full-cleared",
|
||||
"orphaned",
|
||||
"recreated",
|
||||
"dropped"
|
||||
],
|
||||
"max-age-days": 30,
|
||||
"max-mib": 256
|
||||
}
|
||||
],
|
||||
"state": [
|
||||
{
|
||||
"name": "asked",
|
||||
"history": 5
|
||||
},
|
||||
{
|
||||
"name": "requests",
|
||||
"history": 5,
|
||||
"ttl-seconds": 86400
|
||||
}
|
||||
],
|
||||
"consumes": [],
|
||||
"listens": [
|
||||
{
|
||||
"name": "bus",
|
||||
"port": 4222,
|
||||
"protocol": "tcp",
|
||||
"from": "mesh",
|
||||
"why": "the mesh bus — every link the mesh has, over TLS, reached across the overlay"
|
||||
"why": "the mesh bus \u2014 every link the mesh has, over TLS, reached across the overlay"
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
@@ -96,6 +141,13 @@
|
||||
]
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"id": "keeper-account",
|
||||
"type": "user",
|
||||
"name": "nats-keeper",
|
||||
"shell": "/usr/bin/nologin",
|
||||
"home": "/var/lib/nats-keeper"
|
||||
},
|
||||
{
|
||||
"id": "jetstream-data",
|
||||
"type": "directory",
|
||||
@@ -117,6 +169,14 @@
|
||||
"mode": "0711",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "keeper-state",
|
||||
"type": "directory",
|
||||
"path": "/var/lib/nats-keeper",
|
||||
"mode": "0700",
|
||||
"owner": "nats-keeper",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "snapshots",
|
||||
"type": "directory",
|
||||
@@ -158,6 +218,41 @@
|
||||
"artifact": "entrypoint",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "keeper",
|
||||
"type": "process",
|
||||
"name": "nats-keeper",
|
||||
"artifact": "tools",
|
||||
"run": [
|
||||
"./nats-tools",
|
||||
"keep"
|
||||
],
|
||||
"user": "nats-keeper",
|
||||
"env": {
|
||||
"MESH_BROKER_FILE": "${dir:keeper-state}/broker-keeper",
|
||||
"MESH_NATS_FULL_RAISE": "75",
|
||||
"MESH_NATS_FULL_CLEAR": "70"
|
||||
},
|
||||
"bus": {
|
||||
"state": [
|
||||
"asked",
|
||||
"requests"
|
||||
],
|
||||
"asks": true,
|
||||
"invokes": [
|
||||
"mesh-delivery-indexer.indexer_bus_state",
|
||||
"seat:mesh-hand-acts.hand-act"
|
||||
]
|
||||
},
|
||||
"health": {
|
||||
"kind": "tool",
|
||||
"tool": "nats_keeper_health",
|
||||
"interval": "60s",
|
||||
"timeout": "10s",
|
||||
"looks": 2,
|
||||
"grace": "180s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server",
|
||||
"type": "container",
|
||||
@@ -181,7 +276,11 @@
|
||||
"restart-on": [
|
||||
"program-snapshot",
|
||||
"program-entrypoint"
|
||||
]
|
||||
],
|
||||
"health": {
|
||||
"kind": "tcp",
|
||||
"endpoint": "bus"
|
||||
}
|
||||
}
|
||||
],
|
||||
"accesses": [
|
||||
|
||||
Reference in New Issue
Block a user