// Fallback inventory parsing for the per-file dump__/ onekeylog // layout, which has no combined devicefrusdr.log. Instead FRU and sensors live in // separate ipmitool-output text files under component/. package inspur import ( "bufio" "strconv" "strings" "git.mchus.pro/mchus/logpile/internal/models" ) // ParseSensorList parses component/sensor.txt ("ipmitool sensor list" output). // Line format: Name | Value | Unit | Status | lnr | lcr | lnc | unc | ucr | unr func ParseSensorList(content []byte) []models.SensorReading { var readings []models.SensorReading scanner := bufio.NewScanner(strings.NewReader(string(content))) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || !strings.Contains(line, "|") { continue } fields := strings.Split(line, "|") if len(fields) < 4 { continue } name := strings.TrimSpace(fields[0]) valueStr := strings.TrimSpace(fields[1]) unit := strings.TrimSpace(fields[2]) status := strings.TrimSpace(fields[3]) if name == "" { continue } reading := models.SensorReading{ Name: name, Status: status, Unit: unit, Type: determineSensorType(name), } if valueStr != "" && valueStr != "na" { if v, err := strconv.ParseFloat(valueStr, 64); err == nil { reading.Value = v reading.RawValue = valueStr + " " + unit } else { reading.RawValue = valueStr } } readings = append(readings, reading) } return readings } // ParseSDRElist parses component/sdr.txt ("ipmitool sdr elist" output), used as a // fallback when component/sensor.txt is unavailable. // Line format: Name | ID | Status | Entity | Reading (e.g. "21 degrees C" or "no reading") func ParseSDRElist(content []byte) []models.SensorReading { var readings []models.SensorReading scanner := bufio.NewScanner(strings.NewReader(string(content))) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || !strings.Contains(line, "|") { continue } fields := strings.Split(line, "|") if len(fields) < 3 { continue } name := strings.TrimSpace(fields[0]) status := strings.TrimSpace(fields[2]) if name == "" { continue } reading := models.SensorReading{ Name: name, Status: status, Type: determineSensorType(name), } if len(fields) >= 5 { readingStr := strings.TrimSpace(fields[4]) if readingStr != "" && readingStr != "no reading" { reading.RawValue = readingStr if m := valueRegex.FindStringSubmatch(readingStr); m != nil { if v, err := strconv.ParseFloat(m[1], 64); err == nil { reading.Value = v reading.Unit = strings.TrimSpace(m[2]) } } } } readings = append(readings, reading) } return readings }