The second review of #129 found a read stuck in the kernel kept the file fresh and the module healthy, smartd as a second reader could wake or keep awake the drives the watch spares, and a board chip's maximum could stop a fan. Read each drive in its own goroutine from a root reader of the module's own, mark each read in flight, and say a read past its bound or a drive not looked at for twice its cadence; drop smartd; tell smartctl each drive's kind; take a SAS drive's standby; say a drive asleep since when.
46 lines
1.4 KiB
Go
46 lines
1.4 KiB
Go
// The sensors module's Go bundle (novox/hq ADR 0256): the condition of a machine's own hardware —
|
|
// temperatures with their own thresholds, fans, each drive's health, the kernel's counts of hardware
|
|
// errors — read from /sys and /proc, and changing nothing.
|
|
//
|
|
// One binary, two ways to run. With no argument it is the bundle the node's tool runner launches and
|
|
// speaks MCP to over stdio (ADR 0188, ADR 0193), as the operator account. With `watch` and `drives` it is
|
|
// one of the module's two long-running processes, run by the node-engine as root: the fan watch, and the
|
|
// drive reader (watch.go).
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) > 1 {
|
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt)
|
|
defer stop()
|
|
switch os.Args[1] {
|
|
case "watch":
|
|
w := NewFanWatch(Here())
|
|
every(ctx, "watch", w.Look)
|
|
case "drives":
|
|
r := NewDriveReader(Here())
|
|
r.Async = true
|
|
every(ctx, "drives", r.Look)
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "sensors: %q is not a way to run; with no argument it serves its tools, with watch it "+
|
|
"watches the fans, with drives it reads the drives\n", os.Args[1])
|
|
os.Exit(2)
|
|
}
|
|
return
|
|
}
|
|
// An empty name serves as the module the runtime names (MESH_SERVED_MODULE): sensors.
|
|
if err := stdio.Serve("", Tools(Here())); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|