Issue 169: two module-defined seats, and the gap — a seat definition has no neutral home
nfs-share and smb-share share an intent, not a contract; one seat would be a union with every field optional. What the exemplar exposes is that a seat declared inside one module cannot be implemented by another without depending on it.
This commit is contained in:
@@ -37,21 +37,28 @@ Under the mesh as it stands, this arrangement has no expression and one failure
|
||||
- The clients are LAN devices, so this also meets [issue 154](../154-a-machines-own-network-is-not-a-reach/00-report.md)
|
||||
(no reach for the machine's own network).
|
||||
|
||||
## The proposal (the operator's, 2026-09-30)
|
||||
## The proposal (the operator's, 2026-09-30, settled after two rounds)
|
||||
|
||||
**File sharing is a core seat — a role each machine has, defined by the control plane — and, as
|
||||
with package registries (ADR 0109), one seat per protocol, so several modules occupy the family:**
|
||||
**Two module-defined seats, one per protocol, because NFS and SMB share an intent and not a
|
||||
contract.** A seat in the mesh's sense is a contract — what it accepts, emits and serves, and the
|
||||
tools its holder must answer (ADR 0126, 0132) — and lined up, the two share almost none of it:
|
||||
|
||||
| seat | scope | delivers | held by |
|
||||
|---|---|---|---|
|
||||
| `node-nfs-share` | node | `nfs-share` | an `nfs` module |
|
||||
| `node-smb-share` | node | `smb-share` | a `samba` module |
|
||||
| … (`node-webdav-share`) | node | … | whatever comes next |
|
||||
| | `nfs-share` | `smb-share` |
|
||||
|---|---|---|
|
||||
| serves | export path(s); the client ranges allowed (`sec=sys` authorises by address) | share name(s), path |
|
||||
| pair credential | none | a user and password per consumer |
|
||||
| consumer's mount | `at:/path` | `//at/share` with credentials |
|
||||
| holder's tools | export / unexport a path for a range | add / remove a share, create a user |
|
||||
|
||||
Named for their scope (ADR 0121), one holder per node (ADR 0110), each carrying its protocol
|
||||
(ADR 0129). A machine may hold both — nfs and samba on ace — and one module may hold several
|
||||
(0109: "gitea may hold several seats at once"). Adding a protocol is adding a seat and a
|
||||
provision, not widening one.
|
||||
One `file-share` seat would be the union with every field optional — a consumer could bind it and
|
||||
still not know how to mount what it got (the emptiness ADR 0129 warns against). "Export a path to
|
||||
the network" is a category, and the mesh needs no seat category: a consumer requires the one it
|
||||
can mount. If "give me the library, however" is ever needed, it is a provision an umbrella module
|
||||
serves, not a seat.
|
||||
|
||||
Both are node-scoped, one holder per node (ADR 0110), so ace holds both. `nfs` and `samba` are the
|
||||
first implementations; a second (Ganesha for `nfs-share`, ksmbd for `smb-share`) is what proves
|
||||
0126's promise that "replacing the implementation changes nothing for any caller".
|
||||
|
||||
The holder module:
|
||||
|
||||
@@ -61,14 +68,19 @@ The holder module:
|
||||
units, like `dnsmasq`/`sshd` do for theirs;
|
||||
- declares its endpoints (`nfs` 2049/tcp; `smb` 445/tcp, …) so the reach — internal, or the LAN
|
||||
once 154 has an answer — is the assignment's, and converge keeps them open;
|
||||
- **provides** the seat's provision, serving the export path(s), so a consumer on another node
|
||||
`requires nfs-share` (or `smb-share`) and reads `${bound:nfs-share:at}` and the path from its
|
||||
binding instead of a hand-typed mount — a pair credential where the protocol has one (a Samba
|
||||
user), none for `sec=sys` NFS.
|
||||
- **provides** the seat's provision, so a consumer on another node `requires nfs-share` (or
|
||||
`smb-share`) and reads `${bound:nfs-share:at}` and the path from its binding instead of a
|
||||
hand-typed mount.
|
||||
|
||||
What it would settle: ace's library becomes reachable from the mesh by declaration, the two host
|
||||
services get an owner, converge stops being a trap for them, and a media module on another machine
|
||||
(or a backup on novox) can mount the library the way it binds a database today.
|
||||
## The design gap this exposes
|
||||
|
||||
**A seat definition has no home outside the module that first declared it.** Today a seat is
|
||||
declared inside a manifest (`showcase` declares `the-showcase`, `ca-trust` its own). If `nfs`
|
||||
declared `nfs-share`, Ganesha could hold it only by depending on nfs's manifest — the coupling
|
||||
0126 removed for callers, reintroduced for implementations. The protocol needs a neutral place in
|
||||
the catalogue beside the modules (a seat definition registered like a manifest), with a module
|
||||
saying which seats it implements. This is the first role with an obvious second implementation,
|
||||
which is what makes it the exemplar for that mechanism.
|
||||
|
||||
## Open questions for the decision
|
||||
|
||||
@@ -77,5 +89,3 @@ services get an owner, converge stops being a trap for them, and a media module
|
||||
entries in one file.
|
||||
- How a consumer's binding expresses a *path* to mount (today bindings carry `at`, `port`, `as` and
|
||||
whatever the provider `serves`), and whether one share can serve several paths.
|
||||
- Whether the seat should exist before its first module (a system seat is a decision, ADR 0110) —
|
||||
the decision that adds the two seats can be the one that accepts this proposal.
|
||||
|
||||
Reference in New Issue
Block a user