From 87620f32511fecc99fc0e46bb30f618a3f52b19c Mon Sep 17 00:00:00 2001 From: Sven van Ginkel Date: Sun, 30 Aug 2026 19:09:04 +0200 Subject: [PATCH] feat(hub/agent): alphabetical disk ordering and root disk renaming (#2006) --- agent/agent.go | 8 +++++- agent/disk.go | 25 +++++++++++-------- agent/disk_test.go | 21 +++++++--------- internal/entities/system/system.go | 1 + .../routes/system/charts/disk-charts.tsx | 14 +++++++---- .../systems-table/systems-table-columns.tsx | 8 +++--- internal/site/src/types.d.ts | 2 ++ 7 files changed, 46 insertions(+), 33 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index e181aac6..0dd8638e 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -193,7 +193,13 @@ func (a *Agent) gatherStats(options common.DataRequestOptions) *system.CombinedD data.Stats.ExtraFs = make(map[string]*system.FsStats) data.Info.ExtraFsPct = make(map[string]float64) for name, stats := range a.fsStats { - if !stats.Root && stats.DiskTotal > 0 { + if stats.Root { + if stats.Name != "" { + data.Info.RootDiskName = stats.Name + } + continue + } + if stats.DiskTotal > 0 { // Use custom name if available, otherwise use device name key := name if stats.Name != "" { diff --git a/agent/disk.go b/agent/disk.go index 069fb3cb..4a5d1cdf 100644 --- a/agent/disk.go +++ b/agent/disk.go @@ -18,10 +18,11 @@ import ( // fsRegistrationContext holds the shared lookup state needed to resolve a // filesystem into the tracked fsStats key and metadata. type fsRegistrationContext struct { - filesystem string // value of optional FILESYSTEM env var - isWindows bool - efPath string // path to extra filesystems (default "/extra-filesystems") - diskIoCounters map[string]disk.IOCountersStat + filesystem string // device part of optional FILESYSTEM env var + filesystemName string // optional custom name from FILESYSTEM=device__name + isWindows bool + efPath string // path to extra filesystems (default "/extra-filesystems") + diskIoCounters map[string]disk.IOCountersStat } // diskDiscovery groups the transient state for a single initializeDiskInfo run so @@ -177,7 +178,7 @@ func (d *diskDiscovery) addConfiguredRootFs() bool { for _, p := range d.partitions { if filesystemMatchesPartitionSetting(d.ctx.filesystem, p) { - d.addFsStat(p.Device, p.Mountpoint, true, "") + d.addFsStat(p.Device, p.Mountpoint, true, d.ctx.filesystemName) return true } } @@ -185,7 +186,7 @@ func (d *diskDiscovery) addConfiguredRootFs() bool { // FILESYSTEM may name a physical disk absent from partitions (e.g. ZFS lists // dataset paths like zroot/ROOT/default, not block devices). if ioKey, match := findIoDevice(d.ctx.filesystem, d.ctx.diskIoCounters); match { - d.agent.fsStats[ioKey] = &system.FsStats{Root: true, Mountpoint: d.rootMountPoint} + d.agent.fsStats[ioKey] = &system.FsStats{Root: true, Mountpoint: d.rootMountPoint, Name: d.ctx.filesystemName} return true } @@ -300,7 +301,8 @@ func (d *diskDiscovery) addExtraFilesystemFolders(folderNames []string) { // Sets up the filesystems to monitor for disk usage and I/O. func (a *Agent) initializeDiskInfo() { - filesystem, _ := utils.GetEnv("FILESYSTEM") + filesystemRaw, _ := utils.GetEnv("FILESYSTEM") + filesystem, filesystemName := parseFilesystemEntry(filesystemRaw) hasRoot := false isWindows := runtime.GOOS == "windows" @@ -323,10 +325,11 @@ func (a *Agent) initializeDiskInfo() { } slog.Debug("Disk I/O", "diskstats", diskIoCounters) ctx := fsRegistrationContext{ - filesystem: filesystem, - isWindows: isWindows, - diskIoCounters: diskIoCounters, - efPath: "/extra-filesystems", + filesystem: filesystem, + filesystemName: filesystemName, + isWindows: isWindows, + diskIoCounters: diskIoCounters, + efPath: "/extra-filesystems", } // Get the appropriate root mount point for this system diff --git a/agent/disk_test.go b/agent/disk_test.go index e729bf02..9e8b3d2b 100644 --- a/agent/disk_test.go +++ b/agent/disk_test.go @@ -78,14 +78,7 @@ func TestParseFilesystemEntry(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - fsEntry := strings.TrimSpace(tt.input) - var fs, customName string - if parts := strings.SplitN(fsEntry, "__", 2); len(parts) == 2 { - fs = strings.TrimSpace(parts[0]) - customName = strings.TrimSpace(parts[1]) - } else { - fs = fsEntry - } + fs, customName := parseFilesystemEntry(tt.input) assert.Equal(t, tt.expectedFs, fs) assert.Equal(t, tt.expectedName, customName) @@ -287,8 +280,9 @@ func TestAddConfiguredRootFs(t *testing.T) { rootMountPoint: "/", partitions: []disk.PartitionStat{{Device: "/dev/ada0p2", Mountpoint: "/"}}, ctx: fsRegistrationContext{ - filesystem: "/dev/ada0p2", - isWindows: false, + filesystem: "/dev/ada0p2", + filesystemName: "root disk", + isWindows: false, diskIoCounters: map[string]disk.IOCountersStat{ "ada0": {Name: "ada0", ReadBytes: 1000, WriteBytes: 1000}, }, @@ -302,6 +296,7 @@ func TestAddConfiguredRootFs(t *testing.T) { assert.True(t, exists) assert.True(t, stats.Root) assert.Equal(t, "/", stats.Mountpoint) + assert.Equal(t, "root disk", stats.Name) }) t.Run("adds root from io device when partition is missing", func(t *testing.T) { @@ -310,8 +305,9 @@ func TestAddConfiguredRootFs(t *testing.T) { agent: agent, rootMountPoint: "/sysroot", ctx: fsRegistrationContext{ - filesystem: "zroot", - isWindows: false, + filesystem: "zroot", + filesystemName: "root pool", + isWindows: false, diskIoCounters: map[string]disk.IOCountersStat{ "nda0": {Name: "nda0", Label: "zroot", ReadBytes: 1000, WriteBytes: 1000}, }, @@ -325,6 +321,7 @@ func TestAddConfiguredRootFs(t *testing.T) { assert.True(t, exists) assert.True(t, stats.Root) assert.Equal(t, "/sysroot", stats.Mountpoint) + assert.Equal(t, "root pool", stats.Name) }) t.Run("returns false when filesystem cannot be resolved", func(t *testing.T) { diff --git a/internal/entities/system/system.go b/internal/entities/system/system.go index 996c66df..9091aea0 100644 --- a/internal/entities/system/system.go +++ b/internal/entities/system/system.go @@ -157,6 +157,7 @@ type Info struct { ExtraFsPct map[string]float64 `json:"efs,omitempty" cbor:"21,keyasint,omitempty"` Services []uint16 `json:"sv,omitempty" cbor:"22,keyasint,omitempty"` // [totalServices, numFailedServices] Battery [2]uint8 `json:"bat,omitzero" cbor:"23,keyasint,omitzero"` // [percent, charge state] + RootDiskName string `json:"rdn,omitempty" cbor:"24,keyasint,omitempty"` // custom name for root disk (set via FILESYSTEM=device__name) } // Data that does not change during process lifetime and is not needed in All Systems table diff --git a/internal/site/src/components/routes/system/charts/disk-charts.tsx b/internal/site/src/components/routes/system/charts/disk-charts.tsx index dff757b1..75d5e8ed 100644 --- a/internal/site/src/components/routes/system/charts/disk-charts.tsx +++ b/internal/site/src/components/routes/system/charts/disk-charts.tsx @@ -114,8 +114,10 @@ export function DiskUsageChart({ systemData, extraFsName }: { systemData: System diskSize = Math.round(diskSize) } - const title = extraFsName ? `${extraFsName} ${t`Usage`}` : t`Disk Usage` - const description = extraFsName ? t`Disk usage of ${extraFsName}` : t`Usage of root partition` + const rootName = systemData.system?.info?.rdn + const rootLabel = rootName ?? t`Root` + const title = extraFsName ? `${extraFsName} ${t`Usage`}` : `${rootLabel} ${t`Usage`}` + const description = extraFsName ? t`Disk usage of ${extraFsName}` : t`Disk usage of ${rootLabel}` return ( @@ -152,8 +154,10 @@ export function DiskIOChart({ systemData, extraFsName }: { systemData: SystemDat return null } - const title = extraFsName ? `${extraFsName} I/O` : t`Disk I/O` - const description = extraFsName ? t`Throughput of ${extraFsName}` : t`Throughput of root filesystem` + const rootName = systemData.system?.info?.rdn + const rootLabel = rootName ?? t`Root` + const title = extraFsName ? `${extraFsName} I/O` : `${rootLabel} I/O` + const description = extraFsName ? t`Throughput of ${extraFsName}` : t`Throughput of ${rootLabel}` const hasMoreIOMetrics = chartData.systemStats?.some((record) => record.stats?.dios?.at(0)) @@ -264,7 +268,7 @@ export function ExtraFsCharts({ systemData }: { systemData: SystemData }) { return (
- {Object.keys(extraFs).map((extraFsName) => { + {Object.keys(extraFs).sort((a, b) => a.localeCompare(b)).map((extraFsName) => { let diskSize = systemStats.at(-1)?.stats.efs?.[extraFsName].d ?? NaN // round to nearest GB if (diskSize >= 100) { diff --git a/internal/site/src/components/systems-table/systems-table-columns.tsx b/internal/site/src/components/systems-table/systems-table-columns.tsx index c19b17e8..49e0000b 100644 --- a/internal/site/src/components/systems-table/systems-table-columns.tsx +++ b/internal/site/src/components/systems-table/systems-table-columns.tsx @@ -484,9 +484,9 @@ function DiskCellWithMultiple(info: CellContext) { const { info: sysInfo, status, id } = info.row.original const extraFs = Object.entries(sysInfo.efs ?? {}) const rootDiskPct = sysInfo.dp + const rootDiskName = sysInfo.rdn - // sort extra disks by percentage descending - extraFs.sort((a, b) => b[1] - a[1]) + extraFs.sort((a, b) => a[0].localeCompare(b[0])) function getIndicatorColor(pct: number) { const threshold = getMeterStateByThresholds(pct, colorWarn, colorCrit) @@ -541,8 +541,8 @@ function DiskCellWithMultiple(info: CellContext) {
-
- Root +
+ {rootDiskName ?? Root}
{decimalString(rootDiskPct, rootDiskPct >= 10 ? 1 : 2)}% diff --git a/internal/site/src/types.d.ts b/internal/site/src/types.d.ts index a0a8350d..cbb1ce9a 100644 --- a/internal/site/src/types.d.ts +++ b/internal/site/src/types.d.ts @@ -78,6 +78,8 @@ export interface SystemInfo { efs?: Record /** services [totalServices, numFailedServices] */ sv?: [number, number] + /** custom root disk name */ + rdn?: string } export interface SystemStats {