diff --git a/admin/inertia/hooks/useDiskDisplayData.ts b/admin/inertia/hooks/useDiskDisplayData.ts index 1d8b15d..710ed62 100644 --- a/admin/inertia/hooks/useDiskDisplayData.ts +++ b/admin/inertia/hooks/useDiskDisplayData.ts @@ -19,16 +19,36 @@ export function getAllDiskDisplayItems( ): DiskDisplayItem[] { const validDisks = disks?.filter((d) => d.totalSize > 0) || [] + // If /app/storage is on a dedicated filesystem (e.g. NFS), it won't appear + // in the block-device list. Prepend it so NAS and OS disk are both shown. + const storageMount = fsSize?.find((fs) => fs.mount === '/app/storage' && fs.size > 0) + const storageMountItem: DiskDisplayItem[] = storageMount + ? [ + { + label: 'NAS Storage', + value: storageMount.use || 0, + total: formatBytes(storageMount.size), + used: formatBytes(storageMount.used), + subtext: `${formatBytes(storageMount.used)} / ${formatBytes(storageMount.size)}`, + totalBytes: storageMount.size, + usedBytes: storageMount.used, + }, + ] + : [] + if (validDisks.length > 0) { - return validDisks.map((disk) => ({ - label: disk.name || 'Unknown', - value: disk.percentUsed || 0, - total: formatBytes(disk.totalSize), - used: formatBytes(disk.totalUsed), - subtext: `${formatBytes(disk.totalUsed || 0)} / ${formatBytes(disk.totalSize || 0)}`, - totalBytes: disk.totalSize, - usedBytes: disk.totalUsed, - })) + return [ + ...storageMountItem, + ...validDisks.map((disk) => ({ + label: disk.name || 'Unknown', + value: disk.percentUsed || 0, + total: formatBytes(disk.totalSize), + used: formatBytes(disk.totalUsed), + subtext: `${formatBytes(disk.totalUsed || 0)} / ${formatBytes(disk.totalSize || 0)}`, + totalBytes: disk.totalSize, + usedBytes: disk.totalUsed, + })), + ] } if (fsSize && fsSize.length > 0) { @@ -59,6 +79,15 @@ export function getPrimaryDiskInfo( disks: NomadDiskInfo[] | undefined, fsSize: Systeminformation.FsSizeData[] | undefined ): { totalSize: number; totalUsed: number } | null { + // First, check if /app/storage is on a dedicated filesystem (e.g. NFS mount). + // This is the most accurate source since it reflects the actual backing + // store for NOMAD content, regardless of whether it's a local disk or + // network-attached storage. + const storageMount = fsSize?.find((fs) => fs.mount === '/app/storage' && fs.size > 0) + if (storageMount) { + return { totalSize: storageMount.size, totalUsed: storageMount.used } + } + const validDisks = disks?.filter((d) => d.totalSize > 0) || [] if (validDisks.length > 0) { const diskWithRoot = validDisks.find((d) => diff --git a/install/sidecar-disk-collector/collect-disk-info.sh b/install/sidecar-disk-collector/collect-disk-info.sh index 7705175..2a4a5c6 100755 --- a/install/sidecar-disk-collector/collect-disk-info.sh +++ b/install/sidecar-disk-collector/collect-disk-info.sh @@ -44,7 +44,9 @@ while true; do # These are not real filesystem roots and report misleading sizes [[ -f "/host${mountpoint}" ]] && continue - STATS=$(df -B1 "/host${mountpoint}" 2>/dev/null | awk 'NR==2{print $2,$3,$4,$5}') + # Use -P (POSIX) to force single-line output even when device names + # are long (e.g. NFS mounts), which otherwise wrap across two lines + STATS=$(df -P -B1 "/host${mountpoint}" 2>/dev/null | awk 'NR==2{print $2,$3,$4,$5}') [[ -z "$STATS" ]] && continue read -r size used avail pct <<< "$STATS" @@ -60,7 +62,7 @@ while true; do # The disk-collector container always has /storage bind-mounted from the host, # so df on /storage reflects the actual backing device and its capacity. if [[ "$FIRST" -eq 1 ]] && mountpoint -q /storage 2>/dev/null; then - STATS=$(df -B1 /storage 2>/dev/null | awk 'NR==2{print $1,$2,$3,$4,$5}') + STATS=$(df -P -B1 /storage 2>/dev/null | awk 'NR==2{print $1,$2,$3,$4,$5}') if [[ -n "$STATS" ]]; then read -r dev size used avail pct <<< "$STATS" pct="${pct/\%/}"