package main import ( stdio "git.novox.be/novox/mesh-sdk/go" ) // Tools is the module's tools over one machine. Every one only reads, and none needs root: what only root // may read, the drive reader has read (drives.go, watch.go). func Tools(m *Machine) []stdio.Tool { return []stdio.Tool{ { Name: "sensors_summary", Description: "The condition of this machine's hardware in a few lines: one per finding, flagged CRITICAL, HIGH, FAILING or " + "STOPPED against the hardware's own thresholds (never the mesh's), then one per class — temperatures with the hottest, " + "fans, drives' health, memory and PCIe errors — saying what was read and what the machine does not have. Replaces " + "sensors and smartctl -H. (r)", Run: func(map[string]any) (any, error) { l := m.LookNow() h := l.Health() return map[string]any{"said": l.Said(), "healthy": h.Healthy}, nil }, }, { Name: "sensors_temperatures", Description: "Every temperature the machine reports, in °C: each thermal zone with its trip points, and each hwmon sensor " + "(CPU, GPU, drives, board, network adapters) with its label and its own maximum and critical values. HIGH at its own " + "maximum (or a zone's hot or passive trip), CRITICAL at its own critical value; a sensor that gives no threshold is " + "never flagged, and one that gives no reading is said as not read. Replaces sensors. (r)", Run: func(map[string]any) (any, error) { ts := m.Temperatures() return map[string]any{"temperatures": ts, "count": len(ts)}, nil }, }, { Name: "sensors_fans", Description: "Every fan the machine reports: RPM, the chip's own minimum and alarm where it has them (said in a note, never " + "flagged: a zero-fan GPU is under its minimum by design and a board chip latches its alarm), and whether the " + "module's fan watch saw it turning since the machine started. STOPPED only when it ran and reads 0 while a CPU " + "sensor, a thermal zone or a sensor on its own non-board chip is at or above its own maximum. " + "Replaces sensors. (r)", Run: func(map[string]any) (any, error) { l := m.LookNow() return map[string]any{"fans": l.Fans, "count": len(l.Fans)}, nil }, }, { Name: "sensors_drives", Description: "Each drive's health, as the module's drive reader last read it as root with smartctl (a spinning drive " + "hourly, any other every 10 minutes; a drive in standby is not read, and said as asleep since when): model, serial, size, whether it spins, the overall SMART verdict; for NVMe the critical " + "warning bits, spare, endurance used and media errors; for SATA the reallocated, pending and unreadable sectors, the " + "error log and the last self-test. FAILING when the drive says so, HIGH for the early signs. Replaces smartctl -a " + "and nvme smart-log. (r)", Run: func(map[string]any) (any, error) { ds, note := m.Drives(m.ReadReadings(DrivesPath)) out := map[string]any{"drives": ds, "count": len(ds)} if note != "" { out["note"] = note } return out, nil }, }, { Name: "sensors_faults", Description: "The kernel's counts of hardware errors since the machine started: corrected and uncorrectable memory " + "errors per memory controller and module (EDAC, where the memory has ECC), PCIe errors per device that counted one " + "(AER), and how often an Intel CPU was slowed for heat. A machine without a class has it as not present. Replaces " + "edac-util and reading /sys by hand. (r)", Run: func(map[string]any) (any, error) { return m.Faults(), nil }, }, { Name: "sensors_health", Description: "Whether the hardware is failing, as the module's health check (novox/hq ADR 0256): unhealthy when a " + "CPU, GPU, drive or zone temperature is at or above its own critical value (a board chip's is shown, never judged), " + "a drive says it is failing, a fan that ran reads 0 while a CPU sensor, a thermal zone or its own (non-board) chip is at its own maximum, " + "memory reports an uncorrectable error, or the module's own processes are stale (a file five minutes old, a drive's " + "read stuck, a drive not looked at for twice its cadence); with " + "why, one sentence per finding. HIGH readings, a fan's alarm bit and a fan under its minimum do not make it " + "unhealthy. (r)", Run: func(map[string]any) (any, error) { return m.LookNow().Health(), nil }, }, } }