The routing record is 0066, not 0056
0056 is 'the authority is the control plane, not a database'. A citation pointing at the wrong decision is worse than none: it reads as corroboration. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -66,7 +66,7 @@ func nodeCommand(ctx context.Context, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
case "public-domain":
|
case "public-domain":
|
||||||
// The domain this node composes its routed names under (novox/hq ADR 0056).
|
// The domain this node composes its routed names under (novox/hq ADR 0066).
|
||||||
//
|
//
|
||||||
// **The form with no argument reports; clearing is asked for by name.** It used to clear —
|
// **The form with no argument reports; clearing is asked for by name.** It used to clear —
|
||||||
// so `node public-domain anchor`, which reads like a question and is what anybody types to
|
// so `node public-domain anchor`, which reads like a question and is what anybody types to
|
||||||
@@ -88,7 +88,7 @@ const publicDomainUsage = "node public-domain <name> — what it is now; " +
|
|||||||
//
|
//
|
||||||
// Three forms, and the destructive one is the only one that has to be asked for. Clearing is a
|
// Three forms, and the destructive one is the only one that has to be asked for. Clearing is a
|
||||||
// real thing to want — a machine that stops facing the outside composes no names, and
|
// real thing to want — a machine that stops facing the outside composes no names, and
|
||||||
// lab-versus-production is this one setting (novox/hq ADR 0056) — so it keeps a way to say it.
|
// lab-versus-production is this one setting (novox/hq ADR 0066) — so it keeps a way to say it.
|
||||||
// What it does not keep is being the thing that happens when nothing was said at all.
|
// What it does not keep is being the thing that happens when nothing was said at all.
|
||||||
func publicDomain(ctx context.Context, inv *inventory.Inventory, args []string) error {
|
func publicDomain(ctx context.Context, inv *inventory.Inventory, args []string) error {
|
||||||
set := flag.NewFlagSet("node public-domain", flag.ContinueOnError)
|
set := flag.NewFlagSet("node public-domain", flag.ContinueOnError)
|
||||||
@@ -335,7 +335,7 @@ func showNode(ctx context.Context, inv *inventory.Inventory, name string) error
|
|||||||
fmt.Printf("%s\n", node.Name)
|
fmt.Printf("%s\n", node.Name)
|
||||||
fmt.Printf(" last heard from %s\n", heardFrom(node))
|
fmt.Printf(" last heard from %s\n", heardFrom(node))
|
||||||
|
|
||||||
// The domain its routed names are composed under, when it has one (novox/hq ADR 0056). Shown
|
// The domain its routed names are composed under, when it has one (novox/hq ADR 0066). Shown
|
||||||
// only when set: a machine that serves nothing to the outside has no domain, and saying so of
|
// only when set: a machine that serves nothing to the outside has no domain, and saying so of
|
||||||
// every internal node would be noise.
|
// every internal node would be noise.
|
||||||
domain, err := inv.PublicDomainOf(ctx, name)
|
domain, err := inv.PublicDomainOf(ctx, name)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func planFor(ctx context.Context, open *stores, nodeName string) (catalogue.Reso
|
|||||||
return catalogue.Resolution{}, nil, err
|
return catalogue.Resolution{}, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The domain this node composes its routed names under (novox/hq ADR 0056). A route
|
// The domain this node composes its routed names under (novox/hq ADR 0066). A route
|
||||||
// contribution carries only a label; the resolver joins <label>.<public-domain> for this node,
|
// contribution carries only a label; the resolver joins <label>.<public-domain> for this node,
|
||||||
// so the fact travels on the node it belongs to rather than being looked up where the name is
|
// so the fact travels on the node it belongs to rather than being looked up where the name is
|
||||||
// composed.
|
// composed.
|
||||||
@@ -435,7 +435,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// And every routed name → the node that serves it (novox/hq ADR 0056). Alongside the
|
// And every routed name → the node that serves it (novox/hq ADR 0066). Alongside the
|
||||||
// `<node>.internal` names above, so a container — or an internal ACME validator — resolves a
|
// `<node>.internal` names above, so a container — or an internal ACME validator — resolves a
|
||||||
// routed name to the proxy that serves it, mesh-wide. The mesh publishes the names it was told
|
// routed name to the proxy that serves it, mesh-wide. The mesh publishes the names it was told
|
||||||
// to serve and knows nothing about what they mean.
|
// to serve and knows nothing about what they mean.
|
||||||
@@ -453,7 +453,7 @@ func declarationWith(ctx context.Context, open *stores, node string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// ADR 0056).
|
// ADR 0066).
|
||||||
//
|
//
|
||||||
// **Mesh-wide, so any container resolves any routed name to its proxy** — including an internal
|
// **Mesh-wide, so any container resolves any routed name to its proxy** — including an internal
|
||||||
// ACME validator, which cannot complete a challenge for a name it cannot reach. A routed name is
|
// ACME validator, which cannot complete a challenge for a name it cannot reach. A routed name is
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ type readyNode struct {
|
|||||||
// composeEach works out what each named machine should be, and never lets one machine's answer
|
// composeEach works out what each named machine should be, and never lets one machine's answer
|
||||||
// decide another's.
|
// decide another's.
|
||||||
//
|
//
|
||||||
// **A machine whose set cannot be worked out is that machine's problem** (novox/hq ADR 0056). A
|
// **A machine whose set cannot be worked out is that machine's problem** (novox/hq ADR 0066). A
|
||||||
// whole-mesh push used to refuse outright when any one node failed to resolve, so a single
|
// whole-mesh push used to refuse outright when any one node failed to resolve, so a single
|
||||||
// unanswerable requirement on a single machine — one module requiring a provision nobody had
|
// unanswerable requirement on a single machine — one module requiring a provision nobody had
|
||||||
// assigned a provider for — left every other machine in the mesh unconverged, including machines
|
// assigned a provider for — left every other machine in the mesh unconverged, including machines
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ func run() error {
|
|||||||
root = read
|
root = read
|
||||||
// An empty bundle means the issuer's root is already in the system trust store — a public
|
// An empty bundle means the issuer's root is already in the system trust store — a public
|
||||||
// authority whose root ships with the OS, pointed at by a provider that serves an empty
|
// authority whose root ships with the OS, pointed at by a provider that serves an empty
|
||||||
// root (novox/hq ADR 0056). The mesh always writes the bundle file, so it exists and holds
|
// root (novox/hq ADR 0066). The mesh always writes the bundle file, so it exists and holds
|
||||||
// nothing; that is the signal to fall back to the system roots, the same as if nothing had
|
// nothing; that is the signal to fall back to the system roots, the same as if nothing had
|
||||||
// named a bundle at all. A file that holds bytes but no certificate is still a
|
// named a bundle at all. A file that holds bytes but no certificate is still a
|
||||||
// misconfiguration and is refused, because there the operator meant to trust something.
|
// misconfiguration and is refused, because there the operator meant to trust something.
|
||||||
@@ -257,7 +257,7 @@ func run() error {
|
|||||||
// forThisAuthority is where one ACME authority's account and certificates are kept.
|
// forThisAuthority is where one ACME authority's account and certificates are kept.
|
||||||
//
|
//
|
||||||
// **A cached ACME account belongs to the authority that issued it, and nothing in the cache says
|
// **A cached ACME account belongs to the authority that issued it, and nothing in the cache says
|
||||||
// so** (novox/hq ADR 0056). autocert keeps its account key at one fixed name — `acme_account+key` —
|
// so** (novox/hq ADR 0066). autocert keeps its account key at one fixed name — `acme_account+key` —
|
||||||
// in whatever directory it is given, and reuses it for ever. That is right while the authority stays
|
// in whatever directory it is given, and reuses it for ever. That is right while the authority stays
|
||||||
// the same and silently wrong the moment it does not: an internal CA that is re-initialised is a new
|
// the same and silently wrong the moment it does not: an internal CA that is re-initialised is a new
|
||||||
// authority with a new root, it has never heard of the account in the cache, and every attempt to
|
// authority with a new root, it has never heard of the account in the cache, and every attempt to
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A provider and its consumer on ONE machine, which is what ADR 0056's anchor is.
|
// A provider and its consumer on ONE machine, which is what ADR 0066's anchor is.
|
||||||
//
|
//
|
||||||
// **Every fault in this file is the same shape: the same-node path diverging from the cross-node
|
// **Every fault in this file is the same shape: the same-node path diverging from the cross-node
|
||||||
// one.** A provider on another machine is walked by the control plane — its served facts are
|
// one.** A provider on another machine is walked by the control plane — its served facts are
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A workload on THIS machine contributes the port it declared, and the machine may have
|
// A workload on THIS machine contributes the port it declared, and the machine may have
|
||||||
// published it somewhere else (novox/hq ADR 0056). The mirror of the redirect below: 038 fixed
|
// published it somewhere else (novox/hq ADR 0066). The mirror of the redirect below: 038 fixed
|
||||||
// what a consumer is TOLD about a provider, and this is what a workload TELLS the provider about
|
// what a consumer is TOLD about a provider, and this is what a workload TELLS the provider about
|
||||||
// itself — gitea declaring 3000, published as 20000:3000, and the co-located proxy dialling 3000,
|
// itself — gitea declaring 3000, published as 20000:3000, and the co-located proxy dialling 3000,
|
||||||
// where nothing listens, for every request.
|
// where nothing listens, for every request.
|
||||||
@@ -162,7 +162,7 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A provider answered on this same machine never passed through the walk that works out what a
|
// A provider answered on this same machine never passed through the walk that works out what a
|
||||||
// provider on ANOTHER machine serves (novox/hq 04-ISSUES/038, ADR 0056). That walk does two
|
// provider on ANOTHER machine serves (novox/hq 04-ISSUES/038, ADR 0066). That walk does two
|
||||||
// things — it derives the served facts with the provider node's port assignments, and it settles
|
// things — it derives the served facts with the provider node's port assignments, and it settles
|
||||||
// them with that node's settings layers — and the same-node paths (resolve.go's servedHere, and
|
// them with that node's settings layers — and the same-node paths (resolve.go's servedHere, and
|
||||||
// here() below) did neither, because both run while resolving, before either is known.
|
// here() below) did neither, because both run while resolving, before either is known.
|
||||||
@@ -449,7 +449,7 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
|
|||||||
// And what the module could not have written: the machine it turned out to be
|
// And what the module could not have written: the machine it turned out to be
|
||||||
// assigned to. Beside the bound values because it is the same kind of fact — the
|
// assigned to. Beside the bound values because it is the same kind of fact — the
|
||||||
// mesh's own, held in the clear — and because a module that must name itself to
|
// mesh's own, held in the clear — and because a module that must name itself to
|
||||||
// something else has no binding to learn it from (novox/hq ADR 0056).
|
// something else has no binding to learn it from (novox/hq ADR 0066).
|
||||||
if err := machineInto(copied, thisMachine, m.Module); err != nil {
|
if err := machineInto(copied, thisMachine, m.Module); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -795,7 +795,7 @@ func here(r Resolution, requirement string, with Rendering) (*Needed, error) {
|
|||||||
// 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
|
||||||
// values (ADR 0056, an internal CA's root arriving empty).
|
// values (ADR 0066, an internal CA's root arriving empty).
|
||||||
//
|
//
|
||||||
// Here rather than in the resolver, because here is the first moment both halves exist: resolving
|
// Here rather than in the resolver, because here is the first moment both halves exist: resolving
|
||||||
// runs before a machine's ports are assigned and knows nothing of settings.
|
// runs before a machine's ports are assigned and knows nothing of settings.
|
||||||
@@ -975,7 +975,7 @@ func asPort(v any) (int, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atMachinePort redirects a `port` written by a module on this machine to where this machine
|
// atMachinePort redirects a `port` written by a module on this machine to where this machine
|
||||||
// actually published it (novox/hq 04-ISSUES/038, ADR 0056).
|
// actually published it (novox/hq 04-ISSUES/038, ADR 0066).
|
||||||
//
|
//
|
||||||
// **A module writes the port its software uses; only the mesh knows where the machine put it.** A
|
// **A module writes the port its software uses; only the mesh knows where the machine put it.** A
|
||||||
// bare `ports` mapping is assigned a host port when the declaration is composed, which is after
|
// bare `ports` mapping is assigned a host port when the declaration is composed, which is after
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ import (
|
|||||||
// module is assigned, long after the manifest was written, and until now nothing carried it into a
|
// module is assigned, long after the manifest was written, and until now nothing carried it into a
|
||||||
// file.
|
// file.
|
||||||
//
|
//
|
||||||
// The case that found this is a certificate authority inside the mesh (novox/hq ADR 0056). A proxy
|
// The case that found this is a certificate authority inside the mesh (novox/hq ADR 0066). A proxy
|
||||||
// reaches it at the address the mesh handed over, `<machine>.internal` — so the authority's own
|
// reaches it at the address the mesh handed over, `<machine>.internal` — so the authority's own
|
||||||
// certificate has to be issued for that name, or the first thing that happens is the proxy refusing
|
// certificate has to be issued for that name, or the first thing that happens is the proxy refusing
|
||||||
// to talk to it. The authority is the one thing that cannot be told its name by a binding: it
|
// to talk to it. The authority is the one thing that cannot be told its name by a binding: it
|
||||||
// provides, it does not require. Written as a literal it would be a manifest carrying one
|
// provides, it does not require. Written as a literal it would be a manifest carrying one
|
||||||
// deployment's machine name, which is the shape [ADR 0056] exists to remove.
|
// deployment's machine name, which is the shape [ADR 0066] exists to remove.
|
||||||
//
|
//
|
||||||
// Two facts, both the mesh's own vocabulary — the same `node` and `at` a contribution already
|
// Two facts, both the mesh's own vocabulary — the same `node` and `at` a contribution already
|
||||||
// carries. Nothing about what a machine is *for*: that would be the mesh learning what a module
|
// carries. Nothing about what a machine is *for*: that would be the mesh learning what a module
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// novox/hq ADR 0056 — a module that must name ITSELF to something else.
|
// novox/hq ADR 0066 — a module that must name ITSELF to something else.
|
||||||
//
|
//
|
||||||
// The authority inside the mesh is the case. A proxy reaches it at the address the mesh handed
|
// The authority inside the mesh is the case. A proxy reaches it at the address the mesh handed
|
||||||
// over, so its certificate has to be issued for that name — and it has no binding to learn the name
|
// over, so its certificate has to be issued for that name — and it has no binding to learn the name
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type Node struct {
|
|||||||
// tell whether it can reach the node answering its requirements at all.
|
// tell whether it can reach the node answering its requirements at all.
|
||||||
At string
|
At string
|
||||||
// PublicDomain is the domain this node composes its routed names under, empty if it has none
|
// PublicDomain is the domain this node composes its routed names under, empty if it has none
|
||||||
// (novox/hq ADR 0056). A route contribution carries only a label — the subdomain — and the mesh
|
// (novox/hq ADR 0066). A route contribution carries only a label — the subdomain — and the mesh
|
||||||
// joins <label>.<public-domain> to make the name it grants, interpreting neither half.
|
// joins <label>.<public-domain> to make the name it grants, interpreting neither half.
|
||||||
PublicDomain string
|
PublicDomain string
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ type Resolution struct {
|
|||||||
// where it is — the answer being local does not make the port guessable.
|
// where it is — the answer being local does not make the port guessable.
|
||||||
At string
|
At string
|
||||||
// PublicDomain is the domain this node composes its routed names under, empty if it has none
|
// PublicDomain is the domain this node composes its routed names under, empty if it has none
|
||||||
// (novox/hq ADR 0056). Carried from the node so that composing <label>.<public-domain> for a
|
// (novox/hq ADR 0066). Carried from the node so that composing <label>.<public-domain> for a
|
||||||
// route contribution needs no store lookup here — the join is a fact about this one machine.
|
// route contribution needs no store lookup here — the join is a fact about this one machine.
|
||||||
PublicDomain string
|
PublicDomain string
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// novox/hq ADR 0056 — public routing is name-agnostic.
|
// novox/hq ADR 0066 — public routing is name-agnostic.
|
||||||
//
|
//
|
||||||
// A route contribution carries a label (the subdomain the operator chose); the node carries its
|
// A route contribution carries a label (the subdomain the operator chose); the node carries its
|
||||||
// public domain; the mesh composes <label>.<public-domain> and interprets neither half. The
|
// public domain; the mesh composes <label>.<public-domain> and interprets neither half. The
|
||||||
@@ -133,7 +133,7 @@ func TestALabelWithNoPublicDomainComposesNothing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestARoutedNameResolvesToTheServingNode(t *testing.T) {
|
func TestARoutedNameResolvesToTheServingNode(t *testing.T) {
|
||||||
// novox/hq ADR 0056 propagate: a granted route name is published into internal resolution,
|
// novox/hq ADR 0066 propagate: a granted route name is published into internal resolution,
|
||||||
// mapped to the node that serves it, alongside the `<node>.internal` names — so every
|
// mapped to the node that serves it, alongside the `<node>.internal` names — so every
|
||||||
// container, and an in-mesh ACME validator, resolves a routed name to the proxy that serves it.
|
// container, and an in-mesh ACME validator, resolves a routed name to the proxy that serves it.
|
||||||
// The names map is what withMeshNames writes into every container as `--add-host`; a route name
|
// The names map is what withMeshNames writes into every container as `--add-host`; a route name
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- The public domain a node's routed names are composed under.
|
-- The public domain a node's routed names are composed under.
|
||||||
--
|
--
|
||||||
-- novox/hq ADR 0056. A public route used to carry its whole hostname in the module manifest, so
|
-- novox/hq ADR 0066. A public route used to carry its whole hostname in the module manifest, so
|
||||||
-- running the same catalogue against a different domain — a lab standing in for production, a
|
-- running the same catalogue against a different domain — a lab standing in for production, a
|
||||||
-- second operator's mesh — meant overriding that literal on every routed module. That made the
|
-- second operator's mesh — meant overriding that literal on every routed module. That made the
|
||||||
-- mesh hold a map of names to services: the one thing it must not, because the subdomain is the
|
-- mesh hold a map of names to services: the one thing it must not, because the subdomain is the
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ func (i *Inventory) SealingKeyOf(ctx context.Context, name string) (string, erro
|
|||||||
|
|
||||||
// SetPublicDomain records the domain a node's routed names are composed under.
|
// SetPublicDomain records the domain a node's routed names are composed under.
|
||||||
//
|
//
|
||||||
// A node-level fact (novox/hq ADR 0056), kept beside the node's other node-level configuration
|
// A node-level fact (novox/hq ADR 0066), kept beside the node's other node-level configuration
|
||||||
// rather than in a module's settings: the subdomain is a module's to choose and the domain is the
|
// rather than in a module's settings: the subdomain is a module's to choose and the domain is the
|
||||||
// node's, and the mesh joins the two without interpreting either. An empty domain clears it — a
|
// node's, and the mesh joins the two without interpreting either. An empty domain clears it — a
|
||||||
// node that stops facing the outside composes no names — which is why this writes null rather than
|
// node that stops facing the outside composes no names — which is why this writes null rather than
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// novox/hq ADR 0056 — a node's public domain is a node-level fact, held here beside its other
|
// novox/hq ADR 0066 — a node's public domain is a node-level fact, held here beside its other
|
||||||
// node-level configuration rather than in a module's settings. These check it round-trips, that a
|
// node-level configuration rather than in a module's settings. These check it round-trips, that a
|
||||||
// node with none reports empty rather than failing, and that clearing it works — the setting the
|
// node with none reports empty rather than failing, and that clearing it works — the setting the
|
||||||
// ADR names as the whole of moving a catalogue between a lab and production.
|
// ADR names as the whole of moving a catalogue between a lab and production.
|
||||||
|
|||||||
Reference in New Issue
Block a user