//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 while scanning system: %w", err) } for _, device := range devices { if err := s.scanDevice(acc, device.Name, device.Type); err != nil { return fmt.Errorf("error while 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), } }) }