diff --git a/collector/infiniband_linux.go b/collector/infiniband_linux.go index fb83c152a6..4a966e77f9 100644 --- a/collector/infiniband_linux.go +++ b/collector/infiniband_linux.go @@ -158,20 +158,25 @@ func (c *infinibandCollector) pushCounter(ch chan<- prometheus.Metric, name stri } func (c *infinibandCollector) Update(ch chan<- prometheus.Metric) error { - devices, err := c.fs.InfiniBandClass() + deviceNames, err := c.fs.InfiniBandClassDevices() if err != nil { if errors.Is(err, os.ErrNotExist) { c.logger.Debug("infiniband statistics not found, skipping") return ErrNoData } - return fmt.Errorf("error obtaining InfiniBand class info: %w", err) + return fmt.Errorf("error obtaining InfiniBand device list: %w", err) } - for _, device := range devices { - if c.deviceFilter.ignored(device.Name) { + for _, name := range deviceNames { + if c.deviceFilter.ignored(name) { continue } + device, err := c.fs.InfiniBandDevice(name) + if err != nil { + return fmt.Errorf("error obtaining InfiniBand device %q info: %w", name, err) + } + infoDesc := prometheus.NewDesc( prometheus.BuildFQName(namespace, c.subsystem, "info"), "Non-numeric data from /sys/class/infiniband/, value is always 1.", diff --git a/collector/infiniband_linux_test.go b/collector/infiniband_linux_test.go new file mode 100644 index 0000000000..19c6d45527 --- /dev/null +++ b/collector/infiniband_linux_test.go @@ -0,0 +1,68 @@ +// Copyright 2026 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !noinfiniband + +package collector + +import ( + "io" + "log/slog" + "os" + "path/filepath" + "testing" + + "github.com/prometheus/client_golang/prometheus" +) + +func TestInfiniBandDeviceFilterBeforeRead(t *testing.T) { + sys := t.TempDir() + included := filepath.Join(sys, "class", "infiniband", "mlx5_7") + excluded := filepath.Join(sys, "class", "infiniband", "mlx5_5") + + if err := os.MkdirAll(filepath.Join(included, "ports"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(included, "fw_ver"), []byte("28.47.1088\n"), 0o644); err != nil { + t.Fatal(err) + } + // The excluded device deliberately lacks fw_ver and ports. Reading it would fail. + if err := os.MkdirAll(excluded, 0o755); err != nil { + t.Fatal(err) + } + + oldSysPath := *sysPath + oldInclude := *infinibandDeviceInclude + oldExclude := *infinibandDeviceExclude + t.Cleanup(func() { + *sysPath = oldSysPath + *infinibandDeviceInclude = oldInclude + *infinibandDeviceExclude = oldExclude + }) + *sysPath = sys + *infinibandDeviceInclude = "" + *infinibandDeviceExclude = "^mlx5_5$" + + collector, err := NewInfiniBandCollector(slog.New(slog.NewTextHandler(io.Discard, nil))) + if err != nil { + t.Fatal(err) + } + + ch := make(chan prometheus.Metric, 1) + if err := collector.Update(ch); err != nil { + t.Fatalf("excluded device was read: %v", err) + } + if len(ch) != 1 { + t.Fatalf("expected one metric from the included device, got %d", len(ch)) + } +}