Files
mesh-sdk/go/compose/input.go
T
jschoubben 2fd5ffdd62 A node's answer names every module it cannot compose, a folded module of an old-form build is left to the node as it runs, and no store reached says why (issue 1126, the seed's shadow)
The seed's shadow answers named the first refusal only (ace: baserow's archive,
novox: de-spiegel), so each round showed one more. A build that cannot be read or
taken in, and a module the composition refuses, are now each composed as a stub
and named. A module folded into the node's own composition whose manifest names a
build (de-spiegel, nats, photos, systemd-resolved: haves naming a build-... id)
runs a build only the controller holds: it is composed as a stub and its
resources are carried as the node runs them.
2026-10-27 23:17:05 +01:00

337 lines
16 KiB
Go

// Package compose is the controller's composition of a machine, as a function over a plain input (novox/hq ADR 0453
// clause 3, ADR 0446 clause 4): what the rest of the mesh offers and holds, the private network's generator, one
// node's resolution and, in the issues after, its rendering and its declaration.
//
// **It never allocates, makes, writes, logs or raises.** The controller composes with a store behind it; this
// package is its Reading and Foreseeing modes over data. Everything the controller reads from its store is a field of
// Input, and everything a send would make or record (a port, a credential, a seat passed on, a node left out) is
// returned for the caller to act on, never done. Input is never changed by a call. No field holds a secret value
// the composition needs: sealed values are optional inputs, and without them the composition uses stand-ins named
// foreseen. The logic is the controller's, ported from mesh-controller cmd/mesh-controller at commit
// 6c2a8d62100cb7d491f8eb9a623e1eeea5ec0de1 (plan.go, network.go, holdings.go, seat_pass.go), in the same order, with the
// same refusals in the same words, so that a comparison node for node is a fair one.
//
// It imports the standard library and mesh-sdk's own packages only.
// It reads no environment variable: the range the mesh allocates from and the suffix of its internal names are fields of Input.
package compose
import (
"encoding/json"
"errors"
"fmt"
"sort"
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// Input is everything the composition reads. Each field is what one read of the controller's inventory answers, named
// beside it; the controller's adapter fills it from its stores and the assigner from the mesh's facts and buckets
// (ADR 0446 clause 2).
type Input struct {
// Catalogue is the shelf: every module's manifest by name (inv.Catalogue), as it is to be composed. A recorded
// module kept at the build a machine runs (keepRecorded) is that node's Kept, applied to its own resolution only (never to the rest of the mesh).
Catalogue map[string]catalogue.Manifest
// Nodes is every node the mesh has (inv.Nodes and inv.Overlays together, one row per node).
Nodes []Node
// Holdings is every seat whose holder is on record (inv.Holdings).
Holdings []catalogue.Held
// Licences is every licence the mesh holds, with the machines that use it (open.Licences); none for a mesh with no
// licence.
Licences []Licence
// OverlayCIDR is the range the mesh allocates from when no tunnel was adopted, as genesis was told it (the
// controller's OverlayCIDRVar); empty means DefaultOverlayCIDR. The package reads no environment.
OverlayCIDR string
// InternalSuffix is what the mesh's internal names end in (the controller's MESH_INTERNAL_SUFFIX), with or without a leading
// dot; empty means overlay.DefaultSuffix. A fact of the whole mesh, so it is in the Input and never read from the environment.
InternalSuffix string
// Tunnels is, by node name, the found tunnel whose key is the node's overlay key (inv.Tunnels).
Tunnels map[string]FoundTunnel
// Adopted is the hub's found tunnel and the hub's name, whether or not the hub took it (inv.AdoptedTunnel); nil
// when no hub has one.
Adopted *AdoptedTunnel
// CarriedPeers is every peer of the adopted tunnel (inv.CarriedPeers).
CarriedPeers []CarriedPeer
// Joining is the nodes that hold a live enrolment token (inv.NodesWithALiveToken).
Joining []string
// Credentials is how each pair credential a node takes from elsewhere stands, never its value (what inv.SecretFor,
// SharedSecretFor and GivenPairSecret would answer): held, to be made by the next send, only a person's to give, or
// refused. A need with no entry here is one the next send would make.
Credentials []Credential
// Built is every repository the mesh has built (the keys of inv.Held): what tells a reference recorded with an address
// from an image a module runs straight from a public registry.
Built []string
// OperatorExport is every operator-sealed secret in the mesh, for a module that keeps them (inv.OperatorExport): sealed
// values the composition carries without opening. Nil when the mesh has no operator key.
OperatorExport *catalogue.KeptExport
// Issued is the credentials made for the consumers of each provider (inv.SecretsFrom): one row for each pair credential
// that exists, by the provider node it is for. The grants a provider must create are read from these, so a credential not
// made yet has no grant until the send that makes it. An assigner fills it from the facts snapshot's Grants of each
// machine (go/facts, from format 2), which carry who each credential is for and never the credential.
Issued []Issued
// OwnSecrets is the own secrets held on each machine (the module_secret rows): who made each, and the key it is sealed to.
// Their sealed values are optional.
OwnSecrets []OwnSecretRow
// KeptCoreBoxes is the vault's box last kept for each core credential on each machine (inv.KeptCoreBoxes).
KeptCoreBoxes []CoreBox
// BusUsers is the bus's user list as the controller composes it from the bus records and the hashes it holds (composeBusUsers),
// for the machine that runs the bus: names and hashes, never passwords. Empty when the Input does not carry it, and then
// the composition uses a stand-in, named foreseen. BusMissing are the users left out of it for want of a credential.
BusUsers string
BusMissing []string
// BusMinted are the bus users the mesh has minted a password hash for (inv.BusUserHash): `<node>.<module>` for a module and
// `provisioner.<node>` for a machine's provisioner client.
BusMinted []string
// BusMemberships is, by node, the membership sealed to it for the bus the mesh is moving to (inv.BusMemberships).
BusMemberships map[string]string
// Authority is the mesh's own certificate (identity.EstablishAuthority), public. Optional.
Authority string
// CurrentBuilds is, by module, the commit of the build the mesh holds for it (inv.CurrentBuilds, the commit it was built from);
// BuildIDs the build made from a commit of a module (inv.BuildOf), by module then commit. Read only to name the builds a
// declaration carries to a node-engine that reads them.
CurrentBuilds map[string]string
BuildIDs map[string]map[string]string
}
// Issued is one pair credential made for a consumer of a provider (inv.Secret): ForProvider is its copy sealed to the
// provider, optional.
type Issued struct {
Provision string
Consumer string
ConsumerModule string
Local string
Provider string
ForProvider string
}
// OwnSecretRow is one own secret held on a machine: Origin is `made` (the mesh generated it) or `accepted` (a person gave it),
// SealedTo the sealing key it is sealed to, and Sealed its value sealed to that key, optional.
type OwnSecretRow struct {
Node string
Module string
Name string
Origin string
SealedTo string
Sealed string
}
// CoreBox is the vault's box for one core credential of one machine, as last kept (inv.CoreBox).
type CoreBox struct {
Node string
Module string
Name string
Generation int
SealedTo string
Box json.RawMessage
}
// Node is one node of the mesh and what the composition reads about it.
type Node struct {
Name string
// Place is where it is on the private network (inv.Overlays).
Place Place
// Assigned is the modules assigned to it, in the order the controller reads them (inv.Assigned).
Assigned []string
// Capabilities are the ones present on it (inv.ProfileOf).
Capabilities map[string]bool
// PublicDomain is the domain it composes its routed names under (inv.PublicDomainOf).
PublicDomain string
// Account, AccountHome, AgentAccount and AgentAccountHome are its operator and agent logins (inv.NodeByName).
Account, AccountHome, AgentAccount, AgentAccountHome string
// Adopted is whether it is adopted rather than converged.
Adopted bool
// Pins is the provider each provision was pinned to for it (inv.PinsFor).
Pins map[string]catalogue.Chosen
// Bound is where each of its consumers of a provision that keeps data was last sent (inv.BindingsFor), by consumer
// module and provision. An assigner fills it from the facts snapshot's Bindings of the machine (go/facts, from format 2).
Bound map[string]map[string]catalogue.Chosen
// Settings is its settings layers by module (inv.SettingsFor); a module with none is absent.
Settings map[string][]catalogue.Layer
// Ports is the machine port each module's software port was given on it (inv.PortsFor), by module then port.
Ports map[string]map[int]int
// SealingKey is the public key its secrets are sealed to (inv.SealingKeyOf); empty when it has none. A public key, so
// nothing secret.
SealingKey string
// Taken is the modules taken on it, for an adopted node (inv.Taken).
Taken []string
// OutwardLinks are the links it reported as facing outside it (inv.OutwardLinksOf).
OutwardLinks []string
// Networks are the networks it reported being attached to, as link and network (inv.MachineOf); NetworksSaid is whether
// its node-engine said any at all, which is not the same as saying none.
Networks []catalogue.AttachedNetwork
NetworksSaid bool
// ServingKey is the key the machine serves with, which a certificate is issued for (identity.ServingKeyOf); empty when it has
// never reported one. Certificate is the certificate the mesh issued for its internal name, public and optional.
ServingKey string
Certificate string
// Sequence, Epoch and Generation are what the declaration is sent under (inv.Sequence, SentEpoch, SentGeneration): the order
// against every other send to the node, the lease epoch and the assignment generation it was last sent. Zero is not sent.
Sequence int64
Epoch uint64
Generation int64
// ReadsModules says its node-engine reads a module per resource and a build per module (inv.ReadsModules, issue 1145); only
// then are they sent. SentBuilds is the build of each module it was last sent, by module to commit, and SentKnown whether
// that is known at all (inv.SentBuilds); Runs is what each of its assignments runs (inv.AssignmentRuns), by module.
ReadsModules bool
SentBuilds map[string]string
SentKnown bool
Runs map[string]Run
// Kept is, by module, the manifest of a recorded or core module kept at the build this machine runs (plan.go keepRecorded:
// the caller reads it with recordedKept and ManifestAt), and KeptBuilds the commit of that build. They apply to this node's
// own resolution only, never to another node's, and a declaration carries the kept commit for the module.
Kept map[string]catalogue.Manifest
KeptBuilds map[string]string
// Contract is the contract of its node-engine's newest statement (inv.HealthOf); Stated is whether it ever stated one.
Contract int
Stated bool
// InOwn is the modules it runs inside its own composition (`<node>.node`), not by a composition of their own, since
// no fingerprint of the new form names them where it runs them (novox/hq issue 1126): Compositions folds their
// resources into the node's own, as the controller's composed writer does, unless fps gives one of the new form.
// The private network's module (overlay.Name), which nobody builds, is folded whether or not it is named here.
InOwn map[string]bool
// RunsOwn is the node's own composition (`<node>.node`) as it runs, when the node composes itself: a module folded
// there (InOwn) whose manifest names a build (NamesBuild) runs a build of the old form only the controller holds,
// so it is left to the node: Compositions composes it as a stub (Stub) and carries its resources as they run, each
// after the resource it runs after (issue 1126). Nil composes every folded module from its manifest, as before.
RunsOwn *delivery.Composed
}
// Place is where a node is, as its placement says (inv.Overlay).
type Place struct {
Key string
Endpoint string
Site string
Hub bool
Address string
}
// Reachable says whether the node can be dialled.
func (p Place) Reachable() bool { return strings.TrimSpace(p.Endpoint) != "" }
// Tunnel is a tunnel found on a node (inv.Tunnel).
type Tunnel struct {
Interface string
Unit string
Config string
Port int
MTU int
// Address is the interface's own address with its prefix length, Range the network that prefix names.
Address string
Range string
PublicKey string
Peers []TunnelPeer
}
// TunnelPeer is one peer of a found tunnel.
type TunnelPeer struct {
PublicKey string
Address string
}
// FoundTunnel is a node's tunnel and whether the node is adopted (inv.FoundTunnel).
type FoundTunnel struct {
Tunnel
NodeAdopted bool
}
// AdoptedTunnel is the hub's tunnel, the hub's name, and whether the hub's overlay key is the tunnel's, which is
// whether the private network took the tunnel over.
type AdoptedTunnel struct {
Tunnel Tunnel
Hub string
Adopted bool
}
// CarriedPeer is a peer of the adopted tunnel (inv.CarriedPeer).
type CarriedPeer struct {
PublicKey string
Address string
EnrolledAs string
Named string
}
// Licence is one licence the mesh holds: its name, what a consumer may know of it, and the machines and modules
// that use it.
type Licence struct {
Name string
Serves map[string]any
Holders []Holder
// Keys is, by holder, the licence's key sealed to that holder's machine (held.KeyFor), empty where the mesh holds none:
// the plaintext was discarded when it was supplied. Optional: nil means not given, and the composition uses a stand-in named
// foreseen; given (even empty), a holder with no entry is one the mesh holds no key for.
Keys map[Holder]string
// Manager is the holder of a refreshable-grant licence that manages it (held.ManagerOf); the zero Holder when none.
Manager Holder
}
// Holder is a module on a node that uses a licence.
type Holder struct {
Node string
Module string
}
// ErrNoSuchNode is what the controller's inventory answers for a node it does not have.
var ErrNoSuchNode = errors.New("no node of that name")
// node is the node of that name, or the refusal the controller's inventory gives for one it does not have.
func (in Input) node(name string) (Node, error) {
for _, n := range in.Nodes {
if n.Name == name {
return n, nil
}
}
return Node{}, fmt.Errorf("%w: %s", ErrNoSuchNode, name)
}
// sorted is the nodes by name, the order the controller reads them in.
func (in Input) sorted() []Node {
out := append([]Node(nil), in.Nodes...)
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
return out
}
// CredentialState is how one pair credential stands.
type CredentialState string
const (
// CredentialHeld is a credential held for both ends as they stand now. Sealed, when given, is the consumer's copy; a held
// credential with no value is composed with a stand-in, named foreseen.
CredentialHeld CredentialState = "held"
// CredentialWouldMake is a credential none is held for: the next send makes it, and the composition uses a stand-in,
// named foreseen. It is also what a need with no entry is.
CredentialWouldMake CredentialState = "would-make"
// CredentialNotGiven is a credential only a person gives (novox/hq ADR 0337 clause 4) that nobody has given, or that was given
// under a key one end no longer has: the consumer still resolves, without it. Why is the controller's words for it.
CredentialNotGiven CredentialState = "not-given"
// CredentialRefused is a credential the send would refuse to make, for the reason Why gives in the controller's words: a
// value a person gave sealed to a key the machine no longer has, a machine with no sealing key.
CredentialRefused CredentialState = "refused"
)
// Credential is the state of one pair credential, by the ends it joins: the provision, the consumer's node and module, the
// provider's node, and the local name where a module keeps several (inv.Secret's key).
type Credential struct {
Provision string
Consumer string
ConsumerModule string
Provider string
Local string
State CredentialState
// Sealed is the consumer's copy as it is sealed to the consumer's key; optional, and only the controller's adapter passes it.
Sealed string
// Why is the words of a CredentialNotGiven or CredentialRefused.
Why string
}
// Run is the build an assignment names: the commit it is of and the build made from it (chain.Ref).
type Run struct {
Commit string
Build string
}