Rename mesh-control -> mesh-controller, substrate -> foundation
One name per thing, per the HQ glossary: the module/container/image/binary/repo becomes mesh-controller, the seat the-controller, and the store+broker pair the foundation (embedded base bundles, default template and example lock renamed with their go:embed directives). No behaviour change — a pure vocabulary rename. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
+3
-3
@@ -22,13 +22,13 @@ COPY . .
|
|||||||
ARG VERSION=development
|
ARG VERSION=development
|
||||||
RUN CGO_ENABLED=0 go build -trimpath \
|
RUN CGO_ENABLED=0 go build -trimpath \
|
||||||
-ldflags "-s -w -X main.version=${VERSION}" \
|
-ldflags "-s -w -X main.version=${VERSION}" \
|
||||||
-o /mesh-control ./cmd/mesh-control
|
-o /mesh-controller ./cmd/mesh-controller
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=build /mesh-control /mesh-control
|
COPY --from=build /mesh-controller /mesh-controller
|
||||||
|
|
||||||
# Numeric because there is no /etc/passwd to look a name up in. Nothing here needs to be root:
|
# Numeric because there is no /etc/passwd to look a name up in. Nothing here needs to be root:
|
||||||
# it opens outbound connections and writes nothing to its own filesystem.
|
# it opens outbound connections and writes nothing to its own filesystem.
|
||||||
USER 65534:65534
|
USER 65534:65534
|
||||||
|
|
||||||
ENTRYPOINT ["/mesh-control"]
|
ENTRYPOINT ["/mesh-controller"]
|
||||||
|
|||||||
@@ -12,20 +12,20 @@ LDFLAGS := -s -w -X main.version=$(VERSION)
|
|||||||
# touches a database anybody else is using. Override PG_PORT if this one is taken -- the first
|
# touches a database anybody else is using. Override PG_PORT if this one is taken -- the first
|
||||||
# port chosen was already serving something that had been up for six days.
|
# port chosen was already serving something that had been up for six days.
|
||||||
PG_PORT ?= 55532
|
PG_PORT ?= 55532
|
||||||
PG_CONTAINER ?= mesh-control-check
|
PG_CONTAINER ?= mesh-controller-check
|
||||||
PG_IMAGE ?= postgres:17-alpine
|
PG_IMAGE ?= postgres:17-alpine
|
||||||
export MESH_TEST_POSTGRES ?= postgres://postgres:check@127.0.0.1:$(PG_PORT)/postgres?sslmode=disable
|
export MESH_TEST_POSTGRES ?= postgres://postgres:check@127.0.0.1:$(PG_PORT)/postgres?sslmode=disable
|
||||||
|
|
||||||
.PHONY: build image check test vet fmt postgres postgres-stop clean
|
.PHONY: build image check test vet fmt postgres postgres-stop clean
|
||||||
|
|
||||||
build:
|
build:
|
||||||
CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o build/mesh-control ./cmd/mesh-control
|
CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o build/mesh-controller ./cmd/mesh-controller
|
||||||
|
|
||||||
# Tagged 'development' as well as by version, because the lab places images by name and a
|
# Tagged 'development' as well as by version, because the lab places images by name and a
|
||||||
# scenario naming a version would have to be edited on every build. The version tag is what a
|
# scenario naming a version would have to be edited on every build. The version tag is what a
|
||||||
# real bundle pins.
|
# real bundle pins.
|
||||||
IMAGE ?= mesh-control:$(VERSION)
|
IMAGE ?= mesh-controller:$(VERSION)
|
||||||
DEV_TAG ?= mesh-control:development
|
DEV_TAG ?= mesh-controller:development
|
||||||
|
|
||||||
image:
|
image:
|
||||||
docker build --build-arg VERSION=$(VERSION) -t $(IMAGE) -t $(DEV_TAG) .
|
docker build --build-arg VERSION=$(VERSION) -t $(IMAGE) -t $(DEV_TAG) .
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# mesh-control
|
# mesh-controller
|
||||||
|
|
||||||
**Tier 2 of Novox Mesh — the control plane.** Everything that needs to know about more than one
|
**Tier 2 of Novox Mesh — the control plane.** Everything that needs to know about more than one
|
||||||
node.
|
node.
|
||||||
@@ -31,17 +31,17 @@ argument that is not settled there.
|
|||||||
| the interface every surface speaks to | not built; its shape is not decided |
|
| the interface every surface speaks to | not built; its shape is not decided |
|
||||||
|
|
||||||
```
|
```
|
||||||
mesh-control migrate bring each context's schema up to date
|
mesh-controller migrate bring each context's schema up to date
|
||||||
mesh-control node add <name> create a node record
|
mesh-controller node add <name> create a node record
|
||||||
mesh-control node list the nodes this mesh knows about
|
mesh-controller node list the nodes this mesh knows about
|
||||||
mesh-control token issue --node <name> a one-time right to join, for an existing record
|
mesh-controller token issue --node <name> a one-time right to join, for an existing record
|
||||||
mesh-control token issue --new <name> create the record and issue for it
|
mesh-controller token issue --new <name> create the record and issue for it
|
||||||
mesh-control identity show this control plane's signing key
|
mesh-controller identity show this control plane's signing key
|
||||||
mesh-control broker show where the broker is, and what to expect there
|
mesh-controller broker show where the broker is, and what to expect there
|
||||||
mesh-control version what this binary is
|
mesh-controller version what this binary is
|
||||||
```
|
```
|
||||||
|
|
||||||
`migrate` is **step 3 of the substrate bootstrap** — the step the first node cannot get past, run
|
`migrate` is **step 3 of the foundation bootstrap** — the step the first node cannot get past, run
|
||||||
against a database raised moments earlier from the bundle the host carries.
|
against a database raised moments earlier from the bundle the host carries.
|
||||||
|
|
||||||
### Tokens, and what they are missing
|
### Tokens, and what they are missing
|
||||||
@@ -176,7 +176,7 @@ without its neighbour checked out is a repository nobody can build.
|
|||||||
**What this mesh sends, read by the host that receives it:**
|
**What this mesh sends, read by the host that receives it:**
|
||||||
|
|
||||||
```
|
```
|
||||||
mesh-control: ./build/mesh-control plan <node> --json > /tmp/d.json
|
mesh-controller: ./build/mesh-controller plan <node> --json > /tmp/d.json
|
||||||
mesh-host: MESH_EMITTED=/tmp/d.json go test ./internal/declaration/ -v
|
mesh-host: MESH_EMITTED=/tmp/d.json go test ./internal/declaration/ -v
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ mesh-host: MESH_EMITTED=/tmp/d.json go test ./internal/declaration/ -v
|
|||||||
|
|
||||||
```
|
```
|
||||||
mesh-host: MESH_ENROL_OUT=/tmp/enrol.json go test ./internal/link/
|
mesh-host: MESH_ENROL_OUT=/tmp/enrol.json go test ./internal/link/
|
||||||
mesh-control: MESH_ENROL=/tmp/enrol.json make check
|
mesh-controller: MESH_ENROL=/tmp/enrol.json make check
|
||||||
```
|
```
|
||||||
|
|
||||||
The second does more than compare shapes: it seals something to the key that arrived and opens it
|
The second does more than compare shapes: it seals something to the key that arrived and opens it
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ import (
|
|||||||
|
|
||||||
amqp "github.com/rabbitmq/amqp091-go"
|
amqp "github.com/rabbitmq/amqp091-go"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/builder"
|
"github.com/novox/mesh-controller/internal/builder"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// version is set at build time.
|
// version is set at build time.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/builder"
|
"github.com/novox/mesh-controller/internal/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// buildOnce is the builder doing one build and stopping, with no broker and no mesh.
|
// buildOnce is the builder doing one build and stopping, with no broker and no mesh.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The things the mesh can be asked to do, separated from how it was asked.
|
// The things the mesh can be asked to do, separated from how it was asked.
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// What an assignment says about the machines it was not about.
|
// What an assignment says about the machines it was not about.
|
||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refused and failed stay distinct all the way to the page.
|
// Refused and failed stay distinct all the way to the page.
|
||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// asking a build machine for a module, and what came back.
|
// asking a build machine for a module, and what came back.
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
// Command mesh-control is the control plane: everything that needs to know about more than one
|
// Command mesh-controller is the control plane: everything that needs to know about more than one
|
||||||
// node (novox/hq ADR 0006).
|
// node (novox/hq ADR 0006).
|
||||||
//
|
//
|
||||||
// It runs as one process holding several contexts, each owning its own store. Today it holds one,
|
// It runs as one process holding several contexts, each owning its own store. Today it holds one,
|
||||||
// `inventory`, and does one thing with it — brings its schema up to date, which is step 3 of the
|
// `inventory`, and does one thing with it — brings its schema up to date, which is step 3 of the
|
||||||
// bootstrap in novox/hq 07-the-substrate and the step the first node cannot get past without.
|
// bootstrap in novox/hq 07-the-foundation and the step the first node cannot get past without.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -14,11 +14,11 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/identity"
|
"github.com/novox/mesh-controller/internal/identity"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/licences"
|
"github.com/novox/mesh-controller/internal/licences"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// version is stamped at link time. Unset in a development build, and it says so rather than
|
// version is stamped at link time. Unset in a development build, and it says so rather than
|
||||||
@@ -40,7 +40,7 @@ var held = []struct {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := run(); err != nil {
|
if err := run(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "mesh-control: %v\n", err)
|
fmt.Fprintf(os.Stderr, "mesh-controller: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ func run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprint(os.Stderr, `mesh-control — the control plane
|
fmt.Fprint(os.Stderr, `mesh-controller — the control plane
|
||||||
|
|
||||||
migrate bring each context's schema up to date
|
migrate bring each context's schema up to date
|
||||||
node add <name> create a node record
|
node add <name> create a node record
|
||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/licences"
|
"github.com/novox/mesh-controller/internal/licences"
|
||||||
"github.com/novox/mesh-control/internal/overlay"
|
"github.com/novox/mesh-controller/internal/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A mesh a command can be run against.
|
// A mesh a command can be run against.
|
||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/overlay"
|
"github.com/novox/mesh-controller/internal/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// the catalogue: what exists, what is assigned, and how it is configured.
|
// the catalogue: what exists, what is assigned, and how it is configured.
|
||||||
@@ -257,7 +257,7 @@ func moduleCommand(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// The substrate owns the bus; make sure it exists before a module binds onto it.
|
// The foundation owns the bus; make sure it exists before a module binds onto it.
|
||||||
if err := management.EnsureEventExchanges(ctx); err != nil {
|
if err := management.EnsureEventExchanges(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -271,7 +271,7 @@ func moduleCommand(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// A consumer's queue, with its dead-letter, is the substrate's to declare — its own account
|
// A consumer's queue, with its dead-letter, is the foundation's to declare — its own account
|
||||||
// may not (ADR 0043). Made now, so it exists before the module binds onto it.
|
// may not (ADR 0043). Made now, so it exists before the module binds onto it.
|
||||||
if len(m.Consumes) > 0 {
|
if len(m.Consumes) > 0 {
|
||||||
if err := management.EnsureModuleQueue(ctx, *forNode, module); err != nil {
|
if err := management.EnsureModuleQueue(ctx, *forNode, module); err != nil {
|
||||||
@@ -10,9 +10,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/overlay"
|
"github.com/novox/mesh-controller/internal/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// the private network: who is on it, where, and what they are called.
|
// the private network: who is on it, where, and what they are called.
|
||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// placementOf is what the mesh holds about where one node is.
|
// placementOf is what the mesh holds about where one node is.
|
||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
"github.com/novox/mesh-control/internal/token"
|
"github.com/novox/mesh-controller/internal/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// what a machine is, and what it is allowed to be told.
|
// what a machine is, and what it is allowed to be told.
|
||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/licences"
|
"github.com/novox/mesh-controller/internal/licences"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@@ -453,11 +453,11 @@ func declarationWith(ctx context.Context, open *stores, node string,
|
|||||||
// The ports the mesh itself needs open, which no module declares. Read from the broker this
|
// The ports the mesh itself needs open, which no module declares. Read from the broker this
|
||||||
// control plane was told about rather than written down twice: the address a node is handed in
|
// control plane was told about rather than written down twice: the address a node is handed in
|
||||||
// its token and the port its machine must accept on are the same fact.
|
// its token and the port its machine must accept on are the same fact.
|
||||||
var substrate []int
|
var foundation []int
|
||||||
if b, err := broker.FromEnvironment(); err == nil {
|
if b, err := broker.FromEnvironment(); err == nil {
|
||||||
if _, port, err := net.SplitHostPort(b.Address); err == nil {
|
if _, port, err := net.SplitHostPort(b.Address); err == nil {
|
||||||
if n, err := strconv.Atoi(port); err == nil {
|
if n, err := strconv.Atoi(port); err == nil {
|
||||||
substrate = append(substrate, n)
|
foundation = append(foundation, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,7 +465,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
|
|||||||
return plan.Declaration(catalogue.Rendering{
|
return plan.Declaration(catalogue.Rendering{
|
||||||
Settings: settings, Generators: gens, Grants: grants, Needed: needed, Ports: ports,
|
Settings: settings, Generators: gens, Grants: grants, Needed: needed, Ports: ports,
|
||||||
Certificate: certificate, Authority: authority, Mesh: private, Names: names,
|
Certificate: certificate, Authority: authority, Mesh: private, Names: names,
|
||||||
Substrate: substrate})
|
Foundation: foundation})
|
||||||
}
|
}
|
||||||
|
|
||||||
// routeNamesInTheMesh is every routed name and the address of the node that serves it (novox/hq
|
// routeNamesInTheMesh is every routed name and the address of the node that serves it (novox/hq
|
||||||
@@ -12,10 +12,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// reportUnhostable says which of a node's assigned modules the machine cannot run, once per push.
|
// reportUnhostable says which of a node's assigned modules the machine cannot run, once per push.
|
||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The shape something other than a person reads.
|
// The shape something other than a person reads.
|
||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/overlay"
|
"github.com/novox/mesh-controller/internal/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// is anything broken, is anything not answering, is anything out of date.
|
// is anything broken, is anything not answering, is anything out of date.
|
||||||
@@ -5,10 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/identity"
|
"github.com/novox/mesh-controller/internal/identity"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/licences"
|
"github.com/novox/mesh-controller/internal/licences"
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// reaching each context's store, which no other context may touch.
|
// reaching each context's store, which no other context may touch.
|
||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// following acts on what the catalogue announces.
|
// following acts on what the catalogue announces.
|
||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/overlay"
|
"github.com/novox/mesh-controller/internal/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The examples are manifests, so the thing to check is that the catalogue accepts them.
|
// The examples are manifests, so the thing to check is that the catalogue accepts them.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The password comes from a file, because that is how the mesh delivers one.
|
// The password comes from a file, because that is how the mesh delivers one.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module github.com/novox/mesh-control
|
module github.com/novox/mesh-controller
|
||||||
|
|
||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The names are written twice, so a test keeps them agreeing.
|
// The names are written twice, so a test keeps them agreeing.
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const ExchangeName = "mesh"
|
|||||||
const BuildQueueName = "builds"
|
const BuildQueueName = "builds"
|
||||||
|
|
||||||
// The events bus (novox/hq ADR 0042): one topic exchange every event rides, a second for tool
|
// The events bus (novox/hq ADR 0042): one topic exchange every event rides, a second for tool
|
||||||
// RPC kept apart, and a dead-letter home for a poison event. The substrate owns these — a module's
|
// RPC kept apart, and a dead-letter home for a poison event. The foundation owns these — a module's
|
||||||
// account cannot declare them, only bind its own queue to the events one.
|
// account cannot declare them, only bind its own queue to the events one.
|
||||||
const (
|
const (
|
||||||
EventsExchangeName = "mesh.events"
|
EventsExchangeName = "mesh.events"
|
||||||
@@ -151,7 +151,7 @@ func (m *Management) CreateModuleAccount(ctx context.Context, node, module, pass
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnsureModuleQueue declares a consuming module's queue with its dead-letter exchange, idempotently.
|
// EnsureModuleQueue declares a consuming module's queue with its dead-letter exchange, idempotently.
|
||||||
// The substrate declares it because a scoped module account may not: the broker refuses a queue with
|
// The foundation declares it because a scoped module account may not: the broker refuses a queue with
|
||||||
// a dead-letter exchange to a non-administrator (novox/hq ADR 0043), so a consumer passively checks
|
// a dead-letter exchange to a non-administrator (novox/hq ADR 0043), so a consumer passively checks
|
||||||
// the queue the mesh made rather than declaring its own.
|
// the queue the mesh made rather than declaring its own.
|
||||||
func (m *Management) EnsureModuleQueue(ctx context.Context, node, module string) error {
|
func (m *Management) EnsureModuleQueue(ctx context.Context, node, module string) error {
|
||||||
@@ -166,7 +166,7 @@ func (m *Management) EnsureModuleQueue(ctx context.Context, node, module string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnsureEventExchanges declares the bus's exchanges and the dead-letter home, idempotently. The
|
// EnsureEventExchanges declares the bus's exchanges and the dead-letter home, idempotently. The
|
||||||
// substrate owns them (a module's account may not declare an exchange), and a dead-letter exchange
|
// foundation owns them (a module's account may not declare an exchange), and a dead-letter exchange
|
||||||
// with no queue behind it drops what it receives — so a durable queue bound to `#` retains a poison
|
// with no queue behind it drops what it receives — so a durable queue bound to `#` retains a poison
|
||||||
// event for inspection, which is the whole reason the trail exists.
|
// event for inspection, which is the whole reason the trail exists.
|
||||||
func (m *Management) EnsureEventExchanges(ctx context.Context) error {
|
func (m *Management) EnsureEventExchanges(ctx context.Context) error {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The audit logger consumes everything and emits nothing. Its account must let it declare and read
|
// The audit logger consumes everything and emits nothing. Its account must let it declare and read
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Turning a repository into artifacts the mesh can pin.
|
// Turning a repository into artifacts the mesh can pin.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A repository becoming artifacts the mesh can pin.
|
// A repository becoming artifacts the mesh can pin.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A module naming a base the mesh has not built is refused, and the refusal names what is missing.
|
// A module naming a base the mesh has not built is refused, and the refusal names what is missing.
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func TestAModuleThatDoesNotProvideTheStoreStillBuilds(t *testing.T) {
|
|||||||
|
|
||||||
// A mapping that names an address still names the port, and the machine side is still the middle.
|
// A mapping that names an address still names the port, and the machine side is still the middle.
|
||||||
//
|
//
|
||||||
// The substrate bundle writes "127.0.0.1:5432:5432" today, so the shape is not hypothetical.
|
// The foundation bundle writes "127.0.0.1:5432:5432" today, so the shape is not hypothetical.
|
||||||
// Found in review: the first cut split on the first colon, read "127.0.0.1" as the machine port,
|
// Found in review: the first cut split on the first colon, read "127.0.0.1" as the machine port,
|
||||||
// failed to parse it, and silently skipped the mapping — which put the filter back on the
|
// failed to parse it, and silently skipped the mapping — which put the filter back on the
|
||||||
// declared port, the exact fault MachineSide was written to end.
|
// declared port, the exact fault MachineSide was written to end.
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func routeProxy() Manifest {
|
|||||||
// A co-located provider's served VALUES reach its consumer, not just its served keys.
|
// A co-located provider's served VALUES reach its consumer, not just its served keys.
|
||||||
//
|
//
|
||||||
// The mesh walks a provider on ANOTHER machine and settles what it serves with that node's settings
|
// The mesh walks a provider on ANOTHER machine and settles what it serves with that node's settings
|
||||||
// layers before offering it (cmd/mesh-control plan.go, theRestOfTheMesh). A provider on the
|
// layers before offering it (cmd/mesh-controller plan.go, theRestOfTheMesh). A provider on the
|
||||||
// consumer's own machine was never settled at all: resolve.go's servedHere and declaration.go's
|
// consumer's own machine was never settled at all: resolve.go's servedHere and declaration.go's
|
||||||
// here() both read the manifest and stop there. So a served value the operator supplied — the one
|
// here() both read the manifest and stop there. So a served value the operator supplied — the one
|
||||||
// kind of value a manifest cannot carry, because it is different on every mesh — arrived as the
|
// kind of value a manifest cannot carry, because it is different on every mesh — arrived as the
|
||||||
|
|||||||
@@ -89,11 +89,11 @@ type Rendering struct {
|
|||||||
// a fact about the mesh, and resolution answers questions about one machine.
|
// a fact about the mesh, and resolution answers questions about one machine.
|
||||||
Mesh []string
|
Mesh []string
|
||||||
|
|
||||||
// Substrate is the ports the mesh itself needs reachable on every machine, which no module
|
// Foundation is the ports the mesh itself needs reachable on every machine, which no module
|
||||||
// declares because the substrate is not a module (novox/hq 04-ISSUES/051 and 052). The broker
|
// declares because the foundation is not a module (novox/hq 04-ISSUES/051 and 052). The broker
|
||||||
// is the one that matters: a machine dials it to enrol, and a firewall derived only from
|
// is the one that matters: a machine dials it to enrol, and a firewall derived only from
|
||||||
// modules closes it.
|
// modules closes it.
|
||||||
Substrate []int
|
Foundation []int
|
||||||
|
|
||||||
// Names is every machine's internal name and its address, for containers to be given.
|
// Names is every machine's internal name and its address, for containers to be given.
|
||||||
//
|
//
|
||||||
@@ -213,7 +213,7 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
filtering := AsNftables(rules, with.Mesh, r.PublicDomain != "", with.Substrate)
|
filtering := AsNftables(rules, with.Mesh, r.PublicDomain != "", with.Foundation)
|
||||||
|
|
||||||
var out []map[string]any
|
var out []map[string]any
|
||||||
for _, m := range r.Modules {
|
for _, m := range r.Modules {
|
||||||
@@ -821,7 +821,7 @@ func here(r Resolution, requirement string, with Rendering) (*Needed, error) {
|
|||||||
//
|
//
|
||||||
// **The one derivation, so the two arrangements cannot disagree.** For a provider elsewhere the
|
// **The one derivation, so the two arrangements cannot disagree.** For a provider elsewhere the
|
||||||
// control plane walks that node, reads its manifest with that machine's port assignments, and
|
// control plane walks that node, reads its manifest with that machine's port assignments, and
|
||||||
// settles the result with that node's settings layers before offering it (cmd/mesh-control plan.go,
|
// settles the result with that node's settings layers before offering it (cmd/mesh-controller plan.go,
|
||||||
// theRestOfTheMesh). A provider on the consumer's own machine never passes through that walk, so
|
// theRestOfTheMesh). A provider on the consumer's own machine never passes through that walk, so
|
||||||
// every step of it has to be repeated here — and each step that was not repeated was a promise the
|
// every step of it has to be repeated here — and each step that was not repeated was a promise the
|
||||||
// co-located arrangement quietly broke: first the port (novox/hq 04-ISSUES/038), then the settled
|
// co-located arrangement quietly broke: first the port (novox/hq 04-ISSUES/038), then the settled
|
||||||
|
|||||||
@@ -217,10 +217,10 @@ const SSHPort = 22
|
|||||||
// `outward` says this machine is reachable from outside the mesh, which is the only thing that
|
// `outward` says this machine is reachable from outside the mesh, which is the only thing that
|
||||||
// decides whether ssh is answered there as well as on the private network.
|
// decides whether ssh is answered there as well as on the private network.
|
||||||
//
|
//
|
||||||
// `substrate` is the ports the MESH ITSELF needs reachable, which no module declares.
|
// `foundation` is the ports the MESH ITSELF needs reachable, which no module declares.
|
||||||
//
|
//
|
||||||
// **Everything else in this file is derived from what modules say they listen on, and the
|
// **Everything else in this file is derived from what modules say they listen on, and the
|
||||||
// substrate is not a module** (novox/hq 04-ISSUES/051). So the broker — the port every machine
|
// foundation is not a module** (novox/hq 04-ISSUES/051). So the broker — the port every machine
|
||||||
// dials to enrol and to receive every declaration it is ever sent — was absent from the ruleset,
|
// dials to enrol and to receive every declaration it is ever sent — was absent from the ruleset,
|
||||||
// and nothing noticed: a mesh of one never dials its own broker across the network. The first
|
// and nothing noticed: a mesh of one never dials its own broker across the network. The first
|
||||||
// machine to join a firewalled anchor is refused by the packet filter during enrolment, before
|
// machine to join a firewalled anchor is refused by the packet filter during enrolment, before
|
||||||
@@ -229,7 +229,7 @@ const SSHPort = 22
|
|||||||
// It is a floor for the same reason ssh is. A machine nobody can reach is a machine nobody can
|
// It is a floor for the same reason ssh is. A machine nobody can reach is a machine nobody can
|
||||||
// repair; a machine the mesh cannot reach is a machine the mesh cannot manage. Neither is a thing
|
// repair; a machine the mesh cannot reach is a machine the mesh cannot manage. Neither is a thing
|
||||||
// any module asks for, and neither may be derived away.
|
// any module asks for, and neither may be derived away.
|
||||||
func AsNftables(rules []Rule, mesh []string, outward bool, substrate []int) string {
|
func AsNftables(rules []Rule, mesh []string, outward bool, foundation []int) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
b.WriteString("# Computed by the mesh from what is assigned to this node.\n")
|
b.WriteString("# Computed by the mesh from what is assigned to this node.\n")
|
||||||
b.WriteString("# Edits are lost on the next declaration; change a module's listens instead.\n\n")
|
b.WriteString("# Edits are lost on the next declaration; change a module's listens instead.\n\n")
|
||||||
@@ -297,9 +297,9 @@ func AsNftables(rules []Rule, mesh []string, outward bool, substrate []int) stri
|
|||||||
// Not narrowed to the private network, because the machines that need this most are the ones
|
// Not narrowed to the private network, because the machines that need this most are the ones
|
||||||
// not on it yet: a node enrols BEFORE it has an address here, over the ordinary network, and a
|
// not on it yet: a node enrols BEFORE it has an address here, over the ordinary network, and a
|
||||||
// rule allowing only the private network would close the door being knocked on.
|
// rule allowing only the private network would close the door being knocked on.
|
||||||
if len(substrate) > 0 {
|
if len(foundation) > 0 {
|
||||||
b.WriteString("\n\t\t# the mesh's own — never derived, never closed\n")
|
b.WriteString("\n\t\t# the mesh's own — never derived, never closed\n")
|
||||||
for _, port := range substrate {
|
for _, port := range foundation {
|
||||||
b.WriteString(fmt.Sprintf("\t\ttcp dport %d accept\n", port))
|
b.WriteString(fmt.Sprintf("\t\ttcp dport %d accept\n", port))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
// The mesh's own ports survive a ruleset derived from modules that do not mention them.
|
// The mesh's own ports survive a ruleset derived from modules that do not mention them.
|
||||||
//
|
//
|
||||||
// **The firewall is computed from what modules declare they listen on, and the substrate is not a
|
// **The firewall is computed from what modules declare they listen on, and the foundation is not a
|
||||||
// module** (novox/hq 04-ISSUES/052). So the broker's port — the one every machine dials to enrol
|
// module** (novox/hq 04-ISSUES/052). So the broker's port — the one every machine dials to enrol
|
||||||
// and to receive every declaration it is ever sent — was absent from every ruleset the mesh ever
|
// and to receive every declaration it is ever sent — was absent from every ruleset the mesh ever
|
||||||
// generated, and nothing caught it: a mesh of one never dials its own broker across the network,
|
// generated, and nothing caught it: a mesh of one never dials its own broker across the network,
|
||||||
@@ -37,12 +37,12 @@ func TestTheBrokersPortIsOpenedThoughNoModuleDeclaresIt(t *testing.T) {
|
|||||||
|
|
||||||
// And a mesh that was never told about a broker still gets a ruleset, rather than an empty one or
|
// And a mesh that was never told about a broker still gets a ruleset, rather than an empty one or
|
||||||
// a panic. A control plane in that state cannot issue tokens either, which is where it surfaces.
|
// a panic. A control plane in that state cannot issue tokens either, which is where it surfaces.
|
||||||
func TestNoBrokerMeansNoSubstrateRuleRatherThanNoRuleset(t *testing.T) {
|
func TestNoBrokerMeansNoFoundationRuleRatherThanNoRuleset(t *testing.T) {
|
||||||
out := AsNftables(nil, []string{"10.42.0.1"}, false, nil)
|
out := AsNftables(nil, []string{"10.42.0.1"}, false, nil)
|
||||||
if !strings.Contains(out, "table inet mesh") {
|
if !strings.Contains(out, "table inet mesh") {
|
||||||
t.Fatalf("no ruleset at all:\n%s", out)
|
t.Fatalf("no ruleset at all:\n%s", out)
|
||||||
}
|
}
|
||||||
if strings.Contains(out, "never derived, never closed\n\t\ttcp dport") {
|
if strings.Contains(out, "never derived, never closed\n\t\ttcp dport") {
|
||||||
t.Fatalf("a substrate rule was written for a mesh with no broker:\n%s", out)
|
t.Fatalf("a foundation rule was written for a mesh with no broker:\n%s", out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -706,7 +706,7 @@ func ParseManifest(raw []byte) (Manifest, error) {
|
|||||||
// that provides the store and also builds something asks the mesh to put an artifact into the
|
// that provides the store and also builds something asks the mesh to put an artifact into the
|
||||||
// thing that artifact is needed to create.
|
// thing that artifact is needed to create.
|
||||||
//
|
//
|
||||||
// It is the question the substrate record asks of every candidate — can it grant itself the
|
// It is the question the foundation record asks of every candidate — can it grant itself the
|
||||||
// thing it provides? The store cannot create its own database, the broker cannot create its
|
// thing it provides? The store cannot create its own database, the broker cannot create its
|
||||||
// own virtual host, and a registry cannot grant itself a repository. Such a module names its
|
// own virtual host, and a registry cannot grant itself a repository. Such a module names its
|
||||||
// image, exactly as the bundle names the three a first node starts from.
|
// image, exactly as the bundle names the three a first node starts from.
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/overlay"
|
"github.com/novox/mesh-controller/internal/overlay"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The manifests the control plane actually ships, resolved.
|
// The manifests the control plane actually ships, resolved.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name is what this context is called: its database and its credential are named after it.
|
// Name is what this context is called: its database and its credential are named after it.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fresh(t *testing.T) *Identity {
|
func fresh(t *testing.T) *Identity {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package inventory
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The image every module is compiled on top of is built and never run.
|
// The image every module is compiled on top of is built and never run.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoSuchModule is what the mesh says about a module it has never been told about.
|
// ErrNoSuchModule is what the mesh says about a module it has never been told about.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
func manifest(name string, provides, requires []string) catalogue.Manifest {
|
func manifest(name string, provides, requires []string) catalogue.Manifest {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// What removing a module takes with it, and what re-registering one does not.
|
// What removing a module takes with it, and what re-registering one does not.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ForTest is a fresh inventory in a database of its own, dropped when the test ends.
|
// ForTest is a fresh inventory in a database of its own, dropped when the test ends.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ package inventory
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name is what this context is called: its database, and the environment variable holding the
|
// Name is what this context is called: its database, and the environment variable holding the
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- Ports a machine holds that the mesh did not assign.
|
-- Ports a machine holds that the mesh did not assign.
|
||||||
--
|
--
|
||||||
-- novox/hq ADR 0038. The substrate is not a module: a node raises it from the bundle it carries
|
-- novox/hq ADR 0038. The foundation is not a module: a node raises it from the bundle it carries
|
||||||
-- before any mesh exists, so the control plane has never heard of the store or the broker. Told
|
-- before any mesh exists, so the control plane has never heard of the store or the broker. Told
|
||||||
-- what they hold, it can put a module somewhere else; not told, it hands out a port one of them
|
-- what they hold, it can put a module somewhere else; not told, it hands out a port one of them
|
||||||
-- has and finds out from a container runtime three layers down.
|
-- has and finds out from a container runtime three layers down.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Inventory is this context, holding the store it exclusively owns.
|
// Inventory is this context, holding the store it exclusively owns.
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func (i *Inventory) assignPort(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return Assigned{}, err
|
return Assigned{}, err
|
||||||
}
|
}
|
||||||
// And what the machine itself says it already holds — the substrate it raised before there
|
// And what the machine itself says it already holds — the foundation it raised before there
|
||||||
// was a mesh to ask (novox/hq ADR 0038). Not assignments: nothing here chose them, and
|
// was a mesh to ask (novox/hq ADR 0038). Not assignments: nothing here chose them, and
|
||||||
// nothing here can move them.
|
// nothing here can move them.
|
||||||
carried, err := i.carriedOn(ctx, nodeID)
|
carried, err := i.carriedOn(ctx, nodeID)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
func aNodeWithModules(t *testing.T, modules ...string) (*Inventory, string) {
|
func aNodeWithModules(t *testing.T, modules ...string) (*Inventory, string) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/secrets"
|
"github.com/novox/mesh-controller/internal/secrets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Where sealed secrets live.
|
// Where sealed secrets live.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"crypto/ecdh"
|
"crypto/ecdh"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/secrets"
|
"github.com/novox/mesh-controller/internal/secrets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Shape is how a vendor's credential behaves, and the switch the ADR 0050 carve-out turns on.
|
// Shape is how a vendor's credential behaves, and the switch the ADR 0050 carve-out turns on.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ForTest is a fresh licence store in a database of its own, dropped when the test ends.
|
// ForTest is a fresh licence store in a database of its own, dropped when the test ends.
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/novox/mesh-control/internal/licences/adapters"
|
"github.com/novox/mesh-controller/internal/licences/adapters"
|
||||||
"github.com/novox/mesh-control/internal/secrets"
|
"github.com/novox/mesh-controller/internal/secrets"
|
||||||
"github.com/novox/mesh-control/internal/store"
|
"github.com/novox/mesh-controller/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Name is what this context is called: its database and its credential are named after it.
|
// Name is what this context is called: its database and its credential are named after it.
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/crypto/nacl/box"
|
"golang.org/x/crypto/nacl/box"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/licences/adapters"
|
"github.com/novox/mesh-controller/internal/licences/adapters"
|
||||||
"github.com/novox/mesh-control/internal/secrets"
|
"github.com/novox/mesh-controller/internal/secrets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nodeKeyPair is a node's key as the node would hold it: the public half the mesh seals to, and an
|
// nodeKeyPair is a node's key as the node would hold it: the public half the mesh seals to, and an
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/secrets"
|
"github.com/novox/mesh-controller/internal/secrets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SubmitRefresh is the boundary a manager NODE crosses to publish a refresh it performed: the control
|
// SubmitRefresh is the boundary a manager NODE crosses to publish a refresh it performed: the control
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/crypto/nacl/box"
|
"golang.org/x/crypto/nacl/box"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// What a node says when it joins, as that node's own code writes it.
|
// What a node says when it joins, as that node's own code writes it.
|
||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
// Skipped unless MESH_ENROL names the file the host's suite wrote:
|
// Skipped unless MESH_ENROL names the file the host's suite wrote:
|
||||||
//
|
//
|
||||||
// mesh-host: MESH_ENROL_OUT=/tmp/enrol.json go test ./internal/link/
|
// mesh-host: MESH_ENROL_OUT=/tmp/enrol.json go test ./internal/link/
|
||||||
// mesh-control: MESH_ENROL=/tmp/enrol.json make check
|
// mesh-controller: MESH_ENROL=/tmp/enrol.json make check
|
||||||
//
|
//
|
||||||
// **What this does not cover**, said so nobody reads more into a pass than is there: the full
|
// **What this does not cover**, said so nobody reads more into a pass than is there: the full
|
||||||
// enrolment path also issues a broker account, and that needs a broker. What is checked here is
|
// enrolment path also issues a broker account, and that needs a broker. What is checked here is
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/broker"
|
"github.com/novox/mesh-controller/internal/broker"
|
||||||
"github.com/novox/mesh-control/internal/identity"
|
"github.com/novox/mesh-controller/internal/identity"
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enrolment is what actually happens when a node presents a token: the token is spent, the key is
|
// Enrolment is what actually happens when a node presents a token: the token is spent, the key is
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/inventory"
|
"github.com/novox/mesh-controller/internal/inventory"
|
||||||
"github.com/novox/mesh-control/internal/link"
|
"github.com/novox/mesh-controller/internal/link"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Turning what a node said into what the mesh keeps.
|
// Turning what a node said into what the mesh keeps.
|
||||||
@@ -152,7 +152,7 @@ func TestABareAliveDoesNotWipeTheDeclarationThatSaysANodeIsCurrent(t *testing.T)
|
|||||||
func TestAFailureDoesNotBecomeTheAccountOfWhatTheMachineHolds(t *testing.T) {
|
func TestAFailureDoesNotBecomeTheAccountOfWhatTheMachineHolds(t *testing.T) {
|
||||||
// A partial list is not an account of what the machine holds. Recording one as though it
|
// A partial list is not an account of what the machine holds. Recording one as though it
|
||||||
// were would tell a rebuilding node to remove what it still has — which is the fault that
|
// were would tell a rebuilding node to remove what it still has — which is the fault that
|
||||||
// destroyed a substrate once (novox/hq 04-ISSUES/010).
|
// destroyed a foundation once (novox/hq 04-ISSUES/010).
|
||||||
inv := inventory.ForTest(t)
|
inv := inventory.ForTest(t)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
node, err := inv.AddNode(ctx, "workstation")
|
node, err := inv.AddNode(ctx, "workstation")
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ type Report struct {
|
|||||||
|
|
||||||
// Carried are the machine's ports held by what that host raised from its own bundle.
|
// Carried are the machine's ports held by what that host raised from its own bundle.
|
||||||
//
|
//
|
||||||
// **The half the mesh cannot know** (novox/hq ADR 0038). The substrate is not a module — a
|
// **The half the mesh cannot know** (novox/hq ADR 0038). The foundation is not a module — a
|
||||||
// node raises it before any mesh exists — so without being told, the mesh assigns a module a
|
// node raises it before any mesh exists — so without being told, the mesh assigns a module a
|
||||||
// port the store or the broker already holds, and hears about it from a container runtime.
|
// port the store or the broker already holds, and hears about it from a container runtime.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ func config(node Node, peers []Peer, keyPath string) string {
|
|||||||
b.WriteString("PostDown = sysctl -q -w net.ipv4.ip_forward=0\n")
|
b.WriteString("PostDown = sysctl -q -w net.ipv4.ip_forward=0\n")
|
||||||
|
|
||||||
// And past the machine's own firewall, which on any node with a container runtime is
|
// And past the machine's own firewall, which on any node with a container runtime is
|
||||||
// closed. Docker sets the FORWARD policy to DROP and inserts its chains, so the substrate
|
// closed. Docker sets the FORWARD policy to DROP and inserts its chains, so the foundation
|
||||||
// this mesh installs at tier 1 silently breaks the network it builds at tier 2: every
|
// this mesh installs at tier 1 silently breaks the network it builds at tier 2: every
|
||||||
// spoke reaches the hub, no spoke reaches any other, and every part of it reports
|
// spoke reaches the hub, no spoke reaches any other, and every part of it reports
|
||||||
// success. Found in the lab; nothing about it is visible from the mesh's own state.
|
// success. Found in the lab; nothing about it is visible from the mesh's own state.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The private network as a module rather than as code beside the module system.
|
// The private network as a module rather than as code beside the module system.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/novox/mesh-control/internal/catalogue"
|
"github.com/novox/mesh-controller/internal/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
func networkOf(t *testing.T, nodes []Node) *Generator {
|
func networkOf(t *testing.T, nodes []Node) *Generator {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
// **Why it must hold.** The refresh token is sealed to the manager node — at adoption and after each
|
// **Why it must hold.** The refresh token is sealed to the manager node — at adoption and after each
|
||||||
// rotation — by the manager MODULE, in TypeScript (mesh-catalog anthropic-manager/sealedbox.ts). The
|
// rotation — by the manager MODULE, in TypeScript (mesh-catalog anthropic-manager/sealedbox.ts). The
|
||||||
// HOST then unseals it with Go's box.OpenAnonymous (mesh-host identity.SealingKey.Unseal) to mount the
|
// HOST then unseals it with Go's box.OpenAnonymous (mesh-host identity.SealingKey.Unseal) to mount the
|
||||||
// cleartext, and mesh-control seals every other credential with box.SealAnonymous (secrets.Seal). If
|
// cleartext, and mesh-controller seals every other credential with box.SealAnonymous (secrets.Seal). If
|
||||||
// the TS seal and the Go box disagreed by a byte, the host would refuse the refresh token as a value
|
// the TS seal and the Go box disagreed by a byte, the host would refuse the refresh token as a value
|
||||||
// it cannot open — silently, as a manager that never gets its credential. So this is load-bearing, and
|
// it cannot open — silently, as a manager that never gets its credential. So this is load-bearing, and
|
||||||
// it is pinned here rather than trusted.
|
// it is pinned here rather than trusted.
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"_comment": "Produced by mesh-catalog anthropic-manager sealedbox.ts (crypto_box_seal). Proves that value the module seals to a node's public key opens under Go box.OpenAnonymous — the host's Unseal and mesh-control secrets.Seal/Open. Regenerate with the module's compiled seal().",
|
"_comment": "Produced by mesh-catalog anthropic-manager sealedbox.ts (crypto_box_seal). Proves that value the module seals to a node's public key opens under Go box.OpenAnonymous — the host's Unseal and mesh-controller secrets.Seal/Open. Regenerate with the module's compiled seal().",
|
||||||
"managerPublicKey": "rJZ9OSnuCcU5MNi8iV0EK8c5nYN+Cx5A+q+miIIIoUc=",
|
"managerPublicKey": "rJZ9OSnuCcU5MNi8iV0EK8c5nYN+Cx5A+q+miIIIoUc=",
|
||||||
"managerPrivateKey": "wGHx9hpbO1pyvLiw8oGwi31LBce3HscDiGhXpNU+wl4=",
|
"managerPrivateKey": "wGHx9hpbO1pyvLiw8oGwi31LBce3HscDiGhXpNU+wl4=",
|
||||||
"plaintext": "rt-a-refresh-token-only-the-manager-may-read",
|
"plaintext": "rt-a-refresh-token-only-the-manager-may-read",
|
||||||
|
|||||||
+12
-12
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"module": "mesh-control",
|
"module": "mesh-controller",
|
||||||
"version": "1",
|
"version": "1",
|
||||||
"slug": "control",
|
"slug": "control",
|
||||||
"capabilities": [
|
"capabilities": [
|
||||||
@@ -7,42 +7,42 @@
|
|||||||
],
|
],
|
||||||
"claims": [
|
"claims": [
|
||||||
{
|
{
|
||||||
"name": "the-control-plane",
|
"name": "the-controller",
|
||||||
"scope": "mesh"
|
"scope": "mesh"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"own-secrets": {
|
"own-secrets": {
|
||||||
"inventory": "/var/lib/mesh/mesh-control/inventory",
|
"inventory": "/var/lib/mesh/mesh-controller/inventory",
|
||||||
"identity": "/var/lib/mesh/mesh-control/identity",
|
"identity": "/var/lib/mesh/mesh-controller/identity",
|
||||||
"licences": "/var/lib/mesh/mesh-control/licences",
|
"licences": "/var/lib/mesh/mesh-controller/licences",
|
||||||
"broker": "/var/lib/mesh/mesh-control/broker",
|
"broker": "/var/lib/mesh/mesh-controller/broker",
|
||||||
"broker-management": "/var/lib/mesh/mesh-control/broker-management",
|
"broker-management": "/var/lib/mesh/mesh-controller/broker-management",
|
||||||
"broker-address": "/var/lib/mesh/mesh-control/broker-address"
|
"broker-address": "/var/lib/mesh/mesh-controller/broker-address"
|
||||||
},
|
},
|
||||||
"resources": [
|
"resources": [
|
||||||
{
|
{
|
||||||
"id": "mesh-state",
|
"id": "mesh-state",
|
||||||
"type": "directory",
|
"type": "directory",
|
||||||
"path": "/var/lib/mesh/mesh-control",
|
"path": "/var/lib/mesh/mesh-controller",
|
||||||
"mode": "0700"
|
"mode": "0700"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "control-env",
|
"id": "control-env",
|
||||||
"type": "file",
|
"type": "file",
|
||||||
"path": "/var/lib/mesh/mesh-control/control.env",
|
"path": "/var/lib/mesh/mesh-controller/control.env",
|
||||||
"mode": "0600",
|
"mode": "0600",
|
||||||
"content": "MESH_STORE_INVENTORY=${secret:inventory}\nMESH_STORE_IDENTITY=${secret:identity}\nMESH_STORE_LICENCES=${secret:licences}\nMESH_BROKER_AMQP=${secret:broker}\nMESH_BROKER_MANAGEMENT=${secret:broker-management}\nMESH_BROKER_ADDRESS=${secret:broker-address}\n"
|
"content": "MESH_STORE_INVENTORY=${secret:inventory}\nMESH_STORE_IDENTITY=${secret:identity}\nMESH_STORE_LICENCES=${secret:licences}\nMESH_BROKER_AMQP=${secret:broker}\nMESH_BROKER_MANAGEMENT=${secret:broker-management}\nMESH_BROKER_ADDRESS=${secret:broker-address}\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "server",
|
"id": "server",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"name": "mesh-control",
|
"name": "mesh-controller",
|
||||||
"network": "host",
|
"network": "host",
|
||||||
"args": [
|
"args": [
|
||||||
"serve"
|
"serve"
|
||||||
],
|
],
|
||||||
"env-file": [
|
"env-file": [
|
||||||
"/var/lib/mesh/mesh-control/control.env"
|
"/var/lib/mesh/mesh-controller/control.env"
|
||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"MESH_BROKER_CERTIFICATE": "/broker-tls/tls.crt"
|
"MESH_BROKER_CERTIFICATE": "/broker-tls/tls.crt"
|
||||||
|
|||||||
Reference in New Issue
Block a user