From 0f527e6c5ec041fc9b72ff4b8b1560206bbe0cbd Mon Sep 17 00:00:00 2001 From: Gavin Lam Date: Thu, 15 Feb 2024 05:50:29 -0500 Subject: [PATCH] Add `/sys/class/watchdog` statistics (#594) Signed-off-by: Gavin Lam --- sysfs/class_watchdog.go | 123 +++++++++++++++++++++++++++++++++++ sysfs/class_watchdog_test.go | 76 ++++++++++++++++++++++ testdata/fixtures.ttar | 69 ++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 sysfs/class_watchdog.go create mode 100644 sysfs/class_watchdog_test.go diff --git a/sysfs/class_watchdog.go b/sysfs/class_watchdog.go new file mode 100644 index 00000000..bcc2a67f --- /dev/null +++ b/sysfs/class_watchdog.go @@ -0,0 +1,123 @@ +// Copyright 2023 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 linux +// +build linux + +package sysfs + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/prometheus/procfs/internal/util" +) + +const watchdogClassPath = "class/watchdog" + +// WatchdogStats contains info from files in /sys/class/watchdog for a single watchdog device. +// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-watchdog +type WatchdogStats struct { + Name string + Bootstatus *int64 // /sys/class/watchdog//bootstatus + Options *string // /sys/class/watchdog//options + FwVersion *int64 // /sys/class/watchdog//fw_version + Identity *string // /sys/class/watchdog//identity + Nowayout *int64 // /sys/class/watchdog//nowayout + State *string // /sys/class/watchdog//state + Status *string // /sys/class/watchdog//status + Timeleft *int64 // /sys/class/watchdog//timeleft + Timeout *int64 // /sys/class/watchdog//timeout + Pretimeout *int64 // /sys/class/watchdog//pretimeout + PretimeoutGovernor *string // /sys/class/watchdog//pretimeout_governor + AccessCs0 *int64 // /sys/class/watchdog//access_cs0 +} + +// WatchdogClass is a collection of statistics for every watchdog device in /sys/class/watchdog. +// +// The map keys are the names of the watchdog devices. +type WatchdogClass map[string]WatchdogStats + +// WatchdogClass returns info for all watchdog devices read from /sys/class/watchdog. +func (fs FS) WatchdogClass() (WatchdogClass, error) { + path := fs.sys.Path(watchdogClassPath) + + dirs, err := os.ReadDir(path) + if err != nil { + return nil, fmt.Errorf("failed to list watchdog devices at %q: %w", path, err) + } + + wds := make(WatchdogClass, len(dirs)) + for _, d := range dirs { + stats, err := fs.parseWatchdog(d.Name()) + if err != nil { + return nil, err + } + + wds[stats.Name] = *stats + } + + return wds, nil +} + +func (fs FS) parseWatchdog(wdName string) (*WatchdogStats, error) { + path := fs.sys.Path(watchdogClassPath, wdName) + wd := WatchdogStats{Name: wdName} + + for _, f := range [...]string{"bootstatus", "options", "fw_version", "identity", "nowayout", "state", "status", "timeleft", "timeout", "pretimeout", "pretimeout_governor", "access_cs0"} { + name := filepath.Join(path, f) + value, err := util.SysReadFile(name) + if err != nil { + if os.IsNotExist(err) { + continue + } + return nil, fmt.Errorf("failed to read file %q: %w", name, err) + } + + vp := util.NewValueParser(value) + + switch f { + case "bootstatus": + wd.Bootstatus = vp.PInt64() + case "options": + wd.Options = &value + case "fw_version": + wd.FwVersion = vp.PInt64() + case "identity": + wd.Identity = &value + case "nowayout": + wd.Nowayout = vp.PInt64() + case "state": + wd.State = &value + case "status": + wd.Status = &value + case "timeleft": + wd.Timeleft = vp.PInt64() + case "timeout": + wd.Timeout = vp.PInt64() + case "pretimeout": + wd.Pretimeout = vp.PInt64() + case "pretimeout_governor": + wd.PretimeoutGovernor = &value + case "access_cs0": + wd.AccessCs0 = vp.PInt64() + } + + if err := vp.Err(); err != nil { + return nil, err + } + } + + return &wd, nil +} diff --git a/sysfs/class_watchdog_test.go b/sysfs/class_watchdog_test.go new file mode 100644 index 00000000..ad9d63a8 --- /dev/null +++ b/sysfs/class_watchdog_test.go @@ -0,0 +1,76 @@ +// Copyright 2023 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 linux +// +build linux + +package sysfs + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestWatchdogClass(t *testing.T) { + fs, err := NewFS(sysTestFixtures) + if err != nil { + t.Fatal(err) + } + + got, err := fs.WatchdogClass() + if err != nil { + t.Fatal(err) + } + + var ( + bootstatus int64 = 1 + fwVersion int64 = 2 + nowayout int64 + timeleft int64 = 300 + timeout int64 = 60 + pretimeout int64 = 120 + accessCs0 int64 + + options = "0x8380" + identity = "Software Watchdog" + state = "active" + status = "0x8000" + pretimeoutGovernor = "noop" + ) + + want := WatchdogClass{ + "watchdog0": { + Name: "watchdog0", + Bootstatus: &bootstatus, + Options: &options, + FwVersion: &fwVersion, + Identity: &identity, + Nowayout: &nowayout, + State: &state, + Status: &status, + Timeleft: &timeleft, + Timeout: &timeout, + Pretimeout: &pretimeout, + PretimeoutGovernor: &pretimeoutGovernor, + AccessCs0: &accessCs0, + }, + "watchdog1": { + Name: "watchdog1", + }, + } + + if diff := cmp.Diff(want, got); diff != "" { + t.Fatalf("unexpected watchdog class (-want +got):\n%s", diff) + } +} diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar index b22807ac..ca2bac0c 100644 --- a/testdata/fixtures.ttar +++ b/testdata/fixtures.ttar @@ -6270,6 +6270,75 @@ Lines: 1 acpitz Mode: 664 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/watchdog +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/watchdog/watchdog0 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/access_cs0 +Lines: 1 +0EOF +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/bootstatus +Lines: 1 +1EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/fw_version +Lines: 1 +2EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/identity +Lines: 1 +Software WatchdogEOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/nowayout +Lines: 1 +0EOF +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/options +Lines: 1 +0x8380EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/pretimeout +Lines: 1 +120EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/pretimeout_governor +Lines: 1 +noopEOF +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/state +Lines: 1 +activeEOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/status +Lines: 1 +0x8000EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/timeleft +Lines: 1 +300EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/watchdog/watchdog0/timeout +Lines: 1 +60EOF +Mode: 444 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/watchdog/watchdog1 +Mode: 775 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: fixtures/sys/devices Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -