diff --git a/plugins/inputs/all/smartctl.go b/plugins/inputs/all/smartctl.go new file mode 100644 index 0000000000000..69155b83bdebe --- /dev/null +++ b/plugins/inputs/all/smartctl.go @@ -0,0 +1,5 @@ +//go:build !custom || inputs || inputs.smartctl + +package all + +import _ "github.com/influxdata/telegraf/plugins/inputs/smartctl" // register plugin diff --git a/plugins/inputs/smartctl/README.md b/plugins/inputs/smartctl/README.md new file mode 100644 index 0000000000000..a43f5876b07a1 --- /dev/null +++ b/plugins/inputs/smartctl/README.md @@ -0,0 +1,110 @@ +# smartctl JSON Input Plugin + +Get metrics using the command line utility `smartctl` for S.M.A.R.T. +(Self-Monitoring, Analysis and Reporting Technology) storage devices. SMART is a +monitoring system included in computer hard disk drives (HDDs), solid-state +drives (SSDs), and nVME drives that detects and reports on various indicators of +drive reliability, with the intent of enabling the anticipation of hardware +failures. + +This version of the plugin requires support of the JSON flag from the `smartctl` +command. This flag was added in 7.0 (2019) and further enhanced in subsequent +releases. + +See smartmontools () for more information. + +## smart vs smartctl + +The smartctl plugin is an alternative to the smart plugin. The biggest +difference is that the smart plugin can also call `nvmectl` to collect +additional details about NVMe devices as well as some vendor specific device +information. + +This plugin will also require a version of the `smartctl` command that supports +JSON output versus the smart plugin will parse the raw output. + +## Global configuration options + +In addition to the plugin-specific configuration settings, plugins support +additional global and plugin configuration settings. These settings are used to +modify metrics, tags, and field or create aliases and configure ordering, etc. +See the [CONFIGURATION.md][CONFIGURATION.md] for more details. + +[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins + +## Configuration + +```toml @sample.conf +# Read metrics from SMART storage devices using smartclt's JSON output +[[inputs.smartctl]] + ## Optionally specify the path to the smartctl executable + # path = "/usr/sbin/smartctl" + + ## Use sudo + ## On most platforms used, smartctl requires root access. Setting 'use_sudo' + ## to true will make use of sudo to run smartctl. Sudo must be configured to + ## allow the telegraf user to run smartctl without a password. + # use_sudo = false + + ## Devices to include or exclude + ## By default, the plugin will use all devices found in the output of + ## `smartctl --scan`. Only one option is allowed at a time. If set, include + ## sets the specific devices to scan, while exclude omits specific devices. + # devices_include = [] + # devices_exclude = [] + + ## Skip checking disks in specified power mode + ## Defaults to "standby" to not wake up disks that have stopped rotating. + ## For full details on the options here, see the --nocheck section in the + ## smartctl man page. Choose from: + ## * never: always check the device + ## * sleep: check the device unless it is in sleep mode + ## * standby: check the device unless it is in sleep or standby mode + ## * idle: check the device unless it is in sleep, standby, or idle mode + # nocheck = "standby" + + ## Timeout for the cli command to complete + # timeout = "30s" +``` + +## Permissions + +It is important to note that this plugin references `smartctl`, which may +require additional permissions to execute successfully. Depending on the +user/group permissions of the telegraf user executing this plugin, users may +need to use sudo. + +Users need the following in the Telegraf config: + +```toml +[[inputs.smart_json]] + use_sudo = true +``` + +And to update the `/etc/sudoers` file to allow running smartctl: + +```bash +$ visudo +# Add the following lines: +Cmnd_Alias SMARTCTL = /usr/sbin/smartctl +telegraf ALL=(ALL) NOPASSWD: SMARTCTL +Defaults!SMARTCTL !logfile, !syslog, !pam_session +``` + +## Debugging Issues + +This plugin uses the following commands to determine devices and collect +metrics: + +* `smartctl --json --scan` +* `smartctl --json --all $DEVICE --device $TYPE --nocheck=$NOCHECK` + +Please include the output of the above two commands for all devices that are +having issues. + +## Metrics + +## Example Output + +```text +``` diff --git a/plugins/inputs/smartctl/sample.conf b/plugins/inputs/smartctl/sample.conf new file mode 100644 index 0000000000000..e4bbe243e7656 --- /dev/null +++ b/plugins/inputs/smartctl/sample.conf @@ -0,0 +1,30 @@ +# Read metrics from SMART storage devices using smartclt's JSON output +[[inputs.smartctl]] + ## Optionally specify the path to the smartctl executable + # path = "/usr/sbin/smartctl" + + ## Use sudo + ## On most platforms used, smartctl requires root access. Setting 'use_sudo' + ## to true will make use of sudo to run smartctl. Sudo must be configured to + ## allow the telegraf user to run smartctl without a password. + # use_sudo = false + + ## Devices to include or exclude + ## By default, the plugin will use all devices found in the output of + ## `smartctl --scan`. Only one option is allowed at a time. If set, include + ## sets the specific devices to scan, while exclude omits specific devices. + # devices_include = [] + # devices_exclude = [] + + ## Skip checking disks in specified power mode + ## Defaults to "standby" to not wake up disks that have stopped rotating. + ## For full details on the options here, see the --nocheck section in the + ## smartctl man page. Choose from: + ## * never: always check the device + ## * sleep: check the device unless it is in sleep mode + ## * standby: check the device unless it is in sleep or standby mode + ## * idle: check the device unless it is in sleep, standby, or idle mode + # nocheck = "standby" + + ## Timeout for the cli command to complete + # timeout = "30s" diff --git a/plugins/inputs/smartctl/smartctl.go b/plugins/inputs/smartctl/smartctl.go new file mode 100644 index 0000000000000..7c82ac78d544b --- /dev/null +++ b/plugins/inputs/smartctl/smartctl.go @@ -0,0 +1,93 @@ +//go:generate ../../../tools/readme_config_includer/generator +package smartctl + +import ( + _ "embed" + "errors" + "fmt" + "os" + "os/exec" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/filter" + "github.com/influxdata/telegraf/plugins/inputs" +) + +//go:embed sample.conf +var sampleConfig string + +// execCommand is used to mock commands in tests. +var execCommand = exec.Command + +type Smartctl struct { + Path string `toml:"path"` + NoCheck string `toml:"no_check"` + UseSudo bool `toml:"use_sudo"` + Timeout config.Duration `toml:"timeout"` + DevicesInclude []string `toml:"devices_include"` + DevicesExclude []string `toml:"devices_exclude"` + Log telegraf.Logger `toml:"-"` + + deviceFilter filter.Filter +} + +func (*Smartctl) SampleConfig() string { + return sampleConfig +} + +func (s *Smartctl) Init() error { + if s.Path == "" { + s.Path = "/usr/sbin/smartctl" + } + + switch s.NoCheck { + case "never", "sleep", "standby", "idle": + case "": + s.NoCheck = "standby" + default: + return fmt.Errorf("invalid no_check value: %s", s.NoCheck) + } + + if s.Timeout == 0 { + s.Timeout = config.Duration(time.Second * 30) + } + + if len(s.DevicesInclude) != 0 && len(s.DevicesExclude) != 0 { + return errors.New("cannot specify both devices_include and devices_exclude") + } + + var err error + s.deviceFilter, err = filter.NewIncludeExcludeFilter(s.DevicesInclude, s.DevicesExclude) + if err != nil { + return err + } + + return nil +} + +func (s *Smartctl) Gather(acc telegraf.Accumulator) error { + devices, err := s.scan() + if err != nil { + return fmt.Errorf("Error scanning system: %w", err) + } + + for _, device := range devices { + if err := s.scanDevice(acc, device.Name, device.Type); err != nil { + return fmt.Errorf("Error getting device %s: %w", device, err) + } + } + + return nil +} + +func init() { + // Set LC_NUMERIC to uniform numeric output from cli tools + _ = os.Setenv("LC_NUMERIC", "en_US.UTF-8") + inputs.Add("smartctl", func() telegraf.Input { + return &Smartctl{ + Timeout: config.Duration(time.Second * 30), + } + }) +} diff --git a/plugins/inputs/smartctl/smartctl_device.go b/plugins/inputs/smartctl/smartctl_device.go new file mode 100644 index 0000000000000..03ef6d60eaeb1 --- /dev/null +++ b/plugins/inputs/smartctl/smartctl_device.go @@ -0,0 +1,151 @@ +package smartctl + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" +) + +func (s *Smartctl) scanDevice(acc telegraf.Accumulator, deviceName string, deviceType string) error { + args := []string{"--json", "--all", deviceName, "--device", deviceType, "--nocheck=" + s.NoCheck} + cmd := execCommand(s.Path, args...) + if s.UseSudo { + cmd = execCommand("sudo", append([]string{"-n", s.Path}, args...)...) + } + + var device smartctlDeviceJSON + out, err := internal.CombinedOutputTimeout(cmd, time.Duration(s.Timeout)) + if err != nil { + // Error running the command and unable to parse the JSON, then bail + if jsonErr := json.Unmarshal(out, &device); jsonErr != nil { + return fmt.Errorf("error running smartctl with %s: %w", args, err) + } + + // If we were able to parse the result, then only exit if we get an error + // as sometimes we can get warnings, that still produce data. + if len(device.Smartctl.Messages) > 0 && + device.Smartctl.Messages[0].Severity == "error" && + device.Smartctl.Messages[0].String != "" { + return fmt.Errorf("error running smartctl with %s got smartctl error message: %s", args, device.Smartctl.Messages[0].String) + } + } + + if err := json.Unmarshal(out, &device); err != nil { + return fmt.Errorf("error unable to unmarshall response %s: %w", args, err) + } + + t := time.Now() + + tags := map[string]string{ + "name": device.Device.Name, + "type": device.Device.Type, + "model": device.ModelName, + "serial": device.SerialNumber, + } + + if device.Vendor != "" { + tags["vendor"] = device.Vendor + } + + // The JSON WWN is in decimal and needs to be converted to hex + if device.Wwn.ID != 0 && device.Wwn.Naa != 0 && device.Wwn.Oui != 0 { + tags["wwn"] = fmt.Sprintf("%01x%06x%09x", device.Wwn.Naa, device.Wwn.Oui, device.Wwn.ID) + } + + fields := map[string]interface{}{ + "capacity": device.UserCapacity.Bytes, + "health_ok": device.SmartStatus.Passed, + "temperature": device.Temperature.Current, + "firmware": device.FirmwareVersion, + } + + // Add NVMe specific fields + if device.Device.Type == "nvme" { + fields["critical_warning"] = device.NvmeSmartHealthInformationLog.CriticalWarning + fields["temperature"] = device.NvmeSmartHealthInformationLog.Temperature + fields["available_spare"] = device.NvmeSmartHealthInformationLog.AvailableSpare + fields["available_spare_threshold"] = device.NvmeSmartHealthInformationLog.AvailableSpareThreshold + fields["percentage_used"] = device.NvmeSmartHealthInformationLog.PercentageUsed + fields["data_units_read"] = device.NvmeSmartHealthInformationLog.DataUnitsRead + fields["data_units_written"] = device.NvmeSmartHealthInformationLog.DataUnitsWritten + fields["host_reads"] = device.NvmeSmartHealthInformationLog.HostReads + fields["host_writes"] = device.NvmeSmartHealthInformationLog.HostWrites + fields["controller_busy_time"] = device.NvmeSmartHealthInformationLog.ControllerBusyTime + fields["power_cycles"] = device.NvmeSmartHealthInformationLog.PowerCycles + fields["power_on_hours"] = device.NvmeSmartHealthInformationLog.PowerOnHours + fields["unsafe_shutdowns"] = device.NvmeSmartHealthInformationLog.UnsafeShutdowns + fields["media_errors"] = device.NvmeSmartHealthInformationLog.MediaErrors + fields["num_err_log_entries"] = device.NvmeSmartHealthInformationLog.NumErrLogEntries + fields["warning_temp_time"] = device.NvmeSmartHealthInformationLog.WarningTempTime + fields["critical_comp_time"] = device.NvmeSmartHealthInformationLog.CriticalCompTime + } + + acc.AddFields("smartctl", fields, tags, t) + + // Check for ATA specific attribute fields + for _, attribute := range device.AtaSmartAttributes.Table { + attributeTags := make(map[string]string, len(tags)+1) + for k, v := range tags { + attributeTags[k] = v + } + attributeTags["name"] = attribute.Name + + fields := map[string]interface{}{ + "raw_value": attribute.Raw.Value, + "worst": attribute.Worst, + "threshold": attribute.Thresh, + "value": attribute.Value, + } + + acc.AddFields("smartctl_attributes", fields, attributeTags, t) + } + + // Check for SCSI error counter entries + if device.Device.Type == "scsi" { + counterTags := make(map[string]string, len(tags)+1) + for k, v := range tags { + counterTags[k] = v + } + + counterTags["page"] = "read" + fields := map[string]interface{}{ + "errors_corrected_by_eccfast": device.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, + "errors_corrected_by_eccdelayed": device.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, + "errors_corrected_by_rereads_rewrites": device.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, + "total_errors_corrected": device.ScsiErrorCounterLog.Read.TotalErrorsCorrected, + "correction_algorithm_invocations": device.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, + "gigabytes_processed": device.ScsiErrorCounterLog.Read.GigabytesProcessed, + "total_uncorrected_errors": device.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, + } + acc.AddFields("smartctl_scsi_error_counter_log", fields, counterTags, t) + + counterTags["page"] = "write" + fields = map[string]interface{}{ + "errors_corrected_by_eccfast": device.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, + "errors_corrected_by_eccdelayed": device.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, + "errors_corrected_by_rereads_rewrites": device.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, + "total_errors_corrected": device.ScsiErrorCounterLog.Write.TotalErrorsCorrected, + "correction_algorithm_invocations": device.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, + "gigabytes_processed": device.ScsiErrorCounterLog.Write.GigabytesProcessed, + "total_uncorrected_errors": device.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, + } + acc.AddFields("smartctl_scsi_error_counter_log", fields, counterTags, t) + + counterTags["page"] = "verify" + fields = map[string]interface{}{ + "errors_corrected_by_eccfast": device.ScsiErrorCounterLog.Verify.ErrorsCorrectedByEccfast, + "errors_corrected_by_eccdelayed": device.ScsiErrorCounterLog.Verify.ErrorsCorrectedByEccdelayed, + "errors_corrected_by_rereads_rewrites": device.ScsiErrorCounterLog.Verify.ErrorsCorrectedByRereadsRewrites, + "total_errors_corrected": device.ScsiErrorCounterLog.Verify.TotalErrorsCorrected, + "correction_algorithm_invocations": device.ScsiErrorCounterLog.Verify.CorrectionAlgorithmInvocations, + "gigabytes_processed": device.ScsiErrorCounterLog.Verify.GigabytesProcessed, + "total_uncorrected_errors": device.ScsiErrorCounterLog.Verify.TotalUncorrectedErrors, + } + acc.AddFields("smartctl_scsi_error_counter_log", fields, counterTags, t) + } + + return nil +} diff --git a/plugins/inputs/smartctl/smartctl_json.go b/plugins/inputs/smartctl/smartctl_json.go new file mode 100644 index 0000000000000..a5bdb5ce8467b --- /dev/null +++ b/plugins/inputs/smartctl/smartctl_json.go @@ -0,0 +1,136 @@ +package smartctl + +type smartctlDeviceJSON struct { + JSONFormatVersion []int `json:"json_format_version"` + Smartctl struct { + Version []int `json:"version"` + PreRelease bool `json:"pre_release"` + SvnRevision string `json:"svn_revision"` + PlatformInfo string `json:"platform_info"` + BuildInfo string `json:"build_info"` + Argv []string `json:"argv"` + Messages []struct { + Severity string `json:"severity"` + String string `json:"string"` + } `json:"messages"` + ExitStatus int `json:"exit_status"` + } `json:"smartctl"` + Device struct { + Name string `json:"name"` + InfoName string `json:"info_name"` + Type string `json:"type"` + Protocol string `json:"protocol"` + } `json:"device"` + Vendor string `json:"vendor"` + Product string `json:"product"` + ModelFamily string `json:"model_family"` + ModelName string `json:"model_name"` + SerialNumber string `json:"serial_number"` + FirmwareVersion string `json:"firmware_version"` + Wwn struct { + Naa int `json:"naa"` + Oui int `json:"oui"` + ID int64 `json:"id"` + } `json:"wwn"` + UserCapacity struct { + Bytes int64 `json:"bytes"` + } `json:"user_capacity"` + SmartStatus struct { + Passed bool `json:"passed"` + } `json:"smart_status"` + NvmeSmartHealthInformationLog struct { + CriticalWarning int64 `json:"critical_warning"` + Temperature int64 `json:"temperature"` + AvailableSpare int64 `json:"available_spare"` + AvailableSpareThreshold int64 `json:"available_spare_threshold"` + PercentageUsed int64 `json:"percentage_used"` + DataUnitsRead int64 `json:"data_units_read"` + DataUnitsWritten int64 `json:"data_units_written"` + HostReads int64 `json:"host_reads"` + HostWrites int64 `json:"host_writes"` + ControllerBusyTime int64 `json:"controller_busy_time"` + PowerCycles int64 `json:"power_cycles"` + PowerOnHours int64 `json:"power_on_hours"` + UnsafeShutdowns int64 `json:"unsafe_shutdowns"` + MediaErrors int64 `json:"media_errors"` + NumErrLogEntries int64 `json:"num_err_log_entries"` + WarningTempTime int64 `json:"warning_temp_time"` + CriticalCompTime int64 `json:"critical_comp_time"` + } `json:"nvme_smart_health_information_log"` + Temperature struct { + Current int `json:"current"` + } `json:"temperature"` + AtaSmartAttributes struct { + Revision int `json:"revision"` + Table []struct { + ID int64 `json:"id"` + Name string `json:"name"` + Value int64 `json:"value"` + Worst int64 `json:"worst"` + Thresh int64 `json:"thresh"` + WhenFailed string `json:"when_failed"` + Flags struct { + Value int64 `json:"value"` + String string `json:"string"` + Prefailure bool `json:"prefailure"` + UpdatedOnline bool `json:"updated_online"` + Performance bool `json:"performance"` + ErrorRate bool `json:"error_rate"` + EventCount bool `json:"event_count"` + AutoKeep bool `json:"auto_keep"` + } `json:"flags"` + Raw struct { + Value int64 `json:"value"` + String string `json:"string"` + } `json:"raw"` + } `json:"table"` + } `json:"ata_smart_attributes"` + ScsiErrorCounterLog struct { + Read struct { + ErrorsCorrectedByEccfast int `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int `json:"total_uncorrected_errors"` + } `json:"read"` + Write struct { + ErrorsCorrectedByEccfast int `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int `json:"total_uncorrected_errors"` + } `json:"write"` + Verify struct { + ErrorsCorrectedByEccfast int `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int `json:"total_uncorrected_errors"` + } `json:"verify"` + } `json:"scsi_error_counter_log"` +} + +type smartctlScanJSON struct { + JSONFormatVersion []int `json:"json_format_version"` + Smartctl struct { + Version []int `json:"version"` + PreRelease bool `json:"pre_release"` + SvnRevision string `json:"svn_revision"` + PlatformInfo string `json:"platform_info"` + BuildInfo string `json:"build_info"` + Argv []string `json:"argv"` + ExitStatus int `json:"exit_status"` + } `json:"smartctl"` + Devices []struct { + Name string `json:"name"` + InfoName string `json:"info_name"` + Type string `json:"type"` + Protocol string `json:"protocol"` + } `json:"devices"` +} diff --git a/plugins/inputs/smartctl/smartctl_scan.go b/plugins/inputs/smartctl/smartctl_scan.go new file mode 100644 index 0000000000000..36784b61acff1 --- /dev/null +++ b/plugins/inputs/smartctl/smartctl_scan.go @@ -0,0 +1,46 @@ +package smartctl + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/influxdata/telegraf/internal" +) + +// This is here so we can override it during testing +var scanArgs = []string{"--json", "--scan"} + +type scanDevice struct { + Name string + Type string +} + +func (s *Smartctl) scan() ([]scanDevice, error) { + cmd := execCommand(s.Path, scanArgs...) + if s.UseSudo { + cmd = execCommand("sudo", append([]string{"-n", s.Path}, scanArgs...)...) + } + out, err := internal.CombinedOutputTimeout(cmd, time.Duration(s.Timeout)) + if err != nil { + return nil, fmt.Errorf("error running smartctl with %s: %w", scanArgs, err) + } + + var scan smartctlScanJSON + if err := json.Unmarshal(out, &scan); err != nil { + return nil, fmt.Errorf("error unmarshalling smartctl scan output: %w", err) + } + + devices := make([]scanDevice, 0) + for _, device := range scan.Devices { + if s.deviceFilter.Match(device.Name) { + device := scanDevice{ + Name: device.Name, + Type: device.Type, + } + devices = append(devices, device) + } + } + + return devices, nil +} diff --git a/plugins/inputs/smartctl/smartctl_test.go b/plugins/inputs/smartctl/smartctl_test.go new file mode 100644 index 0000000000000..7e3dde07a7ec7 --- /dev/null +++ b/plugins/inputs/smartctl/smartctl_test.go @@ -0,0 +1,195 @@ +package smartctl + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "slices" + "strconv" + "strings" + "testing" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf/plugins/parsers/influx" + "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/require" +) + +func TestCasesScan(t *testing.T) { + // Get all directories in testdata + folders, err := os.ReadDir("testcases_scan") + require.NoError(t, err) + + // Register the plugin + inputs.Add("smartctl", func() telegraf.Input { + return &Smartctl{} + }) + + for _, f := range folders { + if !f.IsDir() { + continue + } + testcasePath := filepath.Join("testcases_scan", f.Name()) + configFilename := filepath.Join(testcasePath, "telegraf.toml") + scanFilename := filepath.Join(testcasePath, "response.json") + expectedFilename := filepath.Join(testcasePath, "expected.out") + + t.Run(f.Name(), func(t *testing.T) { + parser := &influx.Parser{} + require.NoError(t, parser.Init()) + + // Read the expected output if any + var expected int + if _, err := os.Stat(expectedFilename); err == nil { + var err error + expectedBytes, err := os.ReadFile(expectedFilename) + require.NoError(t, err) + expected, err = strconv.Atoi(strings.TrimSpace(string(expectedBytes))) + require.NoError(t, err) + } + + // Update exec to return fake data. + execCommand = fakeScanExecCommand + defer func() { execCommand = exec.Command }() + + // Configure the plugin + cfg := config.NewConfig() + require.NoError(t, cfg.LoadConfig(configFilename)) + require.Len(t, cfg.Inputs, 1) + plugin := cfg.Inputs[0].Input.(*Smartctl) + require.NoError(t, plugin.Init()) + + scanArgs = append(scanArgs, scanFilename) + devices, err := plugin.scan() + require.NoError(t, err) + require.Len(t, devices, expected) + }) + } +} + +func fakeScanExecCommand(command string, args ...string) *exec.Cmd { + cs := []string{"-test.run=TestScanHelperProcess", "--", command} + cs = append(cs, args...) + cmd := exec.Command(os.Args[0], cs...) + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + return cmd +} + +func TestScanHelperProcess(_ *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + args := os.Args + + scanBytes, err := os.ReadFile(args[len(args)-1]) + if err != nil { + fmt.Fprint(os.Stdout, "unknown filename") + //nolint:revive // os.Exit called intentionally + os.Exit(42) + } + + fmt.Fprint(os.Stdout, string(scanBytes)) + //nolint:revive // os.Exit called intentionally + os.Exit(0) +} + +func TestCasesDevices(t *testing.T) { + // Get all directories in testdata + folders, err := os.ReadDir("testcases_device") + require.NoError(t, err) + + // Register the plugin + inputs.Add("smartctl", func() telegraf.Input { + return &Smartctl{} + }) + + for _, f := range folders { + if !f.IsDir() { + continue + } + testcasePath := filepath.Join("testcases_device", f.Name()) + deviceFilename := filepath.Join(testcasePath, "device") + deviceTypeFilename := filepath.Join(testcasePath, "deviceType") + expectedFilename := filepath.Join(testcasePath, "expected.out") + + t.Run(f.Name(), func(t *testing.T) { + parser := &influx.Parser{} + require.NoError(t, parser.Init()) + + // Read the expected output if any + var expected []telegraf.Metric + if _, err := os.Stat(expectedFilename); err == nil { + var err error + expected, err = testutil.ParseMetricsFromFile(expectedFilename, parser) + require.NoError(t, err) + } + + // Read the devices to scan + deviceBytes, err := os.ReadFile(deviceFilename) + require.NoError(t, err) + deviceTypeBytes, err := os.ReadFile(deviceTypeFilename) + require.NoError(t, err) + + // Update exec to return fake data. + execCommand = fakeDeviceExecCommand + defer func() { execCommand = exec.Command }() + + // Configure the plugin + plugin := Smartctl{} + require.NoError(t, plugin.Init()) + + var acc testutil.Accumulator + require.NoError(t, + plugin.scanDevice( + &acc, + strings.TrimSpace(string(deviceBytes)), + strings.TrimSpace(string(deviceTypeBytes)), + ), + ) + + // Check the metric nevertheless as we might get some metrics despite errors. + actual := acc.GetTelegrafMetrics() + testutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime()) + acc.Lock() + defer acc.Unlock() + require.Empty(t, acc.Errors) + }) + } +} + +func fakeDeviceExecCommand(command string, args ...string) *exec.Cmd { + cs := []string{"-test.run=TestDeviceHelperProcess", "--", command} + cs = append(cs, args...) + cmd := exec.Command(os.Args[0], cs...) + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + return cmd +} + +func TestDeviceHelperProcess(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + args := os.Args + + var filename string + if slices.Contains(args, "/dev/nvme0") { + filename = "testcases_device/nvme/response.json" + } else if slices.Contains(args, "/dev/sda") { + filename = "testcases_device/usb/response.json" + } else if slices.Contains(args, "/dev/bus/6") { + filename = "testcases_device/megaraid/response.json" + } else if slices.Contains(args, "/dev/sdb") { + filename = "testcases_device/scsi/response.json" + } else { + fmt.Fprint(os.Stdout, "unknown filename") + os.Exit(42) //nolint:revive // os.Exit called intentionally + } + + scanBytes, err := os.ReadFile(filename) + require.NoError(t, err) + fmt.Fprint(os.Stdout, string(scanBytes)) + os.Exit(0) //nolint:revive // os.Exit called intentionally +} diff --git a/plugins/inputs/smartctl/testcases_device/megaraid/device b/plugins/inputs/smartctl/testcases_device/megaraid/device new file mode 100644 index 0000000000000..474992ed4deb7 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/megaraid/device @@ -0,0 +1 @@ +/dev/bus/6 diff --git a/plugins/inputs/smartctl/testcases_device/megaraid/deviceType b/plugins/inputs/smartctl/testcases_device/megaraid/deviceType new file mode 100644 index 0000000000000..62c2cd720a5ca --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/megaraid/deviceType @@ -0,0 +1 @@ +megaraid,14 diff --git a/plugins/inputs/smartctl/testcases_device/megaraid/expected.out b/plugins/inputs/smartctl/testcases_device/megaraid/expected.out new file mode 100644 index 0000000000000..4d242d4747ef1 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/megaraid/expected.out @@ -0,0 +1,25 @@ +smartctl,model=ST6000NM0115-1YZ110,name=/dev/bus/6,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d capacity=6001175126016i,firmware="SN04",health_ok=true,temperature=25i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Raw_Read_Error_Rate,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=181426040i,threshold=44i,value=83i,worst=64i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Spin_Up_Time,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=91i,worst=91i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Start_Stop_Count,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=62i,threshold=20i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Reallocated_Sector_Ct,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=10i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Seek_Error_Rate,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=2827960730i,threshold=45i,value=95i,worst=60i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Power_On_Hours,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=44316i,threshold=0i,value=50i,worst=50i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Spin_Retry_Count,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=97i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Power_Cycle_Count,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=62i,threshold=20i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=End-to-End_Error,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=99i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Reported_Uncorrect,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Command_Timeout,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=High_Fly_Writes,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Airflow_Temperature_Cel,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=504627225i,threshold=40i,value=75i,worst=64i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=G-Sense_Error_Rate,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=3295i,threshold=0i,value=99i,worst=99i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Power-Off_Retract_Count,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=1865i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Load_Cycle_Count,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=1894i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Temperature_Celsius,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=30064771097i,threshold=0i,value=25i,worst=40i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Hardware_ECC_Recovered,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=181426040i,threshold=0i,value=83i,worst=64i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Current_Pending_Sector,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Offline_Uncorrectable,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=100i,worst=100i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=UDMA_CRC_Error_Count,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=0i,threshold=0i,value=200i,worst=200i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Head_Flying_Hours,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=1265348905053451i,threshold=0i,value=100i,worst=253i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Total_LBAs_Written,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=28111553262i,threshold=0i,value=100i,worst=253i 1711726425026052398 +smartctl_attributes,model=ST6000NM0115-1YZ110,name=Total_LBAs_Read,serial=ZAD2C11G,type=sat+megaraid\,14,wwn=5000c500a496983d raw_value=3197497186480i,threshold=0i,value=100i,worst=253i 1711726425026052398 diff --git a/plugins/inputs/smartctl/testcases_device/megaraid/response.json b/plugins/inputs/smartctl/testcases_device/megaraid/response.json new file mode 100644 index 0000000000000..9c92c077bc968 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/megaraid/response.json @@ -0,0 +1,733 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 1 + ], + "svn_revision": "5022", + "platform_info": "x86_64-linux-5.4.0-172-generic", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--json", + "--all", + "/dev/bus/6", + "--device", + "megaraid,14", + "--nocheck=standby" + ], + "messages": [ + { + "string": "Warning: This result is based on an Attribute check.", + "severity": "warning" + } + ], + "exit_status": 4 + }, + "device": { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_14] [SAT]", + "type": "sat+megaraid,14", + "protocol": "ATA" + }, + "model_family": "Seagate Enterprise Capacity 3.5 HDD", + "model_name": "ST6000NM0115-1YZ110", + "serial_number": "ZAD2C11G", + "wwn": { + "naa": 5, + "oui": 3152, + "id": 2761332797 + }, + "firmware_version": "SN04", + "user_capacity": { + "blocks": 11721045168, + "bytes": 6001175126016 + }, + "logical_block_size": 512, + "physical_block_size": 4096, + "rotation_rate": 7200, + "form_factor": { + "ata_value": 2, + "name": "3.5 inches" + }, + "in_smartctl_database": true, + "ata_version": { + "string": "ACS-3 T13/2161-D revision 5", + "major_value": 2032, + "minor_value": 109 + }, + "sata_version": { + "string": "SATA 3.1", + "value": 127 + }, + "interface_speed": { + "max": { + "sata_value": 14, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + }, + "current": { + "sata_value": 3, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + } + }, + "local_time": { + "time_t": 1711639509, + "asctime": "Thu Mar 28 16:25:09 2024 CET" + }, + "smart_status": { + "passed": true + }, + "ata_smart_data": { + "offline_data_collection": { + "status": { + "value": 130, + "string": "was completed without error", + "passed": true + }, + "completion_seconds": 567 + }, + "self_test": { + "status": { + "value": 0, + "string": "completed without error", + "passed": true + }, + "polling_minutes": { + "short": 1, + "extended": 584, + "conveyance": 2 + } + }, + "capabilities": { + "values": [ + 123, + 3 + ], + "exec_offline_immediate_supported": true, + "offline_is_aborted_upon_new_cmd": false, + "offline_surface_scan_supported": true, + "self_tests_supported": true, + "conveyance_self_test_supported": true, + "selective_self_test_supported": true, + "attribute_autosave_enabled": true, + "error_logging_supported": true, + "gp_logging_supported": true + } + }, + "ata_sct_capabilities": { + "value": 28861, + "error_recovery_control_supported": true, + "feature_control_supported": true, + "data_table_supported": true + }, + "ata_smart_attributes": { + "revision": 10, + "table": [ + { + "id": 1, + "name": "Raw_Read_Error_Rate", + "value": 83, + "worst": 64, + "thresh": 44, + "when_failed": "", + "flags": { + "value": 15, + "string": "POSR-- ", + "prefailure": true, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 181426040, + "string": "181426040" + } + }, + { + "id": 3, + "name": "Spin_Up_Time", + "value": 91, + "worst": 91, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 3, + "string": "PO---- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 4, + "name": "Start_Stop_Count", + "value": 100, + "worst": 100, + "thresh": 20, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 62, + "string": "62" + } + }, + { + "id": 5, + "name": "Reallocated_Sector_Ct", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 51, + "string": "PO--CK ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 7, + "name": "Seek_Error_Rate", + "value": 95, + "worst": 60, + "thresh": 45, + "when_failed": "", + "flags": { + "value": 15, + "string": "POSR-- ", + "prefailure": true, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 2827960730, + "string": "2827960730" + } + }, + { + "id": 9, + "name": "Power_On_Hours", + "value": 50, + "worst": 50, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 44316, + "string": "44316" + } + }, + { + "id": 10, + "name": "Spin_Retry_Count", + "value": 100, + "worst": 100, + "thresh": 97, + "when_failed": "", + "flags": { + "value": 19, + "string": "PO--C- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 12, + "name": "Power_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 20, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 62, + "string": "62" + } + }, + { + "id": 184, + "name": "End-to-End_Error", + "value": 100, + "worst": 100, + "thresh": 99, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 187, + "name": "Reported_Uncorrect", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 188, + "name": "Command_Timeout", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0 0 0" + } + }, + { + "id": 189, + "name": "High_Fly_Writes", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 58, + "string": "-O-RCK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 190, + "name": "Airflow_Temperature_Cel", + "value": 75, + "worst": 64, + "thresh": 40, + "when_failed": "", + "flags": { + "value": 34, + "string": "-O---K ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 504627225, + "string": "25 (Min/Max 20/30)" + } + }, + { + "id": 191, + "name": "G-Sense_Error_Rate", + "value": 99, + "worst": 99, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 3295, + "string": "3295" + } + }, + { + "id": 192, + "name": "Power-Off_Retract_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 1865, + "string": "1865" + } + }, + { + "id": 193, + "name": "Load_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 1894, + "string": "1894" + } + }, + { + "id": 194, + "name": "Temperature_Celsius", + "value": 25, + "worst": 40, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 34, + "string": "-O---K ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 30064771097, + "string": "25 (0 7 0 0 0)" + } + }, + { + "id": 195, + "name": "Hardware_ECC_Recovered", + "value": 83, + "worst": 64, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 26, + "string": "-O-RC- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 181426040, + "string": "181426040" + } + }, + { + "id": 197, + "name": "Current_Pending_Sector", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 198, + "name": "Offline_Uncorrectable", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 16, + "string": "----C- ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 199, + "name": "UDMA_CRC_Error_Count", + "value": 200, + "worst": 200, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 62, + "string": "-OSRCK ", + "prefailure": false, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 240, + "name": "Head_Flying_Hours", + "value": 100, + "worst": 253, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 0, + "string": "------ ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 1265348905053451, + "string": "44299h+04m+54.612s" + } + }, + { + "id": 241, + "name": "Total_LBAs_Written", + "value": 100, + "worst": 253, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 0, + "string": "------ ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 28111553262, + "string": "28111553262" + } + }, + { + "id": 242, + "name": "Total_LBAs_Read", + "value": 100, + "worst": 253, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 0, + "string": "------ ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 3197497186480, + "string": "3197497186480" + } + } + ] + }, + "power_on_time": { + "hours": 44316 + }, + "power_cycle_count": 62, + "temperature": { + "current": 25 + }, + "ata_smart_error_log": { + "summary": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_self_test_log": { + "standard": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_selective_self_test_log": { + "revision": 1, + "table": [ + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + } + ], + "flags": { + "value": 0, + "remainder_scan_enabled": false + }, + "power_up_scan_resume_minutes": 0 + } +} diff --git a/plugins/inputs/smartctl/testcases_device/nvme/device b/plugins/inputs/smartctl/testcases_device/nvme/device new file mode 100644 index 0000000000000..a6a0c2fbc79b5 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/nvme/device @@ -0,0 +1 @@ +/dev/nvme0 diff --git a/plugins/inputs/smartctl/testcases_device/nvme/deviceType b/plugins/inputs/smartctl/testcases_device/nvme/deviceType new file mode 100644 index 0000000000000..9158fff478b2a --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/nvme/deviceType @@ -0,0 +1 @@ +nvme diff --git a/plugins/inputs/smartctl/testcases_device/nvme/expected.out b/plugins/inputs/smartctl/testcases_device/nvme/expected.out new file mode 100644 index 0000000000000..f8316ab3708af --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/nvme/expected.out @@ -0,0 +1 @@ +smartctl,model=Sabrent\ Rocket\ 4.0\ 1TB,name=/dev/nvme0,serial=6D1107091C9583054511,type=nvme available_spare=100i,available_spare_threshold=5i,capacity=1000204886016i,controller_busy_time=1635i,critical_comp_time=0i,critical_warning=0i,data_units_read=28337502i,data_units_written=76471882i,firmware="RKT401.3",health_ok=true,host_reads=294243226i,host_writes=733021025i,media_errors=0i,num_err_log_entries=4871i,percentage_used=4i,power_cycles=1815i,power_on_hours=8733i,temperature=48i,unsafe_shutdowns=39i,warning_temp_time=0i 1711480345635747372 diff --git a/plugins/inputs/smartctl/testcases_device/nvme/response.json b/plugins/inputs/smartctl/testcases_device/nvme/response.json new file mode 100644 index 0000000000000..814527a750836 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/nvme/response.json @@ -0,0 +1,145 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 4 + ], + "pre_release": false, + "svn_revision": "5530", + "platform_info": "x86_64-linux-6.8.1-arch1-1", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-a", + "-d", + "nvme", + "/dev/nvme0", + "--json" + ], + "exit_status": 0 + }, + "local_time": { + "time_t": 1711371013, + "asctime": "Mon Mar 25 06:50:13 2024 MDT" + }, + "device": { + "name": "/dev/nvme0", + "info_name": "/dev/nvme0", + "type": "nvme", + "protocol": "NVMe" + }, + "model_name": "Sabrent Rocket 4.0 1TB", + "serial_number": "6D1107091C9583054511", + "firmware_version": "RKT401.3", + "nvme_pci_vendor": { + "id": 6535, + "subsystem_id": 6535 + }, + "nvme_ieee_oui_identifier": 6584743, + "nvme_total_capacity": 1000204886016, + "nvme_unallocated_capacity": 0, + "nvme_controller_id": 1, + "nvme_version": { + "string": "1.3", + "value": 66304 + }, + "nvme_number_of_namespaces": 1, + "nvme_namespaces": [ + { + "id": 1, + "size": { + "blocks": 1953525168, + "bytes": 1000204886016 + }, + "capacity": { + "blocks": 1953525168, + "bytes": 1000204886016 + }, + "utilization": { + "blocks": 1953525168, + "bytes": 1000204886016 + }, + "formatted_lba_size": 512, + "eui64": { + "oui": 6584743, + "ext_id": 268705991866 + } + } + ], + "user_capacity": { + "blocks": 1953525168, + "bytes": 1000204886016 + }, + "logical_block_size": 512, + "smart_support": { + "available": true, + "enabled": true + }, + "smart_status": { + "passed": true, + "nvme": { + "value": 0 + } + }, + "nvme_smart_health_information_log": { + "critical_warning": 0, + "temperature": 48, + "available_spare": 100, + "available_spare_threshold": 5, + "percentage_used": 4, + "data_units_read": 28337502, + "data_units_written": 76471882, + "host_reads": 294243226, + "host_writes": 733021025, + "controller_busy_time": 1635, + "power_cycles": 1815, + "power_on_hours": 8733, + "unsafe_shutdowns": 39, + "media_errors": 0, + "num_err_log_entries": 4871, + "warning_temp_time": 0, + "critical_comp_time": 0 + }, + "temperature": { + "current": 48 + }, + "power_cycle_count": 1815, + "power_on_time": { + "hours": 8733 + }, + "nvme_error_information_log": { + "size": 63, + "read": 16, + "unread": 0, + "table": [ + { + "error_count": 4871, + "submission_queue_id": 0, + "command_id": 20495, + "status_field": { + "value": 8194, + "do_not_retry": false, + "status_code_type": 0, + "status_code": 2, + "string": "Invalid Field in Command" + }, + "phase_tag": false, + "parm_error_location": 40, + "lba": { + "value": 0 + }, + "nsid": 0 + } + ] + }, + "nvme_self_test_log": { + "current_self_test_operation": { + "value": 0, + "string": "No self-test in progress" + } + } +} diff --git a/plugins/inputs/smartctl/testcases_device/scsi/device b/plugins/inputs/smartctl/testcases_device/scsi/device new file mode 100644 index 0000000000000..32962ffd4f83a --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/scsi/device @@ -0,0 +1 @@ +/dev/sdb diff --git a/plugins/inputs/smartctl/testcases_device/scsi/deviceType b/plugins/inputs/smartctl/testcases_device/scsi/deviceType new file mode 100644 index 0000000000000..7e90c4b42440a --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/scsi/deviceType @@ -0,0 +1 @@ +scsi diff --git a/plugins/inputs/smartctl/testcases_device/scsi/expected.out b/plugins/inputs/smartctl/testcases_device/scsi/expected.out new file mode 100644 index 0000000000000..1994b51ccc6a9 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/scsi/expected.out @@ -0,0 +1,4 @@ +smartctl,model=XXXX\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,vendor=XXXXXXX capacity=13715978077777i,firmware="",health_ok=true,temperature=24i 1712071085987864368 +smartctl_scsi_error_counter_log,model=XXXX\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,page=read,vendor=XXXXXXX correction_algorithm_invocations=0i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=1i,errors_corrected_by_rereads_rewrites=5i,gigabytes_processed="315926.142",total_errors_corrected=3i,total_uncorrected_errors=0i 1712071085987864368 +smartctl_scsi_error_counter_log,model=XXXX\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,page=write,vendor=XXXXXXX correction_algorithm_invocations=20i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=0i,errors_corrected_by_rereads_rewrites=20i,gigabytes_processed="132513.233",total_errors_corrected=20i,total_uncorrected_errors=0i 1712071085987864368 +smartctl_scsi_error_counter_log,model=XXXX\ XX0000NM123,name=/dev/sdb,serial=XXXXXXX,type=scsi,page=verify,vendor=XXXXXXX correction_algorithm_invocations=0i,errors_corrected_by_eccdelayed=0i,errors_corrected_by_eccfast=12i,errors_corrected_by_rereads_rewrites=0i,gigabytes_processed="1437.032",total_errors_corrected=3i,total_uncorrected_errors=0i 1712071085987864368 diff --git a/plugins/inputs/smartctl/testcases_device/scsi/response.json b/plugins/inputs/smartctl/testcases_device/scsi/response.json new file mode 100644 index 0000000000000..bc821a6bb035d --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/scsi/response.json @@ -0,0 +1,96 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 2 + ], + "svn_revision": "5123", + "platform_info": "x86_64-linux-4.12.0-1-amd64", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--json", + "--all", + "/dev/sdb", + "--device", + "scsi" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/sdb", + "info_name": "/dev/sdb", + "type": "scsi", + "protocol": "SCSI" + }, + "vendor": "XXXXXXX", + "product": "XXXX000OOOO", + "model_name": "XXXX XX0000NM123", + "revision": "RSL5", + "scsi_version": "SPC-5", + "user_capacity": { + "blocks": 26789019888, + "bytes": 13715978077777 + }, + "logical_block_size": 512, + "physical_block_size": 4096, + "rotation_rate": 7200, + "form_factor": { + "scsi_value": 3, + "name": "3.5 inches" + }, + "serial_number": "XXXXXXX", + "device_type": { + "scsi_value": 0, + "name": "disk" + }, + "local_time": { + "time_t": 1711977687, + "asctime": "Sun Mar 31 13:21:27 2024 UTC" + }, + "smart_status": { + "passed": true + }, + "temperature": { + "current": 24, + "drive_trip": 60 + }, + "power_on_time": { + "hours": 32978, + "minutes": 46 + }, + "scsi_grown_defect_list": 0, + "scsi_error_counter_log": { + "read": { + "errors_corrected_by_eccfast": 1, + "errors_corrected_by_eccdelayed": 0, + "errors_corrected_by_rereads_rewrites": 5, + "total_errors_corrected": 3, + "correction_algorithm_invocations": 0, + "gigabytes_processed": "315926.142", + "total_uncorrected_errors": 0 + }, + "write": { + "errors_corrected_by_eccfast": 0, + "errors_corrected_by_eccdelayed": 0, + "errors_corrected_by_rereads_rewrites": 20, + "total_errors_corrected": 20, + "correction_algorithm_invocations": 20, + "gigabytes_processed": "132513.233", + "total_uncorrected_errors": 0 + }, + "verify": { + "errors_corrected_by_eccfast": 12, + "errors_corrected_by_eccdelayed": 0, + "errors_corrected_by_rereads_rewrites": 0, + "total_errors_corrected": 3, + "correction_algorithm_invocations": 0, + "gigabytes_processed": "1437.032", + "total_uncorrected_errors": 0 + } + } +} diff --git a/plugins/inputs/smartctl/testcases_device/usb/device b/plugins/inputs/smartctl/testcases_device/usb/device new file mode 100644 index 0000000000000..c7b6a1bc03332 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/usb/device @@ -0,0 +1 @@ +/dev/sda diff --git a/plugins/inputs/smartctl/testcases_device/usb/deviceType b/plugins/inputs/smartctl/testcases_device/usb/deviceType new file mode 100644 index 0000000000000..6b8a2c3d2dbc9 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/usb/deviceType @@ -0,0 +1 @@ +sat diff --git a/plugins/inputs/smartctl/testcases_device/usb/expected.out b/plugins/inputs/smartctl/testcases_device/usb/expected.out new file mode 100644 index 0000000000000..3eadb53dde1d2 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/usb/expected.out @@ -0,0 +1,14 @@ +smartctl,model=SanDisk\ pSSD,name=/dev/sda,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c capacity=15693664256i,firmware="3",health_ok=true,temperature=0i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Reallocated_Sector_Ct,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Power_On_Hours,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=11i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Power_Cycle_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=223i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Program_Fail_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Erase_Fail_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Avg_Write/Erase_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=3i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Unexpect_Power_Loss_Ct,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=114i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Reported_Uncorrect,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Perc_Write/Erase_Count,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=10i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Perc_Avail_Resrvd_Space,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=5i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Perc_Write/Erase_Ct_BC,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=0i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Total_LBAs_Written,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=10171055i,threshold=0i,value=100i,worst=100i 1711480345675066854 +smartctl_attributes,model=SanDisk\ pSSD,name=Total_LBAs_Read,serial=06c9f4c44,type=sat,wwn=5001b4409f6c444c raw_value=94845144i,threshold=0i,value=100i,worst=100i 1711480345675066854 diff --git a/plugins/inputs/smartctl/testcases_device/usb/response.json b/plugins/inputs/smartctl/testcases_device/usb/response.json new file mode 100644 index 0000000000000..dedeef0460f96 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_device/usb/response.json @@ -0,0 +1,486 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 4 + ], + "pre_release": false, + "svn_revision": "5530", + "platform_info": "x86_64-linux-6.8.1-arch1-1", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-a", + "-d", + "sat", + "/dev/sda", + "--json" + ], + "drive_database_version": { + "string": "7.3/5528" + }, + "exit_status": 0 + }, + "local_time": { + "time_t": 1711370961, + "asctime": "Mon Mar 25 06:49:21 2024 MDT" + }, + "device": { + "name": "/dev/sda", + "info_name": "/dev/sda [SAT]", + "type": "sat", + "protocol": "ATA" + }, + "model_family": "SanDisk based SSDs", + "model_name": "SanDisk pSSD", + "serial_number": "06c9f4c44", + "wwn": { + "naa": 5, + "oui": 6980, + "id": 2674672716 + }, + "firmware_version": "3", + "user_capacity": { + "blocks": 30651688, + "bytes": 15693664256 + }, + "logical_block_size": 512, + "physical_block_size": 512, + "rotation_rate": 0, + "form_factor": { + "ata_value": 4, + "name": "1.8 inches" + }, + "trim": { + "supported": true, + "deterministic": true, + "zeroed": true + }, + "in_smartctl_database": true, + "ata_version": { + "string": "ATA8-ACS T13/1699-D revision 2d", + "major_value": 496, + "minor_value": 263 + }, + "sata_version": { + "string": "SATA 2.6", + "value": 17 + }, + "interface_speed": { + "max": { + "sata_value": 14, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + }, + "current": { + "sata_value": 2, + "string": "3.0 Gb/s", + "units_per_second": 30, + "bits_per_unit": 100000000 + } + }, + "smart_support": { + "available": true, + "enabled": true + }, + "smart_status": { + "passed": true + }, + "ata_smart_data": { + "offline_data_collection": { + "status": { + "value": 0, + "string": "was never started" + }, + "completion_seconds": 120 + }, + "self_test": { + "status": { + "value": 0, + "string": "completed without error", + "passed": true + }, + "polling_minutes": { + "short": 2, + "extended": 3 + } + }, + "capabilities": { + "values": [ + 81, + 3 + ], + "exec_offline_immediate_supported": true, + "offline_is_aborted_upon_new_cmd": false, + "offline_surface_scan_supported": false, + "self_tests_supported": true, + "conveyance_self_test_supported": false, + "selective_self_test_supported": true, + "attribute_autosave_enabled": true, + "error_logging_supported": true, + "gp_logging_supported": true + } + }, + "ata_smart_attributes": { + "revision": 1, + "table": [ + { + "id": 5, + "name": "Reallocated_Sector_Ct", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 9, + "name": "Power_On_Hours", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 11, + "string": "11" + } + }, + { + "id": 12, + "name": "Power_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 223, + "string": "223" + } + }, + { + "id": 171, + "name": "Program_Fail_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 172, + "name": "Erase_Fail_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 173, + "name": "Avg_Write/Erase_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 3, + "string": "3" + } + }, + { + "id": 174, + "name": "Unexpect_Power_Loss_Ct", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 114, + "string": "114" + } + }, + { + "id": 187, + "name": "Reported_Uncorrect", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 230, + "name": "Perc_Write/Erase_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 10, + "string": "10" + } + }, + { + "id": 232, + "name": "Perc_Avail_Resrvd_Space", + "value": 100, + "worst": 100, + "thresh": 5, + "when_failed": "", + "flags": { + "value": 3, + "string": "PO---- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 234, + "name": "Perc_Write/Erase_Ct_BC", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 241, + "name": "Total_LBAs_Written", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 10171055, + "string": "10171055" + } + }, + { + "id": 242, + "name": "Total_LBAs_Read", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 94845144, + "string": "94845144" + } + } + ] + }, + "power_on_time": { + "hours": 11 + }, + "power_cycle_count": 223, + "ata_smart_error_log": { + "summary": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_self_test_log": { + "standard": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_selective_self_test_log": { + "revision": 1, + "table": [ + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + } + ], + "flags": { + "value": 0, + "remainder_scan_enabled": false + }, + "power_up_scan_resume_minutes": 0 + } +} diff --git a/plugins/inputs/smartctl/testcases_scan/all/expected.out b/plugins/inputs/smartctl/testcases_scan/all/expected.out new file mode 100644 index 0000000000000..00750edc07d64 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/all/expected.out @@ -0,0 +1 @@ +3 diff --git a/plugins/inputs/smartctl/testcases_scan/all/response.json b/plugins/inputs/smartctl/testcases_scan/all/response.json new file mode 100644 index 0000000000000..8cb1cf4298893 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/all/response.json @@ -0,0 +1,42 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 4 + ], + "pre_release": false, + "svn_revision": "5530", + "platform_info": "x86_64-linux-6.8.1-arch1-1", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--scan", + "--json" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/sda", + "info_name": "/dev/sda [SAT]", + "type": "sat", + "protocol": "ATA" + }, + { + "name": "/dev/nvme0", + "info_name": "/dev/nvme0", + "type": "nvme", + "protocol": "NVMe" + }, + { + "name": "/dev/nvme1", + "info_name": "/dev/nvme1", + "type": "nvme", + "protocol": "NVMe" + } + ] +} diff --git a/plugins/inputs/smartctl/testcases_scan/all/telegraf.toml b/plugins/inputs/smartctl/testcases_scan/all/telegraf.toml new file mode 100644 index 0000000000000..6cd853f61d473 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/all/telegraf.toml @@ -0,0 +1 @@ +[[inputs.smartctl]] diff --git a/plugins/inputs/smartctl/testcases_scan/exclude/expected.out b/plugins/inputs/smartctl/testcases_scan/exclude/expected.out new file mode 100644 index 0000000000000..d00491fd7e5bb --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/exclude/expected.out @@ -0,0 +1 @@ +1 diff --git a/plugins/inputs/smartctl/testcases_scan/exclude/response.json b/plugins/inputs/smartctl/testcases_scan/exclude/response.json new file mode 100644 index 0000000000000..8cb1cf4298893 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/exclude/response.json @@ -0,0 +1,42 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 4 + ], + "pre_release": false, + "svn_revision": "5530", + "platform_info": "x86_64-linux-6.8.1-arch1-1", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--scan", + "--json" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/sda", + "info_name": "/dev/sda [SAT]", + "type": "sat", + "protocol": "ATA" + }, + { + "name": "/dev/nvme0", + "info_name": "/dev/nvme0", + "type": "nvme", + "protocol": "NVMe" + }, + { + "name": "/dev/nvme1", + "info_name": "/dev/nvme1", + "type": "nvme", + "protocol": "NVMe" + } + ] +} diff --git a/plugins/inputs/smartctl/testcases_scan/exclude/telegraf.toml b/plugins/inputs/smartctl/testcases_scan/exclude/telegraf.toml new file mode 100644 index 0000000000000..0a3f7b2987527 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/exclude/telegraf.toml @@ -0,0 +1,2 @@ +[[inputs.smartctl]] + devices_exclude = ["/dev/nvme0", "/dev/nvme1"] diff --git a/plugins/inputs/smartctl/testcases_scan/include/expected.out b/plugins/inputs/smartctl/testcases_scan/include/expected.out new file mode 100644 index 0000000000000..d00491fd7e5bb --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/include/expected.out @@ -0,0 +1 @@ +1 diff --git a/plugins/inputs/smartctl/testcases_scan/include/response.json b/plugins/inputs/smartctl/testcases_scan/include/response.json new file mode 100644 index 0000000000000..8cb1cf4298893 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/include/response.json @@ -0,0 +1,42 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 4 + ], + "pre_release": false, + "svn_revision": "5530", + "platform_info": "x86_64-linux-6.8.1-arch1-1", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--scan", + "--json" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/sda", + "info_name": "/dev/sda [SAT]", + "type": "sat", + "protocol": "ATA" + }, + { + "name": "/dev/nvme0", + "info_name": "/dev/nvme0", + "type": "nvme", + "protocol": "NVMe" + }, + { + "name": "/dev/nvme1", + "info_name": "/dev/nvme1", + "type": "nvme", + "protocol": "NVMe" + } + ] +} diff --git a/plugins/inputs/smartctl/testcases_scan/include/telegraf.toml b/plugins/inputs/smartctl/testcases_scan/include/telegraf.toml new file mode 100644 index 0000000000000..82d4e111476df --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/include/telegraf.toml @@ -0,0 +1,2 @@ +[[inputs.smartctl]] + devices_include = ["/dev/sda"] diff --git a/plugins/inputs/smartctl/testcases_scan/megaraid/expected.out b/plugins/inputs/smartctl/testcases_scan/megaraid/expected.out new file mode 100644 index 0000000000000..f599e28b8ab0d --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/megaraid/expected.out @@ -0,0 +1 @@ +10 diff --git a/plugins/inputs/smartctl/testcases_scan/megaraid/response.json b/plugins/inputs/smartctl/testcases_scan/megaraid/response.json new file mode 100644 index 0000000000000..b41f469fb4888 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/megaraid/response.json @@ -0,0 +1,83 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 1 + ], + "svn_revision": "5022", + "platform_info": "x86_64-linux-5.4.0-172-generic", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--scan", + "--json" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/sda", + "info_name": "/dev/sda", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdb", + "info_name": "/dev/sdb", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdc", + "info_name": "/dev/sdc [SAT]", + "type": "sat", + "protocol": "ATA" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_08]", + "type": "megaraid,8", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_09]", + "type": "megaraid,9", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_10]", + "type": "megaraid,10", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_11]", + "type": "megaraid,11", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_12]", + "type": "megaraid,12", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_13]", + "type": "megaraid,13", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/6", + "info_name": "/dev/bus/6 [megaraid_disk_14]", + "type": "megaraid,14", + "protocol": "SCSI" + } + ] +} diff --git a/plugins/inputs/smartctl/testcases_scan/megaraid/telegraf.toml b/plugins/inputs/smartctl/testcases_scan/megaraid/telegraf.toml new file mode 100644 index 0000000000000..6cd853f61d473 --- /dev/null +++ b/plugins/inputs/smartctl/testcases_scan/megaraid/telegraf.toml @@ -0,0 +1 @@ +[[inputs.smartctl]]