go.d smartctl: use scan-open when "no_check_power_mode" is "never" (#18146)
Ilya Mashchenko committed
Jul 14, 2024 at 23:01 UTC
7aeb251f5486706c1f553da4938cb66cc93268eb
4 files changed
+42
-14
src/go/plugin/go.d/modules/smartctl/exec.go
+4
@@ -33,6 +33,10 @@ func (e *smartctlCliExec) scan() (*gjson.Result, error) {
33
return e.execute("smartctl-json-scan")
34
}
35
36
+func (e *smartctlCliExec) scanOpen() (*gjson.Result, error) {
37
+ return e.execute("smartctl-json-scan-open")
38
+}
39
+
40
func (e *smartctlCliExec) deviceInfo(deviceName, deviceType, powerMode string) (*gjson.Result, error) {
41
return e.execute("smartctl-json-device-info",
42
"--deviceName", deviceName,
src/go/plugin/go.d/modules/smartctl/scan.go
+33
-14
@@ -6,6 +6,8 @@ import (
6
"errors"
7
"fmt"
8
"strings"
9
+
10
+ "github.com/tidwall/gjson"
11
)
12
13
type scanDevice struct {
@@ -24,7 +26,22 @@ func (s *scanDevice) shortName() string {
26
}
27
28
func (s *Smartctl) scanDevices() (map[string]*scanDevice, error) {
27
- resp, err := s.exec.scan()
29
+ powerModeNever := s.NoCheckPowerMode == "never"
30
+
31
+ var resp *gjson.Result
32
+ var err error
33
+
34
+ // Issue on Discord: https://discord.com/channels/847502280503590932/1261747175361347644/1261747175361347644
35
+ // "sat" devices being identified as "scsi" with --scan, and then later
36
+ // code attempts to validate the type by calling `smartctl` with the "scsi" type.
37
+ // This validation can trigger unintended "Enabling discard_zeroes_data" messages in system logs (dmesg).
38
+ // To address this specific issue we use `smartctl --scan-open` as a workaround.
39
+ // This method reliably identifies device types.
40
+ if powerModeNever {
41
+ resp, err = s.exec.scanOpen()
42
+ } else {
43
+ resp, err = s.exec.scan()
44
+ }
45
if err != nil {
46
return nil, fmt.Errorf("failed to scan devices: %v", err)
47
}
@@ -35,7 +52,7 @@ func (s *Smartctl) scanDevices() (map[string]*scanDevice, error) {
52
dev := &scanDevice{
53
name: d.Get("name").String(),
54
infoName: d.Get("info_name").String(),
38
- typ: d.Get("type").String(), // guessed type (we do '--scan' not '--scan-open')
55
+ typ: d.Get("type").String(), // guessed type when using '--scan' instead of '--scan-open'
56
}
57
58
if dev.name == "" || dev.typ == "" {
@@ -48,19 +65,21 @@ func (s *Smartctl) scanDevices() (map[string]*scanDevice, error) {
65
continue
66
}
67
51
- if dev.typ == "scsi" {
52
- // `smartctl --scan` attempts to guess the device type based on the path, but this can be unreliable.
53
- // Accurate device type information is crucial because we use the `--device` option to gather data.
54
- // Using the wrong type can lead to issues.
55
- // For example, using 'scsi' for 'sat' devices prevents `smartctl` from issuing the necessary ATA commands.
56
- d := scanDevice{name: dev.name, typ: "sat"}
57
- if _, ok := s.scannedDevices[d.key()]; ok {
58
- dev.typ = "sat"
59
- } else {
60
- resp, _ := s.exec.deviceInfo(dev.name, dev.typ, s.NoCheckPowerMode)
61
- if resp != nil && isExitStatusHasBit(resp, 2) {
62
- s.Debugf("changing device '%s' type 'scsi' -> 'sat'", dev.name)
68
+ if !powerModeNever {
69
+ if dev.typ == "scsi" {
70
+ // `smartctl --scan` attempts to guess the device type based on the path, but this can be unreliable.
71
+ // Accurate device type information is crucial because we use the `--device` option to gather data.
72
+ // Using the wrong type can lead to issues.
73
+ // For example, using 'scsi' for 'sat' devices prevents `smartctl` from issuing the necessary ATA commands.
74
+ d := scanDevice{name: dev.name, typ: "sat"}
75
+ if _, ok := s.scannedDevices[d.key()]; ok {
76
dev.typ = "sat"
77
+ } else {
78
+ resp, _ := s.exec.deviceInfo(dev.name, dev.typ, s.NoCheckPowerMode)
79
+ if resp != nil && isExitStatusHasBit(resp, 2) {
80
+ s.Debugf("changing device '%s' type 'scsi' -> 'sat'", dev.name)
81
+ dev.typ = "sat"
82
+ }
83
}
84
}
85
}
src/go/plugin/go.d/modules/smartctl/smartctl.go
+1
@@ -83,6 +83,7 @@ type (
83
}
84
smartctlCli interface {
85
scan() (*gjson.Result, error)
86
+ scanOpen() (*gjson.Result, error)
87
deviceInfo(deviceName, deviceType, powerMode string) (*gjson.Result, error)
88
}
89
)
src/go/plugin/go.d/modules/smartctl/smartctl_test.go
+4
@@ -477,6 +477,10 @@ func (m *mockSmartctlCliExec) scan() (*gjson.Result, error) {
477
return &res, nil
478
}
479
480
+func (m *mockSmartctlCliExec) scanOpen() (*gjson.Result, error) {
481
+ return m.scan()
482
+}
483
+
484
func (m *mockSmartctlCliExec) deviceInfo(deviceName, deviceType, powerMode string) (*gjson.Result, error) {
485
if m.deviceDataFunc == nil {
486
return nil, nil