diff --git a/collector/fibrechannel_linux.go b/collector/fibrechannel_linux.go index 4854b93a46..22628881c8 100644 --- a/collector/fibrechannel_linux.go +++ b/collector/fibrechannel_linux.go @@ -127,22 +127,47 @@ func (c *fibrechannelCollector) Update(ch chan<- prometheus.Metric) error { )...) // Then the counters - // Note: `procfs` does not guarantee a safe dereference for these counters. - // A disabled host returns no statistics counters. - if host.PortState == nil || *host.PortState == "Unknown" { + // Note: These are not guaranteed to exist in the filesystem + if host.Counters.DumpedFrames == nil { host.Counters.DumpedFrames = new(uint64) + } + if host.Counters.ErrorFrames == nil { host.Counters.ErrorFrames = new(uint64) + } + if host.Counters.InvalidCRCCount == nil { host.Counters.InvalidCRCCount = new(uint64) + } + if host.Counters.RXFrames == nil { host.Counters.RXFrames = new(uint64) + } + if host.Counters.RXWords == nil { host.Counters.RXWords = new(uint64) + } + if host.Counters.TXFrames == nil { host.Counters.TXFrames = new(uint64) + } + if host.Counters.TXWords == nil { host.Counters.TXWords = new(uint64) + } + if host.Counters.SecondsSinceLastReset == nil { host.Counters.SecondsSinceLastReset = new(uint64) + } + if host.Counters.InvalidTXWordCount == nil { host.Counters.InvalidTXWordCount = new(uint64) + } + if host.Counters.LinkFailureCount == nil { host.Counters.LinkFailureCount = new(uint64) + } + if host.Counters.LossOfSyncCount == nil { host.Counters.LossOfSyncCount = new(uint64) + } + if host.Counters.LossOfSignalCount == nil { host.Counters.LossOfSignalCount = new(uint64) + } + if host.Counters.NosCount == nil { host.Counters.NosCount = new(uint64) + } + if host.Counters.FCPPacketAborts == nil { host.Counters.FCPPacketAborts = new(uint64) } c.pushCounter(ch, "dumped_frames_total", *host.Counters.DumpedFrames, *host.Name) diff --git a/collector/fibrechannel_linux_test.go b/collector/fibrechannel_linux_test.go new file mode 100644 index 0000000000..d56fe211c0 --- /dev/null +++ b/collector/fibrechannel_linux_test.go @@ -0,0 +1,51 @@ +// Copyright 2021 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 !nofibrechannel + +package collector + +import ( + "io" + "log/slog" + "testing" + + "github.com/prometheus/client_golang/prometheus" +) + +func TestFibreChannelCollector(t *testing.T) { + // The fixtures directory includes host2 which has + // port_state="Online" but an empty statistics/ dir. + // Before the fix, this would panic with a nil pointer + // dereference when trying to read counter values. + + logger := slog.New(slog.NewTextHandler(io.Discard, nil)) + + // Override sysPath to point to our fixtures + testSysPath := "fixtures/sys" + oldSysPath := *sysPath + *sysPath = testSysPath + defer func() { *sysPath = oldSysPath }() + + collector, err := NewFibreChannelCollector(logger) + if err != nil { + t.Fatal(err) + } + + // This should not panic even with missing statistics files + ch := make(chan prometheus.Metric, 100) + err = collector.Update(ch) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } +} diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt index f0ac7ebac4..7b8e4be5e4 100644 --- a/collector/fixtures/e2e-64k-page-output.txt +++ b/collector/fixtures/e2e-64k-page-output.txt @@ -1406,61 +1406,76 @@ node_entropy_pool_size_bits 4096 # HELP node_fibrechannel_dumped_frames_total Number of dumped frames # TYPE node_fibrechannel_dumped_frames_total counter node_fibrechannel_dumped_frames_total{fc_host="host1"} 0 +node_fibrechannel_dumped_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_error_frames_total Number of errors in frames # TYPE node_fibrechannel_error_frames_total counter node_fibrechannel_error_frames_total{fc_host="host0"} 0 node_fibrechannel_error_frames_total{fc_host="host1"} 19 +node_fibrechannel_error_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_fcp_packet_aborts_total Number of aborted packets # TYPE node_fibrechannel_fcp_packet_aborts_total counter node_fibrechannel_fcp_packet_aborts_total{fc_host="host0"} 19 +node_fibrechannel_fcp_packet_aborts_total{fc_host="host2"} 0 # HELP node_fibrechannel_info Non-numeric data from /sys/class/fc_host/, value is always 1. # TYPE node_fibrechannel_info gauge node_fibrechannel_info{dev_loss_tmo="",fabric_name="",fc_host="host1",port_id="",port_name="",port_state="Online",port_type="",speed="8 Gbit",supported_classes="",supported_speeds="",symbolic_name=""} 1 node_fibrechannel_info{dev_loss_tmo="30",fabric_name="0",fc_host="host0",port_id="000002",port_name="1000e0071bce95f2",port_state="Online",port_type="Point-To-Point (direct nport connection)",speed="16 Gbit",supported_classes="Class 3",supported_speeds="4 Gbit, 8 Gbit, 16 Gbit",symbolic_name="Emulex SN1100E2P FV12.4.270.3 DV12.4.0.0. HN:gotest. OS:Linux"} 1 +node_fibrechannel_info{dev_loss_tmo="300",fabric_name="c050760aab8f2cff",fc_host="host2",port_id="0b19e2",port_name="c050760aab8f2cff",port_state="Online",port_type="NPIV VPORT",speed="unknown",supported_classes="Class 3",supported_speeds="",symbolic_name=""} 1 # HELP node_fibrechannel_invalid_crc_total Invalid Cyclic Redundancy Check count # TYPE node_fibrechannel_invalid_crc_total counter node_fibrechannel_invalid_crc_total{fc_host="host0"} 2 node_fibrechannel_invalid_crc_total{fc_host="host1"} 32 +node_fibrechannel_invalid_crc_total{fc_host="host2"} 0 # HELP node_fibrechannel_invalid_tx_words_total Number of invalid words transmitted by host port # TYPE node_fibrechannel_invalid_tx_words_total counter node_fibrechannel_invalid_tx_words_total{fc_host="host0"} 8 node_fibrechannel_invalid_tx_words_total{fc_host="host1"} 128 +node_fibrechannel_invalid_tx_words_total{fc_host="host2"} 0 # HELP node_fibrechannel_link_failure_total Number of times the host port link has failed # TYPE node_fibrechannel_link_failure_total counter node_fibrechannel_link_failure_total{fc_host="host0"} 9 node_fibrechannel_link_failure_total{fc_host="host1"} 144 +node_fibrechannel_link_failure_total{fc_host="host2"} 0 # HELP node_fibrechannel_loss_of_signal_total Number of times signal has been lost # TYPE node_fibrechannel_loss_of_signal_total counter node_fibrechannel_loss_of_signal_total{fc_host="host0"} 17 node_fibrechannel_loss_of_signal_total{fc_host="host1"} 272 +node_fibrechannel_loss_of_signal_total{fc_host="host2"} 0 # HELP node_fibrechannel_loss_of_sync_total Number of failures on either bit or transmission word boundaries # TYPE node_fibrechannel_loss_of_sync_total counter node_fibrechannel_loss_of_sync_total{fc_host="host0"} 16 node_fibrechannel_loss_of_sync_total{fc_host="host1"} 256 +node_fibrechannel_loss_of_sync_total{fc_host="host2"} 0 # HELP node_fibrechannel_nos_total Number Not_Operational Primitive Sequence received by host port # TYPE node_fibrechannel_nos_total counter node_fibrechannel_nos_total{fc_host="host0"} 18 node_fibrechannel_nos_total{fc_host="host1"} 288 +node_fibrechannel_nos_total{fc_host="host2"} 0 # HELP node_fibrechannel_rx_frames_total Number of frames received # TYPE node_fibrechannel_rx_frames_total counter node_fibrechannel_rx_frames_total{fc_host="host0"} 3 node_fibrechannel_rx_frames_total{fc_host="host1"} 48 +node_fibrechannel_rx_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_rx_words_total Number of words received by host port # TYPE node_fibrechannel_rx_words_total counter node_fibrechannel_rx_words_total{fc_host="host0"} 4 node_fibrechannel_rx_words_total{fc_host="host1"} 64 +node_fibrechannel_rx_words_total{fc_host="host2"} 0 # HELP node_fibrechannel_seconds_since_last_reset_total Number of seconds since last host port reset # TYPE node_fibrechannel_seconds_since_last_reset_total counter node_fibrechannel_seconds_since_last_reset_total{fc_host="host0"} 7 node_fibrechannel_seconds_since_last_reset_total{fc_host="host1"} 112 +node_fibrechannel_seconds_since_last_reset_total{fc_host="host2"} 0 # HELP node_fibrechannel_tx_frames_total Number of frames transmitted by host port # TYPE node_fibrechannel_tx_frames_total counter node_fibrechannel_tx_frames_total{fc_host="host0"} 5 node_fibrechannel_tx_frames_total{fc_host="host1"} 80 +node_fibrechannel_tx_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_tx_words_total Number of words transmitted by host port # TYPE node_fibrechannel_tx_words_total counter node_fibrechannel_tx_words_total{fc_host="host0"} 6 node_fibrechannel_tx_words_total{fc_host="host1"} 96 +node_fibrechannel_tx_words_total{fc_host="host2"} 0 # HELP node_filefd_allocated File descriptor statistics: allocated. # TYPE node_filefd_allocated gauge node_filefd_allocated 1024 diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index 9afd903d6f..d03fb08f44 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -1438,61 +1438,76 @@ node_entropy_pool_size_bits 4096 # HELP node_fibrechannel_dumped_frames_total Number of dumped frames # TYPE node_fibrechannel_dumped_frames_total counter node_fibrechannel_dumped_frames_total{fc_host="host1"} 0 +node_fibrechannel_dumped_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_error_frames_total Number of errors in frames # TYPE node_fibrechannel_error_frames_total counter node_fibrechannel_error_frames_total{fc_host="host0"} 0 node_fibrechannel_error_frames_total{fc_host="host1"} 19 +node_fibrechannel_error_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_fcp_packet_aborts_total Number of aborted packets # TYPE node_fibrechannel_fcp_packet_aborts_total counter node_fibrechannel_fcp_packet_aborts_total{fc_host="host0"} 19 +node_fibrechannel_fcp_packet_aborts_total{fc_host="host2"} 0 # HELP node_fibrechannel_info Non-numeric data from /sys/class/fc_host/, value is always 1. # TYPE node_fibrechannel_info gauge node_fibrechannel_info{dev_loss_tmo="",fabric_name="",fc_host="host1",port_id="",port_name="",port_state="Online",port_type="",speed="8 Gbit",supported_classes="",supported_speeds="",symbolic_name=""} 1 node_fibrechannel_info{dev_loss_tmo="30",fabric_name="0",fc_host="host0",port_id="000002",port_name="1000e0071bce95f2",port_state="Online",port_type="Point-To-Point (direct nport connection)",speed="16 Gbit",supported_classes="Class 3",supported_speeds="4 Gbit, 8 Gbit, 16 Gbit",symbolic_name="Emulex SN1100E2P FV12.4.270.3 DV12.4.0.0. HN:gotest. OS:Linux"} 1 +node_fibrechannel_info{dev_loss_tmo="300",fabric_name="c050760aab8f2cff",fc_host="host2",port_id="0b19e2",port_name="c050760aab8f2cff",port_state="Online",port_type="NPIV VPORT",speed="unknown",supported_classes="Class 3",supported_speeds="",symbolic_name=""} 1 # HELP node_fibrechannel_invalid_crc_total Invalid Cyclic Redundancy Check count # TYPE node_fibrechannel_invalid_crc_total counter node_fibrechannel_invalid_crc_total{fc_host="host0"} 2 node_fibrechannel_invalid_crc_total{fc_host="host1"} 32 +node_fibrechannel_invalid_crc_total{fc_host="host2"} 0 # HELP node_fibrechannel_invalid_tx_words_total Number of invalid words transmitted by host port # TYPE node_fibrechannel_invalid_tx_words_total counter node_fibrechannel_invalid_tx_words_total{fc_host="host0"} 8 node_fibrechannel_invalid_tx_words_total{fc_host="host1"} 128 +node_fibrechannel_invalid_tx_words_total{fc_host="host2"} 0 # HELP node_fibrechannel_link_failure_total Number of times the host port link has failed # TYPE node_fibrechannel_link_failure_total counter node_fibrechannel_link_failure_total{fc_host="host0"} 9 node_fibrechannel_link_failure_total{fc_host="host1"} 144 +node_fibrechannel_link_failure_total{fc_host="host2"} 0 # HELP node_fibrechannel_loss_of_signal_total Number of times signal has been lost # TYPE node_fibrechannel_loss_of_signal_total counter node_fibrechannel_loss_of_signal_total{fc_host="host0"} 17 node_fibrechannel_loss_of_signal_total{fc_host="host1"} 272 +node_fibrechannel_loss_of_signal_total{fc_host="host2"} 0 # HELP node_fibrechannel_loss_of_sync_total Number of failures on either bit or transmission word boundaries # TYPE node_fibrechannel_loss_of_sync_total counter node_fibrechannel_loss_of_sync_total{fc_host="host0"} 16 node_fibrechannel_loss_of_sync_total{fc_host="host1"} 256 +node_fibrechannel_loss_of_sync_total{fc_host="host2"} 0 # HELP node_fibrechannel_nos_total Number Not_Operational Primitive Sequence received by host port # TYPE node_fibrechannel_nos_total counter node_fibrechannel_nos_total{fc_host="host0"} 18 node_fibrechannel_nos_total{fc_host="host1"} 288 +node_fibrechannel_nos_total{fc_host="host2"} 0 # HELP node_fibrechannel_rx_frames_total Number of frames received # TYPE node_fibrechannel_rx_frames_total counter node_fibrechannel_rx_frames_total{fc_host="host0"} 3 node_fibrechannel_rx_frames_total{fc_host="host1"} 48 +node_fibrechannel_rx_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_rx_words_total Number of words received by host port # TYPE node_fibrechannel_rx_words_total counter node_fibrechannel_rx_words_total{fc_host="host0"} 4 node_fibrechannel_rx_words_total{fc_host="host1"} 64 +node_fibrechannel_rx_words_total{fc_host="host2"} 0 # HELP node_fibrechannel_seconds_since_last_reset_total Number of seconds since last host port reset # TYPE node_fibrechannel_seconds_since_last_reset_total counter node_fibrechannel_seconds_since_last_reset_total{fc_host="host0"} 7 node_fibrechannel_seconds_since_last_reset_total{fc_host="host1"} 112 +node_fibrechannel_seconds_since_last_reset_total{fc_host="host2"} 0 # HELP node_fibrechannel_tx_frames_total Number of frames transmitted by host port # TYPE node_fibrechannel_tx_frames_total counter node_fibrechannel_tx_frames_total{fc_host="host0"} 5 node_fibrechannel_tx_frames_total{fc_host="host1"} 80 +node_fibrechannel_tx_frames_total{fc_host="host2"} 0 # HELP node_fibrechannel_tx_words_total Number of words transmitted by host port # TYPE node_fibrechannel_tx_words_total counter node_fibrechannel_tx_words_total{fc_host="host0"} 6 node_fibrechannel_tx_words_total{fc_host="host1"} 96 +node_fibrechannel_tx_words_total{fc_host="host2"} 0 # HELP node_filefd_allocated File descriptor statistics: allocated. # TYPE node_filefd_allocated gauge node_filefd_allocated 1024 diff --git a/collector/fixtures/sys.ttar b/collector/fixtures/sys.ttar index dfcc08bacf..06f38954f9 100644 --- a/collector/fixtures/sys.ttar +++ b/collector/fixtures/sys.ttar @@ -1381,6 +1381,72 @@ Lines: 1 0x60 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: sys/class/fc_host/host2 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/dev_loss_tmo +Lines: 1 +300 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/fabric_name +Lines: 1 +0xc050760aab8f2cff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/issue_lip +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/maxframe_size +Lines: 1 +2048 bytes +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/node_name +Lines: 1 +0xc050760aab8f2cff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/port_id +Lines: 1 +0x0b19e2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/port_name +Lines: 1 +0xc050760aab8f2cff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/port_state +Lines: 1 +Online +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/port_type +Lines: 1 +NPIV VPORT +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/speed +Lines: 1 +unknown +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/supported_classes +Lines: 1 +Class 3 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/tgtid_bind_type +Lines: 1 +wwpn (World Wide Port Name) +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: sys/class/fc_host/host2/uevent +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: sys/class/hwmon Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -