Fix dashboard image disk usage calculation (#1461)
* fix dashboard image disk usage calculation * preserve image size fallback behavior
This commit is contained in:
1 parent
2a9299f932
commit
560b21e03f
4 files changed
+95
-4
No files matched your search
@@ -0,0 +1,32 @@
|
||||
export interface DockerDiskUsageLike {
|
||||
LayersSize?: unknown;
|
||||
ImageUsage?: {
|
||||
TotalSize?: unknown;
|
||||
} | null;
|
||||
Images?: Array<{
|
||||
Size?: unknown;
|
||||
}> | null;
|
||||
}
|
||||
|
||||
function asNonNegativeFiniteNumber(value: unknown): number | null {
|
||||
return typeof value === 'number' && Number.isFinite(value) && value >= 0
|
||||
? value
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Docker's aggregate image disk usage without double-counting shared layers.
|
||||
*
|
||||
* `Images[].Size` is each image's virtual size (shared + unique), so adding those
|
||||
* values overstates disk usage whenever images share layers. Docker exposes the
|
||||
* deduplicated total as `ImageUsage.TotalSize` in the current API and as
|
||||
* `LayersSize` in the legacy response shape.
|
||||
*/
|
||||
export function getImageDiskUsageTotalSize(
|
||||
diskUsage: DockerDiskUsageLike | null | undefined
|
||||
): number | null {
|
||||
const currentTotal = asNonNegativeFiniteNumber(diskUsage?.ImageUsage?.TotalSize);
|
||||
if (currentTotal !== null) return currentTotal;
|
||||
|
||||
return asNonNegativeFiniteNumber(diskUsage?.LayersSize);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from '$lib/server/docker';
|
||||
import { listComposeStacks } from '$lib/server/stacks';
|
||||
import { countLivePending } from '$lib/server/pending-updates-core';
|
||||
import { getImageDiskUsageTotalSize } from '$lib/server/docker-disk-usage-core';
|
||||
import { authorize } from '$lib/server/authorize';
|
||||
import { parseLabels } from '$lib/utils/label-colors';
|
||||
|
||||
@@ -239,9 +240,11 @@ export const GET: RequestHandler = async ({ cookies, url }) => {
|
||||
|
||||
// Process disk usage from /system/df for accurate size data
|
||||
if (diskUsage) {
|
||||
// Images: use Size from /system/df
|
||||
// Images: use Docker's aggregate size so shared layers are counted once
|
||||
envStats.images.total = diskUsage.Images?.length || images.length;
|
||||
envStats.images.totalSize = diskUsage.Images?.reduce((sum: number, img: any) => sum + getValidSize(img.Size), 0) || 0;
|
||||
envStats.images.totalSize = getImageDiskUsageTotalSize(diskUsage)
|
||||
?? diskUsage.Images?.reduce((sum: number, img: any) => sum + getValidSize(img.Size), 0)
|
||||
?? 0;
|
||||
|
||||
// Volumes: use UsageData.Size from /system/df
|
||||
envStats.volumes.total = diskUsage.Volumes?.length || volumes.length;
|
||||
|
||||
@@ -26,6 +26,7 @@ import { prefersJSON, sseToJSON } from '$lib/server/sse';
|
||||
import type { EnvironmentStats } from '../+server';
|
||||
import { parseLabels } from '$lib/utils/label-colors';
|
||||
import { isEdgeConnected } from '$lib/server/hawser';
|
||||
import { getImageDiskUsageTotalSize } from '$lib/server/docker-disk-usage-core';
|
||||
|
||||
|
||||
// Skip disk usage collection (Synology NAS performance fix)
|
||||
@@ -434,9 +435,11 @@ async function getEnvironmentStatsProgressive(
|
||||
: getCachedDiskUsage(env.id)
|
||||
.then((diskUsage) => {
|
||||
if (diskUsage) {
|
||||
// Update images with disk usage data (more accurate)
|
||||
// Update images with Docker's deduplicated aggregate size
|
||||
envStats.images.total = diskUsage.Images?.length || envStats.images.total;
|
||||
envStats.images.totalSize = diskUsage.Images?.reduce((sum: number, img: any) => sum + getValidSize(img.Size), 0) || envStats.images.totalSize;
|
||||
envStats.images.totalSize = getImageDiskUsageTotalSize(diskUsage)
|
||||
?? diskUsage.Images?.reduce((sum: number, img: any) => sum + getValidSize(img.Size), 0)
|
||||
?? envStats.images.totalSize;
|
||||
|
||||
// Volumes from disk usage
|
||||
envStats.volumes.total = diskUsage.Volumes?.length || 0;
|
||||
|
||||
Reference in new issue
Block a user