The seats are called mesh-module-assigner and mesh-node-enroller in mesh-cli, claude-code, the checks, mesh-config, mesh-vault, conditions, self-check and the provisioner client (ADR 0634 §9; K-21; issue 1966)
This commit is contained in:
@@ -111,17 +111,17 @@ var commands = []command{
|
||||
// What runs where.
|
||||
{words: []string{"status"}, does: "what is wrong, what is quiet, what is moving (the delivery view)",
|
||||
build: fixed("mesh-delivery-view.view_status")},
|
||||
{words: []string{"nodes"}, does: "the nodes placement holds", build: fixed("mesh-placement.placement"),
|
||||
{words: []string{"nodes"}, does: "the nodes placement holds", build: fixed("mesh-module-assigner.placement"),
|
||||
render: renderNodes},
|
||||
{words: []string{"node", "list"}, does: "the nodes placement holds", build: fixed("mesh-placement.placement"),
|
||||
{words: []string{"node", "list"}, does: "the nodes placement holds", build: fixed("mesh-module-assigner.placement"),
|
||||
render: renderNodes},
|
||||
{words: []string{"node", "show"}, usage: "<node>", does: "one node's placement: what it runs and its decided fields",
|
||||
build: nodeArg("mesh-placement.placement")},
|
||||
build: nodeArg("mesh-module-assigner.placement")},
|
||||
{words: []string{"node", "public-domain"}, usage: "<node> [<domain> | --clear] [--why <text>]",
|
||||
does: "the domain a node composes its routed names under; with a domain or --clear, proposed to placement",
|
||||
allowed: []string{"clear", "why"}, build: publicDomain},
|
||||
{words: []string{"node", "add"}, instead: "a new machine joins through the seat mesh-enrolment: nox enrol issue <node> --why <text>"},
|
||||
{words: []string{"node", "networks"}, instead: "no seat keeps a node's routed networks yet; mesh-placement.placement shows what a node decides"},
|
||||
{words: []string{"node", "add"}, instead: "a new machine joins through the seat mesh-node-enroller: nox enrol issue <node> --why <text>"},
|
||||
{words: []string{"node", "networks"}, instead: "no seat keeps a node's routed networks yet; mesh-module-assigner.placement shows what a node decides"},
|
||||
{words: []string{"plan"}, usage: "<node>", does: "what the assigner wants the node to run", build: optNode("mesh-delivery-view.assigner_wants")},
|
||||
{words: []string{"haves"}, usage: "[<node>]", does: "what each node runs, as its node-engine said", build: optNode("mesh-delivery-view.node_haves")},
|
||||
{words: []string{"switch"}, does: "what each node runs, as its node-engine said", build: fixed("mesh-delivery-view.node_haves")},
|
||||
@@ -133,9 +133,9 @@ var commands = []command{
|
||||
return call{l.pos[0] + "/node-engine.composition", map[string]any{"module": l.pos[1]}}, nil
|
||||
}},
|
||||
{words: []string{"seats"}, does: "who holds each seat, and where", build: func(line) (call, error) {
|
||||
return call{"mesh-placement.placement", map[string]any{"seats": "true"}}, nil
|
||||
return call{"mesh-module-assigner.placement", map[string]any{"seats": "true"}}, nil
|
||||
}},
|
||||
{words: []string{"seat"}, instead: "a seat is held by placing its module: nox assign <node> <module> --why <text> (mesh-placement.propose)"},
|
||||
{words: []string{"seat"}, instead: "a seat is held by placing its module: nox assign <node> <module> --why <text> (mesh-module-assigner.propose)"},
|
||||
{words: []string{"assign"}, usage: "<node> <module>... --why <text>", does: "propose placing modules on a node",
|
||||
allowed: []string{"why"}, build: placeModules("place")},
|
||||
{words: []string{"unassign"}, usage: "<node> <module>... --why <text>", does: "propose taking modules off a node",
|
||||
@@ -155,9 +155,9 @@ var commands = []command{
|
||||
}
|
||||
return propose(l, map[string]any{"op": "unpin", "node": l.pos[0], "provision": l.pos[1]})
|
||||
}},
|
||||
{words: []string{"proposals"}, usage: "[<id>]", does: "the open proposals of placement", build: optArg("mesh-placement.proposals", "id")},
|
||||
{words: []string{"overlay", "show"}, does: "every node's placement, with its tunnel", build: fixed("mesh-placement.placement")},
|
||||
{words: []string{"overlay"}, instead: "a node's tunnel is a decided field of its placement: mesh-placement.propose with op decide"},
|
||||
{words: []string{"proposals"}, usage: "[<id>]", does: "the open proposals of placement", build: optArg("mesh-module-assigner.proposals", "id")},
|
||||
{words: []string{"overlay", "show"}, does: "every node's placement, with its tunnel", build: fixed("mesh-module-assigner.placement")},
|
||||
{words: []string{"overlay"}, instead: "a node's tunnel is a decided field of its placement: mesh-module-assigner.propose with op decide"},
|
||||
|
||||
// Deliveries and builds.
|
||||
{words: []string{"deliveries"}, usage: "[--state s] [--repository owner/repo] [--group g] [--all]",
|
||||
@@ -458,7 +458,7 @@ var commands = []command{
|
||||
return call{"knowledge-base.progress", a}, nil
|
||||
}},
|
||||
|
||||
// Enrolment (the seat mesh-enrolment; `enrol open` is local, in main.go).
|
||||
// Enrolment (the seat mesh-node-enroller; `enrol open` is local, in main.go).
|
||||
{words: []string{"enrol", "issue"}, usage: "<node> --why <text> [--expires 1h]", does: "a one-time token for a new machine, on the operator's Approve",
|
||||
allowed: []string{"why", "expires"}, build: enrolIssue},
|
||||
{words: []string{"token", "issue"}, usage: "--new <node> --why <text>", does: "the same as nox enrol issue",
|
||||
@@ -472,15 +472,15 @@ var commands = []command{
|
||||
}
|
||||
return enrolIssue(l)
|
||||
}},
|
||||
{words: []string{"enrol", "tokens"}, usage: "[<node>]", does: "every open enrolment, or one", build: optArg("mesh-enrolment.tokens", "node")},
|
||||
{words: []string{"enrol", "tokens"}, usage: "[<node>]", does: "every open enrolment, or one", build: optArg("mesh-node-enroller.tokens", "node")},
|
||||
{words: []string{"enrol", "revoke"}, usage: "<node> --why <text>", does: "end an enrolment at any stage", allowed: []string{"why"},
|
||||
build: func(l line) (call, error) {
|
||||
if len(l.pos) != 1 || !l.has("why") {
|
||||
return call{}, usageErr("give the node and --why")
|
||||
}
|
||||
return call{"mesh-enrolment.revoke", map[string]any{"node": l.pos[0], "why": l.flags["why"]}}, nil
|
||||
return call{"mesh-node-enroller.revoke", map[string]any{"node": l.pos[0], "why": l.flags["why"]}}, nil
|
||||
}},
|
||||
{words: []string{"enrol", "again"}, usage: "<node>", does: "raise an enrolment's ask again", build: needArg("mesh-enrolment.again", "node")},
|
||||
{words: []string{"enrol", "again"}, usage: "<node>", does: "raise an enrolment's ask again", build: needArg("mesh-node-enroller.again", "node")},
|
||||
|
||||
// Any address.
|
||||
{words: []string{"call"}, usage: "<address> [<json arguments>]", does: "call any seat verb or module tool, e.g. ace/node-service-manager.status",
|
||||
@@ -630,7 +630,7 @@ func propose(l line, changes ...map[string]any) (call, error) {
|
||||
for i, c := range changes {
|
||||
list[i] = c
|
||||
}
|
||||
return call{"mesh-placement.propose", map[string]any{"why": l.flags["why"], "changes": list}}, nil
|
||||
return call{"mesh-module-assigner.propose", map[string]any{"why": l.flags["why"], "changes": list}}, nil
|
||||
}
|
||||
|
||||
func placeModules(op string) func(line) (call, error) {
|
||||
@@ -649,7 +649,7 @@ func placeModules(op string) func(line) (call, error) {
|
||||
func publicDomain(l line) (call, error) {
|
||||
switch {
|
||||
case len(l.pos) == 1 && !l.has("clear"):
|
||||
return call{"mesh-placement.placement", map[string]any{"node": l.pos[0]}}, nil
|
||||
return call{"mesh-module-assigner.placement", map[string]any{"node": l.pos[0]}}, nil
|
||||
case len(l.pos) == 1:
|
||||
return propose(l, map[string]any{"op": "decide", "node": l.pos[0], "field": "public-domain", "value": nil})
|
||||
case len(l.pos) == 2 && !l.has("clear"):
|
||||
@@ -705,7 +705,7 @@ func enrolIssue(l line) (call, error) {
|
||||
}
|
||||
a := pick(l, "why", "expires")
|
||||
a["node"] = l.pos[0]
|
||||
return call{"mesh-enrolment.issue", a}, nil
|
||||
return call{"mesh-node-enroller.issue", a}, nil
|
||||
}
|
||||
|
||||
func addressCall(address string, rest []string) (call, error) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
// `nox enrol open`: the operator opens an enrolment token at their own terminal (novox/hq ADR 0587 §6, §8).
|
||||
//
|
||||
// The seat mesh-enrolment's `tokens` answers the token sealed to the operator key, which only the operator's private key
|
||||
// The seat mesh-node-enroller's `tokens` answers the token sealed to the operator key, which only the operator's private key
|
||||
// opens; the mesh never holds it. This subcommand is local: it asks nothing of the node-engine's socket and nothing of
|
||||
// the controller or the bus. It reads the sealed token (the base64 of the sealed box) on standard input and the private
|
||||
// key from a file (`--key`, the raw X25519 key in base64 that `operator key make` wrote), opens the box, and prints the
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
const enrolUsage = `nox enrol open --key <operator private key file>
|
||||
|
||||
Opens an enrolment token sealed to the operator key (the answer of the seat mesh-enrolment's tokens) and prints the token
|
||||
Opens an enrolment token sealed to the operator key (the answer of the seat mesh-node-enroller's tokens) and prints the token
|
||||
to type on the new machine. The sealed token is read on standard input; this runs here and asks nothing of the mesh.
|
||||
`
|
||||
|
||||
|
||||
@@ -87,17 +87,17 @@ func TestEachLineCallsItsOwner(t *testing.T) {
|
||||
address string
|
||||
args string
|
||||
}{
|
||||
{"node show ace", "mesh-placement.placement", `{"node":"ace"}`},
|
||||
{"node public-domain ace", "mesh-placement.placement", `{"node":"ace"}`},
|
||||
{"node public-domain ace example.org --why moved", "mesh-placement.propose", `{"changes":[{"field":"public-domain","node":"ace","op":"decide","value":"example.org"}],"why":"moved"}`},
|
||||
{"node show ace", "mesh-module-assigner.placement", `{"node":"ace"}`},
|
||||
{"node public-domain ace", "mesh-module-assigner.placement", `{"node":"ace"}`},
|
||||
{"node public-domain ace example.org --why moved", "mesh-module-assigner.propose", `{"changes":[{"field":"public-domain","node":"ace","op":"decide","value":"example.org"}],"why":"moved"}`},
|
||||
{"plan ace", "mesh-delivery-view.assigner_wants", `{"node":"ace"}`},
|
||||
{"haves", "mesh-delivery-view.node_haves", `{}`},
|
||||
{"composition ace plex", "ace/node-engine.composition", `{"module":"plex"}`},
|
||||
{"seats", "mesh-placement.placement", `{"seats":"true"}`},
|
||||
{"assign ace plex sonarr --why=media", "mesh-placement.propose", `{"changes":[{"module":"plex","node":"ace","op":"place"},{"module":"sonarr","node":"ace","op":"place"}],"why":"media"}`},
|
||||
{"unassign ace plex --why gone", "mesh-placement.propose", `{"changes":[{"module":"plex","node":"ace","op":"take-off"}],"why":"gone"}`},
|
||||
{"pin ace postgres-database novox postgres --why one", "mesh-placement.propose", `{"changes":[{"node":"ace","op":"pin","provider":{"module":"postgres","node":"novox"},"provision":"postgres-database"}],"why":"one"}`},
|
||||
{"unpin ace postgres-database --why back", "mesh-placement.propose", `{"changes":[{"node":"ace","op":"unpin","provision":"postgres-database"}],"why":"back"}`},
|
||||
{"seats", "mesh-module-assigner.placement", `{"seats":"true"}`},
|
||||
{"assign ace plex sonarr --why=media", "mesh-module-assigner.propose", `{"changes":[{"module":"plex","node":"ace","op":"place"},{"module":"sonarr","node":"ace","op":"place"}],"why":"media"}`},
|
||||
{"unassign ace plex --why gone", "mesh-module-assigner.propose", `{"changes":[{"module":"plex","node":"ace","op":"take-off"}],"why":"gone"}`},
|
||||
{"pin ace postgres-database novox postgres --why one", "mesh-module-assigner.propose", `{"changes":[{"node":"ace","op":"pin","provider":{"module":"postgres","node":"novox"},"provision":"postgres-database"}],"why":"one"}`},
|
||||
{"unpin ace postgres-database --why back", "mesh-module-assigner.propose", `{"changes":[{"node":"ace","op":"unpin","provision":"postgres-database"}],"why":"back"}`},
|
||||
{"deliveries --state merged --json", "mesh-delivery.deliveries", `{"state":"merged"}`},
|
||||
{"delivery novox/mesh-sdk@dff0ce2abb21", "mesh-delivery.show", `{"id":"novox/mesh-sdk@dff0ce2abb21"}`},
|
||||
{"checks novox/mesh-catalog --number 591", "mesh-delivery.checks", `{"number":"591","repository":"novox/mesh-catalog"}`},
|
||||
@@ -132,9 +132,9 @@ func TestEachLineCallsItsOwner(t *testing.T) {
|
||||
{"kb ask what holds about the merge window", "knowledge-base.ask", `{"question":"what holds about the merge window"}`},
|
||||
{"kb get 587 --reasoning", "knowledge-base.get", `{"number":587,"reasoning":true}`},
|
||||
{"progress 47", "knowledge-base.progress", `{"of":"design 47"}`},
|
||||
{"enrol issue new1 --why laptop --expires 2h", "mesh-enrolment.issue", `{"expires":"2h","node":"new1","why":"laptop"}`},
|
||||
{"token issue --new new1 --why laptop", "mesh-enrolment.issue", `{"node":"new1","why":"laptop"}`},
|
||||
{"enrol tokens", "mesh-enrolment.tokens", `{}`},
|
||||
{"enrol issue new1 --why laptop --expires 2h", "mesh-node-enroller.issue", `{"expires":"2h","node":"new1","why":"laptop"}`},
|
||||
{"token issue --new new1 --why laptop", "mesh-node-enroller.issue", `{"node":"new1","why":"laptop"}`},
|
||||
{"enrol tokens", "mesh-node-enroller.tokens", `{}`},
|
||||
{"call ace/node-service-manager.status {\"unit\":\"plex\"}", "ace/node-service-manager.status", `{"unit":"plex"}`},
|
||||
{"ask mesh-catalog catalog_modules", "mesh-catalog.catalog_modules", `{}`},
|
||||
} {
|
||||
@@ -190,13 +190,13 @@ func TestALineWithNoOwnerOrNotReadCallsNothingAndSaysWhy(t *testing.T) {
|
||||
// What the console says is printed as said: an answer it marks an error on standard error with exit 1, a console that
|
||||
// does not answer as nothing called, a verb's process refused before anything is called; nodes are one line each.
|
||||
func TestAnswersRefusalsAndSilenceAreSaid(t *testing.T) {
|
||||
got := console(t, map[string]string{"mesh-enrolment.tokens": "!nothing serves seat:mesh-enrolment.tokens"})
|
||||
got := console(t, map[string]string{"mesh-node-enroller.tokens": "!nothing serves seat:mesh-node-enroller.tokens"})
|
||||
if code, out, errOut := runLine("enrol", "tokens"); code != 1 || out != "" || !strings.Contains(errOut, "nothing serves") {
|
||||
t.Errorf("an error answer: exit %d, stdout %q, stderr %q", code, out, errOut)
|
||||
}
|
||||
placement := `{"keys":{"novox":{"placement":{"decided":{"address":"10.10.0.1","site":"hub"},"modules":[{},{}]}},` +
|
||||
`"ace":{"placement":{"decided":{"address":"10.10.0.2"},"modules":[{}]}}}}`
|
||||
console(t, map[string]string{"mesh-placement.placement": placement})
|
||||
console(t, map[string]string{"mesh-module-assigner.placement": placement})
|
||||
if code, out, _ := runLine("nodes"); code != 0 || !strings.HasPrefix(out, "ace ") ||
|
||||
!strings.Contains(out, "10.10.0.1") || !strings.Contains(out, "2 modules") || !strings.HasSuffix(out, "answered by ace\n") {
|
||||
t.Errorf("nodes: exit %d, %q", code, out)
|
||||
|
||||
Reference in New Issue
Block a user