mesh/merge-gate pass: builds mounts, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request
185 lines
12 KiB
Markdown
185 lines
12 KiB
Markdown
# mounts
|
|
|
|
The shares and the occasional sources a machine mounts, and what it mounts and shares, read as tools
|
|
(novox/hq ADR 0263, to-be design 52 "Shares and mounts", from research 038). It holds the node seat
|
|
`node-mounts`, one holder per machine.
|
|
|
|
A machine mounts only what its assignment names (ADR 0263 rule 5): nothing by default, and "every
|
|
machine" is the same setting given once at the mesh-wide layer. A share of another machine comes from the
|
|
provision `nfs-share`, which `nfs-server` provides on the machine that shares.
|
|
|
|
## What it owns
|
|
|
|
- The packages `nfs-utils` and `cifs-utils`.
|
|
- `/etc/mesh-mounts/mounts.conf`, placed by the mesh from the assignment: the settings `shares` and
|
|
`sources`, the binding of `nfs-share` (`from`, the sharing machine, and `at`, where it is reached on
|
|
the private network), the operator account, and where the module's secret is.
|
|
- One `.mount` and one `.automount` unit per share or source, in `/etc/systemd/system`, named as
|
|
`systemd-escape --path` names the mount point and opened by the marker
|
|
`# Written by the mesh (module mounts, novox/hq ADR 0263).` A unit file without that marker is not the
|
|
module's: it is never written over, stopped or removed, and the share whose mount point it holds is
|
|
said as not set up.
|
|
- The SMB logins, one file per source in the module's state directory, readable by root only.
|
|
- `/var/lib/mesh-mounts/from-bus` (the bundle's: what the sharing machine exports) and `/run/mesh-mounts`
|
|
(the processes': what was applied and what was found).
|
|
|
|
What it never does: chown or chmod a mount point (it makes one that is missing, and nothing else), touch a
|
|
mounted filesystem to look at it, or remove a pair because the sharing machine did not answer. A pair is
|
|
removed only when the settings stop naming its mount point. The files a share serves are the operator's
|
|
(ADR 0051): the module mounts them and owns nothing in them.
|
|
|
|
## The unit pair
|
|
|
|
Only the automount is enabled (under `remote-fs.target`; a disk's under `local-fs.target`). The mount
|
|
is never enabled: it is made at the first use of its mount point and released after ten idle minutes
|
|
(`TimeoutIdleSec=600`). So nothing mounts at boot and nothing can fail a boot, and a mount point is always
|
|
an autofs mount, so nothing writes into the empty directory under it.
|
|
|
|
| kind | What | Options | TimeoutSec |
|
|
|---|---|---|---|
|
|
| a node's share, read-write | `<at>:<path>`, `Type=nfs4` | `vers=4.2,hard,timeo=150,retrans=3,_netdev` | 30 |
|
|
| a node's share, read-only | `<at>:<path>`, `Type=nfs4` | `ro,vers=4.2,soft,timeo=150,retrans=3,_netdev` | 30 |
|
|
| an SMB source | `//<host>/<share>`, `Type=cifs` | `credentials=<file>,iocharset=utf8,_netdev,nofail,uid=…,gid=…` | 10 |
|
|
| a disk | `/dev/disk/by-uuid/<uuid>`; the mount `BindsTo=` the disk's device | `nofail` | 10 |
|
|
|
|
A mount of the module's own that failed because its source was not there — an occasional source that is
|
|
off, or a node's share whose server is away, tried when someone opened the mount point — is cleared
|
|
(`systemctl reset-failed`) by `apply` within five seconds, and so is the failure a unit of the same name
|
|
carried before the module wrote it (the unit fstab's generator makes until the line is adopted). The module
|
|
says such a share as `absent` or `unreachable`; left failed, the unit would also be said as a failed unit of
|
|
the machine's own, with a notification each time it is touched. A mount that failed while its source answers
|
|
is left failed: that is a fault, and the share is said `failed`.
|
|
|
|
A share is read-only when the setting says `:ro` or the sharing machine exports it read-only. A
|
|
read-write share is mounted hard, so a write is never dropped while the server is away.
|
|
|
|
## Settings
|
|
|
|
Both are preferences whose default, `none`, mounts nothing (ADR 0262 allows no empty default).
|
|
|
|
- `shares`: space-separated `name=mountpoint`, each optionally `:ro`. The name is the share's on the
|
|
sharing machine; its path there comes from that machine over the bus, never from this setting.
|
|
For example `library=/srv/library downloads=/srv/downloads:ro`.
|
|
- `sources`: space-separated occasional sources, each optionally `:ro`:
|
|
`name=smb://<host>/<share>@<mountpoint>` or `name=disk:<filesystem uuid>@<mountpoint>`.
|
|
For example `games=smb://192.0.2.76/Share@/mnt/games`.
|
|
|
|
A mount point is an absolute, plainly written path, not a directory of the system's own (`/etc`, `/usr`,
|
|
`/run`, …). An entry that cannot be read is said, and only that entry is left out.
|
|
|
|
## The secret
|
|
|
|
`smb-credentials` is the module's own secret, issued by an outside party (the device's owner), so the mesh
|
|
never makes one in its place. The operator gives it with
|
|
`secret accept <node> mounts smb-credentials --from <file>`; the file holds one section per SMB source:
|
|
|
|
```
|
|
[games]
|
|
username=…
|
|
password=…
|
|
domain=… (optional)
|
|
```
|
|
|
|
A source whose section is missing is not mounted, and is said with that remedy. No tool answers a
|
|
password: the options, fstab lines and mountinfo the tools read are redacted.
|
|
|
|
## The processes and the bus
|
|
|
|
- `apply` (root, judged by its unit) writes and removes the unit pairs and the logins, makes a missing
|
|
mount point, reloads the service manager when anything changed and arms every automount, every 30 s.
|
|
- `watch` (root, judged by `mounts_health`) tries each source without touching its mount point — TCP 2049
|
|
for a node's share, 445 for an SMB source, the device for a disk — and says each one's state.
|
|
- The bundle (the operator account) reads what the sharing machine exports from `nfs-server`'s state
|
|
`exports`, keyed by that machine, and leaves it for `apply`; a failed read keeps the last answer. It puts
|
|
what `watch` found in the module's state `shares`, keyed by this machine, with `wants`: each share this
|
|
machine asks of which server and whether read-write or read-only (`[{"server", "share", "access"}]`).
|
|
The server exports a share only to the machines that want it and that it grants, and decides the access
|
|
itself: `apply` mounts a share at the access the server's answer gives this machine (`to[]`), read-only
|
|
when either the share or this machine's grant is, and not at all when the server does not export it
|
|
here (said as failed, naming the grant that is missing). Every five minutes the bundle also asks the controller's `data` verb where the mesh keeps data on
|
|
this machine, and leaves the paths for `apply`; a failed ask keeps the last paths. No module reads
|
|
another's files (ADR 0260).
|
|
|
|
## What it refuses
|
|
|
|
Each refusal is said as the share's state `failed`, with why, and nothing is written for it:
|
|
|
|
- a mount point at, under or above a path where the mesh keeps data on this machine (the controller's
|
|
`data` verb: Plex's library and configuration, a backup repository, an agent's home). Until that list
|
|
has been read once, nothing new is set up; a pair the module already has stays;
|
|
- a mount point the system owns (`/`, `/etc`, `/usr`, `/boot`, `/proc`, `/sys`, `/dev`, `/run` and what
|
|
is under them, and `/var`, `/home`, `/root`, `/tmp` themselves);
|
|
- a mount point that something else is mounted at, or an automount that is not the module's;
|
|
- a folder that holds files: a mount would hide them. Only a folder not in the kernel's mount table is
|
|
opened, so a server that is away cannot hold the look;
|
|
- a share that this machine serves itself.
|
|
|
|
And what it never does:
|
|
|
|
- remove a pair while an entry of `shares` or `sources` cannot be read: nobody can tell which mount point
|
|
the mistyped entry meant, so every pair stays until the settings read again;
|
|
- stop or remove a pair whose mount point has a filesystem mounted that is not the pair's own source; the
|
|
verb `unmount` refuses the same.
|
|
|
|
The states: `armed` (the automount waits), `mounted`, `absent` (an occasional source that is not there —
|
|
a state, not a fault), `unreachable` (should be there and is not), `failed` (tried and refused, or not
|
|
set up; `why` says which).
|
|
|
|
## Health
|
|
|
|
Unhealthy when a share that should always be there has been unreachable or failed for five minutes ("The
|
|
share library of <machine> is not reachable from this machine since 19:21."), when an automount is not
|
|
armed, when something the settings name cannot be set up (a missing login, a unit file that is not the
|
|
module's), or when `watch` has not looked for two minutes. An occasional source that is absent is
|
|
healthy, and said as not present since when.
|
|
|
|
## Taking over a hand-written line
|
|
|
|
The operator's own fstab lines for a share are taken over only through `adopt`, on their word, and only
|
|
once the module's own pair for the same mount point is written and its automount armed: the replacement
|
|
works first, then the line goes. Without `confirm` it is a dry run. With it (and `why`), the line is
|
|
commented out as `# adopted by the mesh (module mounts) on <date>: <the line, any password redacted>`,
|
|
the file as it was is kept as `/etc/fstab.mesh-adopted-<date-time>` readable by root only, and the
|
|
service manager reloads. The module never takes a line over on its own.
|
|
|
|
## What it reads
|
|
|
|
- `/etc/fstab`, every line but swap. A credential in the options (`password=`, `pass=`, `passwd=`) is
|
|
answered as `(redacted)`; a `credentials=` file is named and never opened.
|
|
- The service manager's mount and automount units, with `systemctl list-units` and `systemctl show`:
|
|
state, result, timeout, and whether each was generated from fstab or comes from a unit file. The
|
|
kernel's own filesystems (proc, tmpfs, mqueue and the like) are left out.
|
|
- `/proc/self/mountinfo`, for what is mounted now. A mount point is never opened or statted, so a
|
|
network filesystem whose server is away cannot hang a call.
|
|
- `/etc/exports`, `/etc/exports.d/*.exports` and the kernel's live export table `/var/lib/nfs/etab`.
|
|
- The ZFS `sharenfs` and `sharesmb` properties, where `zfs` is installed.
|
|
- The share sections of `/etc/samba/smb.conf`: path, valid users, read only or writable, force user and
|
|
the like. The `[global]` section and every other setting are left out, so no password or password
|
|
backend is answered.
|
|
|
|
A file that cannot be read, and a command that does not answer, is said under `notes`, never answered
|
|
as empty.
|
|
|
|
## Tools
|
|
|
|
What only root may do (`mount`, `unmount`, `adopt`) goes through `sudo -n`, as the packet filter's and the
|
|
service manager's tools do; a refusal by sudo is said as one.
|
|
|
|
| tool | | answers |
|
|
|---|---|---|
|
|
| `mounts_list` | r | every mount point, its fstab line, its mount and automount units and whether it is mounted now; network filesystems marked; a network mount without automount or nofail said. Narrowed with `network` and `match` |
|
|
| `mounts_exports` | r | the NFS exports declared and live, the ZFS share properties, the Samba shares, and whether nfs-server and smb are active; an export declared and not live, or live and declared nowhere, said |
|
|
| `mounts_health` | r | the health check: healthy or not, with why, one sentence per finding |
|
|
| `node-mounts.list` | r | the machine's mount points, and every share and source the module is asked to mount with its state, since when and why |
|
|
| `node-mounts.test` | r | whether one share's or source's server answers now, tried without touching its mount point |
|
|
| `node-mounts.mount` | a | mount one share or source now |
|
|
| `node-mounts.unmount` | a | release one now; its automount stays armed |
|
|
| `node-mounts.adopt` | a | take over one hand-written fstab line, as above |
|
|
|
|
## Root acts and sudo
|
|
|
|
The tools run as the operator account and act as root through `sudo -n`. The `sudo` module grants that
|
|
account every command, so **this module's code is the only line** between a tool call and root: each act
|
|
checks again what it may touch before it runs a command, and a test holds each check. Narrowing what sudo
|
|
grants the account to the commands these modules need is a separate decision, not made here.
|