mirror of
				https://github.com/ClusterCockpit/cc-metric-collector.git
				synced 2025-11-04 10:45:06 +01:00 
			
		
		
		
	Run ipmitool asynchron. Improved error handling.
This commit is contained in:
		@@ -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)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user