Issue 169: the consumer half is a module (network-share), not a host resource kind; the access-on-a-mountpoint check is the data-loss case

This commit is contained in:
2026-09-30 13:56:07 +02:00
parent 90b89aa1c9
commit ee801a6441
@@ -82,29 +82,38 @@ the catalogue beside the modules (a seat definition registered like a manifest),
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.
## The consumer's half: the machine mounts it (2026-09-30, third round)
## The consumer's half: a module mounts it (2026-09-30, third and fourth round)
A binding tells a consumer *where* the share is; it does not put the files on its machine. A
consumer on another node needs the export **mounted by the host, at a directory the consumer
declares, before its container starts**, and unmounted when the requirement goes. That is a host
action, not something a container reads from a file.
A binding tells a consumer *where* the share is; it does not put the files on its machine. Mounting
is something done on a machine, and something done on a machine is a module's work — not the host's
(the vocabulary stays closed; no `mount` resource kind).
**Not a client module.** A node-wide `nfs-client` with a list of mounts in its settings is fstab
with a manifest around it: consumers would stop requiring `nfs-share` and couple on a path again,
unassigning a consumer would leave its mount behind, and a person is back in the loop deciding
which machine mounts what — the thing the binding removes.
**A consumer-side module, `network-share`,** assigned on the node that wants the files:
**A mount is a resource of the consuming module.** The vocabulary (directory, file, package,
container, service, process, network, archive, user, access) has no `mount`. It can be assembled
today — a `package` (nfs-utils), a `file` writing a systemd `.mount` unit with
`What=${bound:nfs-share:at}:${bound:nfs-share:path}` and `Where=${dir:library}`, a `service`
enabling it after the overlay is up — but the honest form is a **`mount` resource kind**: the host
mounts from the binding, refuses a mountpoint the module did not declare (ADR 0091's three ways a
path can be), and unmounts on undeclare. The nfs and samba modules are then the *server* side only.
- `requires nfs-share` (or `smb-share`); several shares on one node are several local names of
the requirement (ADR 0094);
- its manifest is a `package` (nfs-utils), a `file` writing a systemd `.mount` unit filled from
the binding — `What=${bound:nfs-share:at}:${bound:nfs-share:path}` — and a `service` enabling it
after the overlay is up: the same shape as `resolv-conf` or `sshd`, files and a unit;
- *where* it mounts is the assignment's setting (`/srv/media` on one machine, elsewhere on
another); which machine mounts what is an operator decision made at assignment, exactly as which
paths a machine shares is.
**The modules that use the files never learn about NFS.** A player, an indexer, a backup declares
the mounted path as an `access` — an operator-chosen, pre-existing path the mesh never owns
(ADR 0051), exactly as `/storage/media` is on ace. The same app manifest then runs on ace against
the local library and on another node against the mounted one, with only its assignment differing.
**The one check to add, because it is the data-loss case.** An `access` is confirmed today by the
path being present. For a mountpoint that is not enough: a writer whose container starts before the
mount is up writes into the empty directory underneath it, and the files vanish when the mount
lands. The access check must confirm the path is *a mountpoint* when the module says so (or the
module's unit is ordered before the consumer's container — which crosses modules and is exactly
what the mesh does not order). Which of the two is the decision's.
**Identity crosses the wire.** `sec=sys` NFS trusts the client's uid, so a consumer must run as the
library's owner on the server (ace: `media`, 1001:2000) — hq 153's `${access:<id>:uid}` proposal
extended to a mount, `${mount:<id>:uid}`, read from the mounted tree.
library's owner on the server (ace: `media`, 1001:2000) — hq 153's `${access:<id>:uid}`, read from
the mounted tree, answers it on the consumer's side too.
## Open questions for the decision