From 3865fd7d10d76cd265800fd8d5915a5792be4619 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 19 Oct 2026 21:20:00 +0200 Subject: Dashboard: VM meters and sparklines, slackpkg tile sbb-remote 0.3.0 adds CPU busy % (two /proc/stat samples), RAM total and available, disk / total and free, and the last slackpkg update (LASTUPDATE) and package change (/var/log/packages), replacing disk_free. The Dashboard shows a VM card with meters for CPU, RAM and disk / (accent, warning from 80%, critical from 90%, value always printed) and CPU/RAM sparklines from this session's polls, and a slackpkg tile in place of VM load. Co-Authored-By: Claude Opus 5.5 --- remote/sbb-remote | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'remote') diff --git a/remote/sbb-remote b/remote/sbb-remote index b26fa9f..d82120a 100755 --- a/remote/sbb-remote +++ b/remote/sbb-remote @@ -38,7 +38,7 @@ import tempfile import time import tomllib -VERSION = "0.2.0" +VERSION = "0.3.0" DEFAULTS = { "state_dir": "/var/lib/sb-builder", "repo_dir": "/var/lib/sbopkg/SBo-danix", @@ -358,12 +358,50 @@ def _uptime(): return float(f.read().split()[0]) +def _cpu_times(path="/proc/stat"): + """(busy, total) jiffies over all CPUs; idle and iowait are not busy.""" + with open(path) as f: + fields = [int(x) for x in f.readline().split()[1:]] + total = sum(fields[:8]) # guest time is already in user/nice + return total - fields[3] - fields[4], total + + +def _cpu(): + """Busy percent over a short sample.""" + b1, t1 = _cpu_times() + time.sleep(0.25) + b2, t2 = _cpu_times() + return round(100 * (b2 - b1) / max(t2 - t1, 1), 1) + + +def _meminfo(path="/proc/meminfo"): + with open(path) as f: + kb = {k: int(v.split()[0]) for k, v in (line.split(":", 1) for line in f)} + return {"total": kb["MemTotal"] * 1024, "available": kb["MemAvailable"] * 1024} + + +def _slackpkg(lastupdate="/var/lib/slackpkg/LASTUPDATE", pkgdir="/var/log/packages"): + """Last 'slackpkg update' (its LASTUPDATE stamp) and last package change.""" + def update(): + with open(lastupdate) as f: + return int(f.read().split()[0]) + + def upgrade(): + # ponytail: newest package entry; slackrepo INSTALL=n, so this is slackpkg's + with os.scandir(pkgdir) as it: + return int(max(e.stat().st_mtime for e in it)) + return {"update": _try(update), "upgrade": _try(upgrade)} + + def cmd_stats(cfg): - dirs = {"repo": cfg["repo_dir"], "state": cfg["state_dir"]} + root = _try(lambda: shutil.disk_usage("/")) return { "load": _try(os.getloadavg), "uptime": _try(_uptime), - "disk_free": {k: _try(lambda p=p: shutil.disk_usage(p).free) for k, p in dirs.items()}, + "cpu": _try(_cpu), + "mem": _try(_meminfo), + "disk": {"total": root and root.total, "free": root and root.free}, + "slackpkg": _slackpkg(), "packages": _try(lambda: _packages(cfg)), "sync": {o: _try(lambda o=o: int(_git(cfg, "log", "-1", "--format=%ct", "--", o + "/"))) for o in cfg["overlays"]}, -- cgit v1.2.3