diff --git a/collectors/ipmiMetric.go b/collectors/ipmiMetric.go index 32c4c45..69e03ee 100644 --- a/collectors/ipmiMetric.go +++ b/collectors/ipmiMetric.go @@ -1,51 +1,58 @@ package collectors import ( + "bufio" + "bytes" "encoding/json" "errors" + "fmt" + "io" "log" - "os" "os/exec" "strconv" "strings" "time" + cclog "github.com/ClusterCockpit/cc-metric-collector/pkg/ccLogger" lp "github.com/ClusterCockpit/cc-metric-collector/pkg/ccMetric" ) -const IPMITOOL_PATH = `ipmitool` const IPMISENSORS_PATH = `ipmi-sensors` -type IpmiCollectorConfig struct { - ExcludeDevices []string `json:"exclude_devices"` - IpmitoolPath string `json:"ipmitool_path"` - IpmisensorsPath string `json:"ipmisensors_path"` -} - type IpmiCollector struct { metricCollector - //tags map[string]string - //matches map[string]string - config IpmiCollectorConfig + config struct { + ExcludeDevices []string `json:"exclude_devices"` + IpmitoolPath string `json:"ipmitool_path"` + IpmisensorsPath string `json:"ipmisensors_path"` + } ipmitool string ipmisensors string } func (m *IpmiCollector) Init(config json.RawMessage) error { + // Check if already initialized + if m.init { + return nil + } + m.name = "IpmiCollector" m.setup() m.parallel = true - m.meta = map[string]string{"source": m.name, "group": "IPMI"} - m.config.IpmitoolPath = string(IPMITOOL_PATH) - m.config.IpmisensorsPath = string(IPMISENSORS_PATH) - m.ipmitool = "" - m.ipmisensors = "" + m.meta = map[string]string{ + "source": m.name, + "group": "IPMI", + } + // default path to IPMI tools + m.config.IpmitoolPath = "ipmitool" + m.config.IpmisensorsPath = "ipmi-sensors" if len(config) > 0 { err := json.Unmarshal(config, &m.config) if err != nil { return err } } + // Check if executables ipmitool or ipmisensors are found p, err := exec.LookPath(m.config.IpmitoolPath) if err == nil { m.ipmitool = p @@ -62,25 +69,33 @@ func (m *IpmiCollector) Init(config json.RawMessage) error { } func (m *IpmiCollector) readIpmiTool(cmd string, output chan lp.CCMetric) { + + // Setup ipmitool command command := exec.Command(cmd, "sensor") - command.Wait() - stdout, err := command.Output() - if err != nil { - log.Print(err) + stdout, _ := command.StdoutPipe() + errBuf := new(bytes.Buffer) + command.Stderr = errBuf + + // start command + if err := command.Start(); err != nil { + cclog.ComponentError( + m.name, + fmt.Sprintf("readIpmiTool(): Failed to start command \"%s\": %v", command.String(), err), + ) return } - ll := strings.Split(string(stdout), "\n") - - for _, line := range ll { - lv := strings.Split(line, "|") + // Read command output + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + lv := strings.Split(scanner.Text(), "|") if len(lv) < 3 { continue } - v, err := strconv.ParseFloat(strings.Trim(lv[1], " "), 64) + v, err := strconv.ParseFloat(strings.TrimSpace(lv[1]), 64) if err == nil { - name := strings.ToLower(strings.Replace(strings.Trim(lv[0], " "), " ", "_", -1)) - unit := strings.Trim(lv[2], " ") + name := strings.ToLower(strings.Replace(strings.TrimSpace(lv[0]), " ", "_", -1)) + unit := strings.TrimSpace(lv[2]) if unit == "Volts" { unit = "Volts" } else if unit == "degrees C" { @@ -98,6 +113,17 @@ func (m *IpmiCollector) readIpmiTool(cmd string, output chan lp.CCMetric) { } } } + + // Wait for command end + if err := command.Wait(); err != nil { + errMsg, _ := io.ReadAll(errBuf) + cclog.ComponentError( + m.name, + fmt.Sprintf("readIpmiTool(): Failed to wait for the end of command \"%s\": %v\n", command.String(), err), + fmt.Sprintf("readIpmiTool(): command stderr: \"%s\"\n", string(errMsg)), + ) + return + } } func (m *IpmiCollector) readIpmiSensors(cmd string, output chan lp.CCMetric) { @@ -131,16 +157,16 @@ func (m *IpmiCollector) readIpmiSensors(cmd string, output chan lp.CCMetric) { } func (m *IpmiCollector) Read(interval time.Duration, output chan lp.CCMetric) { + + // Check if already initialized + if !m.init { + return + } + if len(m.config.IpmitoolPath) > 0 { - _, err := os.Stat(m.config.IpmitoolPath) - if err == nil { - m.readIpmiTool(m.config.IpmitoolPath, output) - } + m.readIpmiTool(m.config.IpmitoolPath, output) } else if len(m.config.IpmisensorsPath) > 0 { - _, err := os.Stat(m.config.IpmisensorsPath) - if err == nil { - m.readIpmiSensors(m.config.IpmisensorsPath, output) - } + m.readIpmiSensors(m.config.IpmisensorsPath, output) } }