Seats held by assignments, one assignment per module per node, and 0113's bottom of the stack
Decided with the author: - A seat is held by one assignment, not claimed by a definition. A definition says which seats a module can hold; an assignment says which it does. The store module can run on every node and one assignment holds mesh-store; moving a role changes an assignment, never a definition. The foundation's seats name what the mesh itself uses and route no consumer — database and amqp consumers use co-location, the holder included. This replaces the wrong rationale that the foundation's store is "provider to nobody", which contradicted ADR 0078 and to-be 21. 0079's one-postgres rule becomes one mesh-store holder. - A module is assigned at most once to a node. The instance identity in 0112 and 27 is withdrawn, and the login-length problem with it. Review fixes to 0113: - The bottom of the stack: the vault is installed as soon as the shared runtime base exists, and genesis generates everything needed until then — including the permanent controller's, the control-node agent's, the builder's and the broker provisioner's bus accounts, and the controller's store login. Genesis creates those accounts until the broker's provisioner runs and adopts them. - Genesis's values are delivered recorded as the mesh's own, so 0092's never-replace rule for operator values does not make them unrotatable. - Backend-issued secrets (a forge's once-only API token) enter through the vault. Non-module parties (the controller's logins, node agents' accounts) are answered the same way, the controller asking on their behalf; an enrolment token reaches the controller only as what verifies it. - A secret with no provisioner to apply it is marked not rotatable by the mesh and refused, instead of a restart reported as done. Unused password generators in six provider clients are removed, and a catalogue scan checks no module mints. - Rotation's lock-out cases (offline reader, bus account owner, restarted provisioner) are recorded as open, with overlap and re-confirm-with-safeguards as the two answers, to be chosen before acceptance. 0110, 0111 and 26 are marked proposed: they changed in meaning and are under review, and an accepted record must not rest on proposed ones. To-be 23 and the glossary are restored to main; they change when these records are accepted.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
layer: to-be
|
||||
status: in-progress
|
||||
status: proposed
|
||||
code:
|
||||
- mesh-controller internal/catalogue/seats.go
|
||||
- mesh-controller internal/catalogue/resolve.go
|
||||
@@ -17,8 +17,8 @@ decisions:
|
||||
|
||||
# 26 — The seats
|
||||
|
||||
**What a mesh can have one of, and who fills each.** A seat is a named role at a scope, taken by a
|
||||
module assignment. The mesh defines which seats exist. Occupying one may deliver a provision, and the
|
||||
**What a mesh can have one of, and who fills each.** A seat is a named role at a scope, held by one
|
||||
module assignment. The mesh defines which seats exist. Holding one may deliver a provision, and the
|
||||
list of seats with their holders is the quickest answer to "what is in this mesh".
|
||||
|
||||
## What a seat is
|
||||
@@ -27,28 +27,31 @@ A seat has four properties, fixed by the mesh rather than by any module:
|
||||
|
||||
| property | is |
|
||||
|---|---|
|
||||
| name | what a manifest claims, and what a person reads in the list |
|
||||
| name | what a definition names and an assignment holds, and what a person reads in the list |
|
||||
| scope | node, site or mesh: where its capacity applies. Every seat in the set has a capacity of one, so one holder per scope. A bench, a seat with several holders, is a word the glossary keeps and no seat uses yet |
|
||||
| delivers | the provision its holder answers for, or nothing |
|
||||
| decision | the record that made it a seat |
|
||||
|
||||
**A module assignment holds a seat by claiming it.** The claim is the manifest's `claims`, and it is
|
||||
satisfied by assigning the module somewhere. The seat is not a second record beside the assignment.
|
||||
It points at the assignment, and everything the mesh knows about the holder is what it knows about
|
||||
that assignment: the node, the node's settings for the module, and what the module serves.
|
||||
**A definition says which seats a module can hold. An assignment says which it does hold.** The store
|
||||
module can hold `mesh-store`, and it may run on every node whose capabilities match. Exactly one of
|
||||
those assignments holds the seat, because that assignment says so, and a second assignment saying so
|
||||
is refused. A seat makes a role singular, never a module.
|
||||
|
||||
**The set is closed.** A claim naming a seat the mesh does not define is refused, and so is a claim at
|
||||
the wrong scope. Adding a seat is a decision, recorded, for the reason every addition to the host's
|
||||
vocabulary is one: the set is what a person reads to learn what a mesh can have, and an entry nobody
|
||||
argued for is an entry nobody can explain.
|
||||
**The seat points at the assignment.** Everything the mesh knows about the holder is what it knows
|
||||
about that assignment: the node, the node's settings for the module, and what the module serves.
|
||||
|
||||
**The set is closed.** A seat the mesh does not define is refused wherever it is named, and so is one
|
||||
named at the wrong scope. Adding a seat is a decision, recorded, for the reason every addition to the
|
||||
host's vocabulary is one: the set is what a person reads to learn what a mesh can have, and an entry
|
||||
nobody argued for is an entry nobody can explain.
|
||||
|
||||
## The set
|
||||
|
||||
| seat | scope | delivers | typically held by |
|
||||
|---|---|---|---|
|
||||
| `mesh-controller` | mesh | — | the controller |
|
||||
| `mesh-store` | mesh | — | the foundation's store |
|
||||
| `mesh-broker` | mesh | `amqp` | the broker |
|
||||
| `mesh-store` | mesh | — | the store the mesh's own records live in |
|
||||
| `mesh-broker` | mesh | — | the broker carrying the mesh's own bus |
|
||||
| `mesh-vault` | mesh | `secret`, reserved | the vault |
|
||||
| `the-artifact-store` | mesh | `artifact-store` | the artifact registry |
|
||||
| `the-catalogue` | mesh | — | the catalogue |
|
||||
@@ -64,27 +67,24 @@ argued for is an entry nobody can explain.
|
||||
|
||||
The controller holds this set in code, and a test asserts both its size and that every entry names
|
||||
the record that made it a seat. **This table and [ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md)
|
||||
govern, and code that disagrees is what is wrong.** The implementation in progress predates three
|
||||
things here: the `mesh-vault` seat and its reservation, and the rule that `mesh-store` delivers
|
||||
nothing. It is brought to this table before it merges.
|
||||
govern, and code that disagrees is what is wrong.** The implementation in progress predates several
|
||||
things here: seats held by assignments rather than claimed by definitions, the `mesh-vault` seat and
|
||||
its reservation, and the foundation's seats delivering nothing. It is brought to this table before it
|
||||
merges.
|
||||
|
||||
## The foundation's seats
|
||||
|
||||
`mesh-controller`, `mesh-store` and `mesh-broker` name which assignment the mesh *itself* uses: the
|
||||
controller, the store holding its records, the broker carrying its bus. **They route no consumer.** The
|
||||
store and broker modules may run on other nodes too. A database or `amqp` consumer is served by
|
||||
co-location, from whichever runs on its own node, the seat's holder included
|
||||
([23 — Choosing a provider](23-choosing-a-provider.md)).
|
||||
|
||||
## A seat that delivers a provision
|
||||
|
||||
A seat that delivers a provision may only be held by a module that provides it, at the seat's scope.
|
||||
A mesh seat delivers a mesh-scoped provision.
|
||||
|
||||
**A seat delivers a provision only where the mesh has one answer for everyone.** The broker, the
|
||||
artifact store, the npm registry, git and the vault are each one per mesh by decision. The store is
|
||||
not: nodes run their own stores and a consumer uses the one on its machine
|
||||
([23 — Choosing a provider](23-choosing-a-provider.md)), and the foundation's store is the controller's
|
||||
own memory, provider to nobody. So `mesh-store` guards that the foundation's store is singular, and
|
||||
routes nobody.
|
||||
|
||||
**The vault's provision is reserved.** Only the holder of `mesh-vault` may provide `secret` at all: a
|
||||
module providing it without the seat is refused, and a pin cannot choose another provider, because
|
||||
there is none. A second provider of secrets would be a second place secrets live, which is what the
|
||||
vault being one per mesh exists to prevent. Every other delivered provision may have second
|
||||
providers, which a pin can choose.
|
||||
**A seat delivers a provision only where the mesh has one answer for everyone.** The artifact store,
|
||||
the npm registry, git and the vault are each one per mesh by decision. A seat that delivers a
|
||||
provision may only be held by an assignment of a module that provides it, at the seat's scope.
|
||||
|
||||
**Its holder answers for that provision.** A requirement for it resolves, in order, to:
|
||||
|
||||
@@ -96,21 +96,23 @@ providers, which a pin can choose.
|
||||
Co-location, which answers first for every other provision, does not apply here: a seat says which
|
||||
one is the mesh's, and co-location answering first would let any second provider on a consumer's
|
||||
machine take over for that consumer, silently. So a second provider can run beside the holder and
|
||||
harm nothing. The forge holds
|
||||
`npm-package-registry`. An npm proxy may provide the same provision on another machine, and a module
|
||||
requiring an npm registry is still served by the forge, without anybody pinning it.
|
||||
harm nothing. A forge assignment holds `npm-package-registry`. An npm proxy may provide the same
|
||||
provision on another machine, and a module requiring an npm registry is still served by the forge,
|
||||
without anybody pinning it.
|
||||
|
||||
**Moving the role is changing which module claims the seat, and today that is a definition change.**
|
||||
A claim is part of a module's definition, so the proxy's definition must claim the seat and the
|
||||
forge's must stop. The forge cannot simply be unassigned, because it holds `git` as well. Every
|
||||
consumer follows once the claim moves. Making *which* seats a module holds the assignment's choice,
|
||||
with the definition saying only which seats it *can* hold, is the consistent answer, and
|
||||
[27 — A module requires, the mesh resolves](27-a-module-requires-the-mesh-resolves.md) lists it as
|
||||
not yet settled.
|
||||
**Moving the role is changing which assignment holds the seat.** No definition changes and nothing is
|
||||
unassigned: the forge keeps running, and keeps holding `git`, when its npm role moves. A module can
|
||||
take the role only if its definition says it can hold the seat.
|
||||
|
||||
**What a consumer receives is a grant**, the same as for any provision: where the provider answers,
|
||||
what it serves, and a credential. A consumer never reads the seat directly. The one exception is the
|
||||
controller itself, which reaches the store and the broker through a narrow seat placeholder,
|
||||
**The vault's provision is reserved.** Only an assignment holding `mesh-vault` may provide `secret` at
|
||||
all: a definition providing it that cannot hold the seat is refused, an assignment providing it without
|
||||
holding the seat is refused, and a pin cannot choose another provider, because there is none. A second
|
||||
provider of secrets would be a second place secrets live, which is what the vault being one per mesh
|
||||
exists to prevent.
|
||||
|
||||
**What a consumer receives is what it required**, the same as for any provision: where the provider
|
||||
answers, what it serves, and a credential. A consumer never reads the seat directly. The one exception
|
||||
is the controller itself, which reaches the store and the broker through a narrow seat placeholder,
|
||||
because it made them before any module existed and cannot be their consumer. One foundation module
|
||||
also reads it today, to find its own server's port. [27](27-a-module-requires-the-mesh-resolves.md)
|
||||
moves that to a host port requirement.
|
||||
@@ -123,9 +125,9 @@ their job, and it is a real one: it is the mesh saying what a machine is, in wor
|
||||
|
||||
## The overview
|
||||
|
||||
The controller lists every seat in the set with its scope, what it delivers, and each holder as a
|
||||
node and a module. A seat nobody holds is listed as unheld. That is an answer, "this mesh has no
|
||||
forge", and not a fault.
|
||||
The controller lists every seat in the set with its scope, what it delivers, and its holder as a node
|
||||
and a module. A seat nobody holds is listed as unheld. That is an answer, "this mesh has no forge",
|
||||
and not a fault.
|
||||
|
||||
Holdings are derived from assignments whenever they are asked for, never stored. The list is always
|
||||
what the mesh is running, because it is computed from the same thing that decides what the mesh runs.
|
||||
@@ -140,13 +142,13 @@ mesh records which:
|
||||
| on the `git` seat | a repository on the forge that holds the seat | its path on the forge, and the seat |
|
||||
| external | a repository anywhere else, a public forge for instance | its URL, exactly as given |
|
||||
|
||||
For a repository on the seat, the controller composes the clone URL at the moment of building,
|
||||
from where the holder runs and the scheme and port it serves for `git`. The recorded source never
|
||||
contains an address, so moving the forge changes nothing that was recorded. The build machine is not
|
||||
told the difference: it receives a URL either way.
|
||||
For a repository on the seat, the controller composes the clone URL at the moment of building, from
|
||||
where the holder runs and the scheme and port it serves for `git`. The recorded source never contains
|
||||
an address, so moving the forge changes nothing that was recorded. The build machine is not told the
|
||||
difference: it receives a URL either way.
|
||||
|
||||
With the seat unheld, a build from the seat is refused and says why. External builds carry on.
|
||||
|
||||
**Not yet designed:** a credential for cloning a private repository. The mesh's own repositories are
|
||||
public. The natural place for a clone credential is the `git` provision's grant, and that is a
|
||||
decision still to take.
|
||||
public. The natural place for a clone credential is a `secret` from the vault, and that is a decision
|
||||
still to take.
|
||||
|
||||
Reference in New Issue
Block a user