123 lines
3.7 KiB
Go
123 lines
3.7 KiB
Go
package platform
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
var techDumpFixedCommands = []struct {
|
|
Name string
|
|
Args []string
|
|
File string
|
|
}{
|
|
{Name: "dmidecode", Args: []string{"-t", "0"}, File: "dmidecode-type0.txt"},
|
|
{Name: "dmidecode", Args: []string{"-t", "1"}, File: "dmidecode-type1.txt"},
|
|
{Name: "dmidecode", Args: []string{"-t", "2"}, File: "dmidecode-type2.txt"},
|
|
{Name: "dmidecode", Args: []string{"-t", "4"}, File: "dmidecode-type4.txt"},
|
|
{Name: "dmidecode", Args: []string{"-t", "17"}, File: "dmidecode-type17.txt"},
|
|
{Name: "lspci", Args: []string{"-vmm", "-D"}, File: "lspci-vmm.txt"},
|
|
{Name: "lsblk", Args: []string{"-J", "-d", "-o", "NAME,TYPE,SIZE,SERIAL,MODEL,TRAN,HCTL"}, File: "lsblk.json"},
|
|
{Name: "sensors", Args: []string{"-j"}, File: "sensors.json"},
|
|
{Name: "ipmitool", Args: []string{"fru", "print"}, File: "ipmitool-fru.txt"},
|
|
{Name: "ipmitool", Args: []string{"sdr"}, File: "ipmitool-sdr.txt"},
|
|
{Name: "nvidia-smi", Args: []string{"-q"}, File: "nvidia-smi-q.txt"},
|
|
{Name: "nvidia-smi", Args: []string{"--query-gpu=index,pci.bus_id,serial,vbios_version,temperature.gpu,power.draw,ecc.errors.uncorrected.aggregate.total,ecc.errors.corrected.aggregate.total,clocks_throttle_reasons.hw_slowdown", "--format=csv,noheader,nounits"}, File: "nvidia-smi-query.csv"},
|
|
{Name: "nvme", Args: []string{"list", "-o", "json"}, File: "nvme-list.json"},
|
|
}
|
|
|
|
type lsblkDumpRoot struct {
|
|
Blockdevices []struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
} `json:"blockdevices"`
|
|
}
|
|
|
|
type nvmeDumpRoot struct {
|
|
Devices []struct {
|
|
DevicePath string `json:"DevicePath"`
|
|
} `json:"Devices"`
|
|
}
|
|
|
|
func (s *System) CaptureTechnicalDump(baseDir string) error {
|
|
if err := os.MkdirAll(baseDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, cmd := range techDumpFixedCommands {
|
|
writeCommandDump(filepath.Join(baseDir, cmd.File), cmd.Name, cmd.Args...)
|
|
}
|
|
|
|
for _, dev := range lsblkDumpDevices(filepath.Join(baseDir, "lsblk.json")) {
|
|
writeCommandDump(filepath.Join(baseDir, "smartctl-"+sanitizeDumpName(dev)+".json"), "smartctl", "-j", "-a", "/dev/"+dev)
|
|
}
|
|
for _, dev := range nvmeDumpDevices(filepath.Join(baseDir, "nvme-list.json")) {
|
|
writeCommandDump(filepath.Join(baseDir, "nvme-id-ctrl-"+sanitizeDumpName(dev)+".json"), "nvme", "id-ctrl", dev, "-o", "json")
|
|
writeCommandDump(filepath.Join(baseDir, "nvme-smart-log-"+sanitizeDumpName(dev)+".json"), "nvme", "smart-log", dev, "-o", "json")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func writeCommandDump(path, name string, args ...string) {
|
|
out, err := exec.Command(name, args...).CombinedOutput()
|
|
if err != nil && len(out) == 0 {
|
|
return
|
|
}
|
|
_ = os.WriteFile(path, out, 0644)
|
|
}
|
|
|
|
func lsblkDumpDevices(path string) []string {
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
var root lsblkDumpRoot
|
|
if err := json.Unmarshal(raw, &root); err != nil {
|
|
return nil
|
|
}
|
|
var devices []string
|
|
for _, dev := range root.Blockdevices {
|
|
if dev.Type == "disk" && strings.TrimSpace(dev.Name) != "" {
|
|
devices = append(devices, strings.TrimSpace(dev.Name))
|
|
}
|
|
}
|
|
sort.Strings(devices)
|
|
return devices
|
|
}
|
|
|
|
func nvmeDumpDevices(path string) []string {
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
var root nvmeDumpRoot
|
|
if err := json.Unmarshal(raw, &root); err != nil {
|
|
return nil
|
|
}
|
|
seen := map[string]bool{}
|
|
var devices []string
|
|
for _, dev := range root.Devices {
|
|
name := strings.TrimSpace(dev.DevicePath)
|
|
if name == "" || seen[name] {
|
|
continue
|
|
}
|
|
seen[name] = true
|
|
devices = append(devices, name)
|
|
}
|
|
sort.Strings(devices)
|
|
return devices
|
|
}
|
|
|
|
func sanitizeDumpName(value string) string {
|
|
value = strings.TrimSpace(value)
|
|
value = strings.TrimPrefix(value, "/dev/")
|
|
value = strings.ReplaceAll(value, "/", "_")
|
|
if value == "" {
|
|
return "unknown"
|
|
}
|
|
return value
|
|
}
|