mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group fix/shares-review-followups delivered: every member is delivered
100 lines
6.3 KiB
Go
100 lines
6.3 KiB
Go
package catalogue
|
|
|
|
// A machine's shares, and the shares a machine mounts (novox/hq ADR 0263).
|
|
//
|
|
// **Two roles, one per side of the wire.** A machine that shares a directory with the mesh does it
|
|
// through the holder of `node-nfs-server`: it writes the machine's export file, runs the NFS service,
|
|
// opens its port to the private network only, and provides each share as the provision `nfs-share`. A
|
|
// machine that wants the files gets them through the holder of `node-mounts`: it writes a mount unit and
|
|
// an automount unit per share, so nothing mounts at boot and nothing can fail a boot, and it says a
|
|
// device that comes and goes is absent rather than failed.
|
|
//
|
|
// **One holder per machine on each side.** Two modules writing one machine's export file, or two writing
|
|
// mount units for one mount point, is the conflict a seat exists to refuse. Both seats deliver nothing:
|
|
// `nfs-share` is provided at the mesh's scope, by the module holding `node-nfs-server` on the machine that
|
|
// shares, and a seat at a node's scope cannot be the answer for a provision at the mesh's.
|
|
//
|
|
// **The data is the operator's** (ADR 0051). Neither holder creates, chowns or removes anything under a
|
|
// shared path; the export maps every client to the path's owner, so no client acts as another account on
|
|
// the server. Their verbs read, and the ones that act take over what a person wrote by hand only on a
|
|
// person's word: a dataset's export property, an fstab line.
|
|
|
|
// NFSServerSeat is the role of the machine that shares directories over NFS (novox/hq ADR 0263).
|
|
const NFSServerSeat = "node-nfs-server"
|
|
|
|
// MountsSeat is the role that mounts a machine's shares and occasional sources (novox/hq ADR 0263).
|
|
const MountsSeat = "node-mounts"
|
|
|
|
// nfsServerVerbs is the contract every holder of node-nfs-server serves (novox/hq ADR 0263).
|
|
func nfsServerVerbs() []Verb {
|
|
return []Verb{
|
|
{Name: "exports", Description: "Every share this machine exports: its name, its path, read-write or " +
|
|
"read-only, the owner every client is mapped to (uid and gid), each node it is exported to with that " +
|
|
"node's private address and access (only the nodes the server grants it to and that ask for it), " +
|
|
"what is granted and not asked for or asked for and not granted, and whether the kernel holds it " +
|
|
"now. Also the exports found that are not the mesh's: a dataset's sharenfs property, a line in " +
|
|
"/etc/exports.",
|
|
Input: schema(map[string]string{}, nil),
|
|
Replaces: []string{"exportfs -v", "cat /etc/exports", "zfs get sharenfs"}},
|
|
{Name: "clients", Description: "Which machines have mounted which share now, as the NFS server " +
|
|
"knows its clients.",
|
|
Input: schema(map[string]string{}, nil),
|
|
Replaces: []string{"ss -tn sport = :2049", "cat /proc/fs/nfsd/clients/*/info"}},
|
|
{Name: "test", Description: "Whether this machine exports one share for the mesh now, and whether its " +
|
|
"NFS service is up; with an address, also whether the share is exported to that address: a node's " +
|
|
"own private address, when the server grants it the share and the node asks for it. What a machine " +
|
|
"mounting the share asks before it mounts.",
|
|
Input: schema(map[string]string{
|
|
"share": "the share, by its name",
|
|
"address": "a node's private address, to ask whether the share is exported to it (optional)",
|
|
}, []string{"share"}),
|
|
Replaces: []string{"showmount -e"}},
|
|
{Name: "reload", Description: "Have the kernel read this machine's export files again now (exportfs " +
|
|
"-ra) and answer the shares as it then holds them. The module's own process writes its export " +
|
|
"file; this is for after a change made outside it. Changes no shared path.",
|
|
Input: schema(map[string]string{}, nil),
|
|
Replaces: []string{"exportfs -ra"}},
|
|
{Name: "adopt", Description: "Take over an export a person made by hand: clear a dataset's sharenfs " +
|
|
"property for a path the mesh's own export now serves — only when that export is live. Without " +
|
|
"confirm, says what it would do and changes nothing.",
|
|
Input: schema(map[string]string{
|
|
"path": "the shared path whose hand-made export is taken over",
|
|
"confirm": "\"true\": change it (needs why); anything else is a dry run",
|
|
"why": "why, for the record",
|
|
}, []string{"path"}, "confirm"),
|
|
Replaces: []string{"zfs set sharenfs=off"}},
|
|
}
|
|
}
|
|
|
|
// mountsVerbs is the contract every holder of node-mounts serves (novox/hq ADR 0263).
|
|
func mountsVerbs() []Verb {
|
|
return []Verb{
|
|
{Name: "list", Description: "Every mount point on this machine: its fstab line, the mesh's mount and " +
|
|
"automount units for it, its state (armed, mounted, absent, unreachable, failed) and since when, " +
|
|
"and which settings asked for it. A password in a mount's options is never shown.",
|
|
Input: schema(map[string]string{}, nil),
|
|
Replaces: []string{"cat /etc/fstab", "findmnt", "systemctl list-units --type=mount"}},
|
|
{Name: "test", Description: "Whether one share's or occasional source's server answers from this " +
|
|
"machine now, without touching its mount point.",
|
|
Input: schema(map[string]string{"name": "the share or source, by its name"}, []string{"name"}),
|
|
Replaces: []string{"showmount -e", "ping"}},
|
|
{Name: "mount", Description: "Mount one share or occasional source now, rather than at its first " +
|
|
"access.",
|
|
Input: schema(map[string]string{"name": "the share or source, by its name"}, []string{"name"}),
|
|
Replaces: []string{"mount"}},
|
|
{Name: "unmount", Description: "Release one share or occasional source now; its automount stays " +
|
|
"armed, so the next access mounts it again.",
|
|
Input: schema(map[string]string{"name": "the share or source, by its name"}, []string{"name"}),
|
|
Replaces: []string{"umount"}},
|
|
{Name: "adopt", Description: "Take over a mount a person wrote by hand: comment out the /etc/fstab " +
|
|
"line for a mount point the mesh's own units now serve, keeping a copy of the file — only when " +
|
|
"the mesh's automount for it is armed. Without confirm, says what it would do and changes nothing.",
|
|
Input: schema(map[string]string{
|
|
"mountpoint": "the mount point whose fstab line is taken over",
|
|
"confirm": "\"true\": change it (needs why); anything else is a dry run",
|
|
"why": "why, for the record",
|
|
}, []string{"mountpoint"}, "confirm"),
|
|
Replaces: []string{"sed -i /etc/fstab"}},
|
|
}
|
|
}
|