Fix Windows VM disk accumulation bug by normalizing drive letters

Related to #656

Windows guest agents can return multiple directory mountpoints (C:\, C:\Users,
C:\Windows) all on the same physical drive. When the QEMU guest agent omits
disk[] metadata, commit 5325ef481 falls back to using the mountpoint string
as the disk identifier. This causes every Windows directory to be treated as
a separate disk, accumulating to inflated totals (e.g., 1TB reported for a
250GB drive).

Root cause:
The fallback logic in pkg/proxmox/client.go:1585-1594 assigns fs.Disk =
fs.Mountpoint when disk[] is missing. On Windows, every directory path is
unique, so the deduplication guard in internal/monitoring/monitor_polling.go:
619-635 never triggers, causing all directories to be summed.

Changes:
- Detect Windows-style mountpoints (drive letter + colon + backslash)
- Normalize to drive root when disk[] is missing (e.g., C:\Users → C:)
- Preserve existing behavior for Linux/BSD and VMs with disk[] metadata
- Add debug logging for synthesized Windows drive identifiers

This fix maintains backward compatibility with commit 5325ef481 while
preventing the Windows directory accumulation issue. LXC containers are
unaffected as they use a different code path.
This commit is contained in:
rcourtman 2025-11-07 12:27:11 +00:00
parent 32e0d453c4
commit 9199892115

View file

@ -1588,8 +1588,24 @@ func (c *Client) GetVMFSInfo(ctx context.Context, node string, vmid int) ([]VMFi
if fs.Mountpoint == "/" {
fs.Disk = "root-filesystem"
} else {
// Use mountpoint as unique identifier
fs.Disk = fs.Mountpoint
// For Windows, normalize drive letters to prevent duplicate counting
// Windows guest agent can return multiple directory entries (C:\, C:\Users, C:\Windows)
// all on the same physical drive. Without disk[] metadata, we must deduplicate by drive letter.
isWindowsDrive := len(fs.Mountpoint) >= 2 && fs.Mountpoint[1] == ':' && strings.Contains(fs.Mountpoint, "\\")
if isWindowsDrive {
// Use drive letter as identifier (e.g., "C:" for C:\, C:\Users, etc.)
driveLetter := strings.ToUpper(fs.Mountpoint[:2])
fs.Disk = driveLetter
log.Debug().
Str("node", node).
Int("vmid", vmid).
Str("mountpoint", fs.Mountpoint).
Str("synthesized_disk", driveLetter).
Msg("Synthesized Windows drive identifier from mountpoint")
} else {
// Use mountpoint as unique identifier for non-Windows paths
fs.Disk = fs.Mountpoint
}
}
}
}