Files
mesh-host/internal/link/messages.go
T

131 lines
6.1 KiB
Go

package link
import "time"
// The wire formats shared with the control plane, which defines them separately because this
// binary requires nothing present and does not import it. A test on each side asserts the field
// names, so a rename breaks both at once rather than on a real machine months later.
// Routing keys a node may publish. Its broker account is scoped to this exchange and its own
// queue, so it can say these things and nothing else.
const (
KeyReport = "report"
KeyAlive = "alive"
)
// Alive is a node saying nothing except that it is there.
//
// novox/hq 09-the-node-lifecycle: *how long it has been disconnected is a fact the mesh must
// hold, and nothing holds it today. Without it, a node running last month's assignments looks
// exactly like one that is current.*
//
// Separate from a report because the two happen at completely different rates: a node is alive
// constantly and applies something rarely, and reading one as the other would make a quiet node
// look like a stale one.
type Alive struct {
Node string `json:"node"`
}
// Signed is a declaration and the signature over it.
//
// novox/hq ADR 0004: the transport is verified once at connect, and **each declaration is
// verified by its signature, every time**. The two are different questions — a node connects to
// the broker and takes instruction from the control plane behind it, and pinning only the first
// would make the second transitive.
//
// The signature is over Declaration exactly as it arrived, bytes unchanged. Re-encoding before
// verifying would mean checking a signature over something other than what was sent, and any
// difference in key order or spacing would break it — so the raw message is what is signed and
// what is checked.
type Signed struct {
Declaration []byte `json:"declaration"`
Signature []byte `json:"signature"`
}
// Report is what a node says after applying, and it is a statement rather than a write.
//
// A node states; the context that owns the data writes (novox/hq ADR 0006). The difference is the
// security boundary: something that can write cannot be prevented from writing anything, and
// something that can only state has its blast radius bounded by what this struct can say.
type Report struct {
Node string `json:"node"`
// Applied is what this machine now owns, by resource id.
Applied []string `json:"applied,omitempty"`
// Failed says what could not be applied, and why, in words for a person.
Failed map[string]string `json:"failed,omitempty"`
// Refused is set when the declaration was rejected whole rather than applied in part.
Refused string `json:"refused,omitempty"`
// Superseded names the newer declaration this one was set aside for, unapplied.
//
// A machine asked to be five successive things becomes the last one (novox/hq issue 031):
// when several declarations are waiting, the host applies the newest and acknowledges the
// rest without applying them. Each of those is still reported, because silence reads as a
// machine that ignored an instruction and "applied" would be a lie — this is the third word.
Superseded string `json:"superseded,omitempty"`
// Carried are the machine's ports held by what this host raised from its own bundle.
//
// **So the mesh can assign around what it did not put here** (novox/hq ADR 0038). A node
// raises its foundation before any mesh exists, so the control plane has never heard of the
// store or the broker — and would hand a module a port one of them holds, discovering it only
// when a container runtime refused to start.
//
// A node *states* and the mesh writes, which is the whole shape of this message: this is the
// machine saying what is true of it, not asking for anything.
Carried []int `json:"carried,omitempty"`
// Declared is the digest of the declaration this report is about — sha256 of the exact bytes
// the mesh sent, which the mesh recorded when it sent them.
//
// **Which declaration, not when.** The mesh compared its send time to this report's arrival
// to decide whether a machine had caught up, and lost the race it invited: an apply started
// under the previous declaration finishes after the next one is sent, its report lands newer
// than the send, and the machine reads as caught up with words it has not read yet. Clocks
// cannot answer "which"; the digest is the answer itself.
Declared string `json:"declared,omitempty"`
// Held is what this adopted node found and is keeping as it was until its module is taken
// (novox/hq ADR 0100). Without it an adopted node reads as converged.
Held []Held `json:"held,omitempty"`
// Firewall is the firewall found on this machine — "ufw" or "none" — and empty on a node that
// was never asked, which is every converged one.
Firewall string `json:"firewall,omitempty"`
// Reachable is what can be reached on this machine now: every listening socket and every
// published container port. Only an adopted node reports it; it is what converging the node
// previews, so nothing closes without being named first.
Reachable []Reach `json:"reachable,omitempty"`
}
// Held is one file or container found on an adopted node and kept as it was.
type Held struct {
ID string `json:"id"`
Module string `json:"module"`
Kind string `json:"kind"`
Target string `json:"target"`
Since time.Time `json:"since"`
// Changed is what something other than the mesh did to it since — rewritten, stopped,
// replaced or gone — and empty while it is as found.
Changed string `json:"changed,omitempty"`
// Kept is where a file's original was kept.
Kept string `json:"kept,omitempty"`
}
// Reach is one thing reachable on the machine: a listening socket, or a published container port.
type Reach struct {
Protocol string `json:"protocol"`
Address string `json:"address"`
Port int `json:"port"`
// By is what holds it — a process, or a container's name.
By string `json:"by,omitempty"`
// Published is a container port the runtime publishes, reached on the forwarded path; its
// container's own port is ContainerPort.
Published bool `json:"published,omitempty"`
ContainerPort int `json:"container-port,omitempty"`
}