diff --git a/internal/hostmetrics/collector.go b/internal/hostmetrics/collector.go index d0e4efa4b..2be3d7a9a 100644 --- a/internal/hostmetrics/collector.go +++ b/internal/hostmetrics/collector.go @@ -412,12 +412,13 @@ func collectDiskIO(ctx context.Context, diskExclude []string) []agentshost.DiskI if isPartition(name) { continue } - // Skip loop devices and ram disks - if strings.HasPrefix(name, "loop") || strings.HasPrefix(name, "ram") { - continue - } - // Skip device-mapper and md devices (report at physical level) - if strings.HasPrefix(name, "dm-") { + // Skip virtual/pseudo block devices (loop, ram, dm-, md, zvols, + // zram, nbd, rbd, drbd, ...). ZFS-backed Proxmox hosts expose one + // zd device per zvol, so without this a host with a few hundred + // guests reports a few hundred phantom disks on every collection + // cycle (issue #1671). The prefix list is shared with SMART + // collection and the server-side resource registry. + if fsfilters.IsVirtualBlockDevice(name) { continue } // Skip user-excluded devices (issue #1142) diff --git a/internal/hostmetrics/coverage_additional_test.go b/internal/hostmetrics/coverage_additional_test.go index ca2632f4f..9b318e2f0 100644 --- a/internal/hostmetrics/coverage_additional_test.go +++ b/internal/hostmetrics/coverage_additional_test.go @@ -189,20 +189,30 @@ func TestCollectDiskIOFiltersAndError(t *testing.T) { "ram0": {ReadBytes: 7}, "dm-0": {ReadBytes: 8}, "sdb": {ReadBytes: 9}, - "md0": {ReadBytes: 10}, + // Aggregate virtual devices whose counters restate the I/O of + // the physical members underneath them. + "md0": {ReadBytes: 10}, + // ZFS zvols. A Proxmox host with ZFS-backed guest storage + // exposes one of these per zvol (issue #1671). + "zd0": {ReadBytes: 11}, + "zd16": {ReadBytes: 12}, + "zd160": {ReadBytes: 13}, + "zram0": {ReadBytes: 14}, + "nbd0": {ReadBytes: 15}, + "rbd0": {ReadBytes: 16}, }, nil } disks := collectDiskIO(context.Background(), []string{"sdb"}) - if len(disks) != 3 { - t.Fatalf("expected 3 disk I/O entries after filtering, got %d: %+v", len(disks), disks) + if len(disks) != 2 { + t.Fatalf("expected 2 disk I/O entries after filtering, got %d: %+v", len(disks), disks) } gotDevices := make([]string, 0, len(disks)) for _, disk := range disks { gotDevices = append(gotDevices, disk.Device) } - wantDevices := []string{"md0", "nvme0n1", "sda"} + wantDevices := []string{"nvme0n1", "sda"} if !reflect.DeepEqual(gotDevices, wantDevices) { t.Fatalf("unexpected disk I/O devices: got %v, want %v", gotDevices, wantDevices) }