New parsers: - NVIDIA Field Diagnostics parser with dmidecode output support - NVIDIA Bug Report parser with comprehensive hardware extraction - Supermicro crashdump (CDump.txt) parser - Generic fallback parser for unrecognized text files Enhanced GPU parsing (nvidia-bug-report): - Model and manufacturer detection (NVIDIA H100 80GB HBM3) - UUID, Video BIOS version, IRQ information - Bus location (BDF), DMA size/mask, device minor - PCIe bus type details New hardware detection (nvidia-bug-report): - System Information: server S/N, UUID, manufacturer, product name - CPU: model, S/N, cores, threads, frequencies from dmidecode - Memory: P/N, S/N, manufacturer, speed for all DIMMs - Power Supplies: manufacturer, model, S/N, wattage, status - Network Adapters: Ethernet/InfiniBand controllers with VPD data - Model, P/N, S/N from lspci Vital Product Data - Port count/type detection (QSFP56, OSFP, etc.) - Support for ConnectX-6/7 adapters Archive handling improvements: - Plain .gz file support (not just tar.gz) - Increased size limit for plain gzip files (50MB) - Better error handling for mixed archive formats Web interface enhancements: - Display parser name and filename badges - Improved file info section with visual indicators Co-Authored-By: Claude (qwen3-coder:480b) <noreply@anthropic.com>
117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
package nvidia_bug_report
|
|
|
|
import (
|
|
"bufio"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
// parsePSUInfo extracts Power Supply information from dmidecode output
|
|
func parsePSUInfo(content string, result *models.AnalysisResult) {
|
|
scanner := bufio.NewScanner(strings.NewReader(content))
|
|
|
|
var currentPSU *models.PSU
|
|
inPowerSupply := false
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
trimmed := strings.TrimSpace(line)
|
|
|
|
// Start of System Power Supply section
|
|
if strings.Contains(trimmed, "System Power Supply") {
|
|
inPowerSupply = true
|
|
currentPSU = &models.PSU{}
|
|
continue
|
|
}
|
|
|
|
// End of current section (empty line or new section with Handle)
|
|
if inPowerSupply && (trimmed == "" || strings.HasPrefix(trimmed, "Handle ")) {
|
|
// Save PSU if it has valid data
|
|
if currentPSU != nil && currentPSU.Slot != "" {
|
|
// Only add if PSU is present
|
|
if strings.Contains(strings.ToLower(currentPSU.Status), "present") {
|
|
result.Hardware.PowerSupply = append(result.Hardware.PowerSupply, *currentPSU)
|
|
}
|
|
}
|
|
inPowerSupply = false
|
|
currentPSU = nil
|
|
continue
|
|
}
|
|
|
|
// Parse fields within System Power Supply section
|
|
if inPowerSupply && currentPSU != nil && strings.Contains(line, ":") {
|
|
parts := strings.SplitN(trimmed, ":", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
field := strings.TrimSpace(parts[0])
|
|
value := strings.TrimSpace(parts[1])
|
|
|
|
if value == "" || value == "Not Specified" || value == "Unknown" || value == "UNKNOWN" {
|
|
continue
|
|
}
|
|
|
|
switch field {
|
|
case "Location":
|
|
currentPSU.Slot = value
|
|
case "Name":
|
|
// Use Name as Model if Model is not set later
|
|
if currentPSU.Model == "" {
|
|
currentPSU.Model = value
|
|
}
|
|
case "Manufacturer":
|
|
currentPSU.Vendor = value
|
|
case "Serial Number":
|
|
currentPSU.SerialNumber = value
|
|
case "Model Part Number":
|
|
// Use Model Part Number as the primary model identifier
|
|
currentPSU.Model = value
|
|
case "Revision":
|
|
currentPSU.Firmware = value
|
|
case "Max Power Capacity":
|
|
// Parse wattage like "2700 W"
|
|
if wattage := parsePowerWattage(value); wattage > 0 {
|
|
currentPSU.WattageW = wattage
|
|
}
|
|
case "Status":
|
|
currentPSU.Status = value
|
|
case "Type":
|
|
// Could store PSU type if needed (e.g., "Switching")
|
|
case "Plugged":
|
|
// Could track if PSU is plugged
|
|
case "Hot Replaceable":
|
|
// Could track if hot-swappable
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save last PSU if exists
|
|
if currentPSU != nil && currentPSU.Slot != "" {
|
|
if strings.Contains(strings.ToLower(currentPSU.Status), "present") {
|
|
result.Hardware.PowerSupply = append(result.Hardware.PowerSupply, *currentPSU)
|
|
}
|
|
}
|
|
}
|
|
|
|
// parsePowerWattage parses power capacity strings like "2700 W" or "1200 Watts"
|
|
func parsePowerWattage(powerStr string) int {
|
|
parts := strings.Fields(powerStr)
|
|
if len(parts) < 1 {
|
|
return 0
|
|
}
|
|
|
|
// Try to parse the number
|
|
wattageStr := parts[0]
|
|
wattage, err := strconv.Atoi(wattageStr)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
|
|
// Check if unit is specified (W, Watts, etc.) and convert if needed
|
|
// For now, assume it's always in Watts
|
|
return wattage
|
|
}
|