功能:完善云管助手与GPU故障恢复核对

This commit is contained in:
songyiming committed 2026-11-13 19:08:40 +08:00
1 parent b6026f9759
commit 9f7b01e4db
42 files changed
+3576 -120

No files matched your search

+29 -2
View File
@@ -103,6 +103,11 @@ func (s *Server) gpuInventory(c *gin.Context) {
s.fail(c, 502, "pci_unavailable", "无法读取节点 PCI 清单,请检查 PVE 连通性及根路径 Sys.Audit 权限")
return
}
healthSamples, err := s.latestGPUHealth(ctx, node)
if err != nil {
s.dbError(c, err)
return
}
items := []gpuItem{}
observedAt := time.Now().UTC()
for _, d := range devices {
@@ -122,7 +127,23 @@ func (s *Server) gpuInventory(c *gin.Context) {
if strings.TrimSpace(d.Driver) != "" {
driverBinding = "bound"
}
items = append(items, gpuItem{ID: node + ":" + address, Address: address, Name: d.DeviceName, Vendor: d.VendorName, VendorID: d.Vendor, DeviceID: d.Device, Class: d.Class, IOMMUGroup: group, Health: gpuHealth{Status: "not_collected", Source: "pve-pci", ObservedAt: observedAt, Driver: d.Driver, DriverBinding: driverBinding}, References: []gpuReference{}})
health := gpuHealth{Status: "not_collected", Source: "pve-pci", ObservedAt: observedAt, Driver: d.Driver, DriverBinding: driverBinding}
if sample, ok := healthSamples[address]; ok {
health.Status = "collected"
health.Source = sample.Source
health.ObservedAt = sample.ObservedAt
health.TemperatureC = sample.TemperatureC
health.UtilizationPercent = sample.UtilizationPercent
health.MemoryUsedBytes = sample.MemoryUsedBytes
health.MemoryTotalBytes = sample.MemoryTotalBytes
if sample.Driver != "" {
health.Driver = sample.Driver
}
if sample.DriverBinding != "" {
health.DriverBinding = sample.DriverBinding
}
}
items = append(items, gpuItem{ID: node + ":" + address, Address: address, Name: d.DeviceName, Vendor: d.VendorName, VendorID: d.Vendor, DeviceID: d.Device, Class: d.Class, IOMMUGroup: group, Health: health, References: []gpuReference{}})
}
fullVisibility, err := pve.HasPermission(ctx, "/", "VM.Audit")
if err != nil || !fullVisibility {
@@ -244,7 +265,13 @@ func (s *Server) gpuInventory(c *gin.Context) {
}
}
sort.Slice(items, func(i, j int) bool { return items[i].Address < items[j].Address })
c.JSON(200, gin.H{"node": node, "observedAt": observedAt, "complete": len(issues) == 0, "visibleVmCount": visibleCount, "scannedVmCount": scannedCount, "items": items, "issues": issues, "health": gin.H{"status": "partial", "source": "pve-pci", "temperature": "not_collected", "utilization": "not_collected", "memory": "not_collected", "driverBinding": "reported_when_pve_exposes_driver"}})
healthStatus := "not_collected"
healthSource := "pve-pci"
if len(healthSamples) > 0 {
healthStatus = "collected"
healthSource = "node-agent"
}
c.JSON(200, gin.H{"node": node, "observedAt": observedAt, "complete": len(issues) == 0, "visibleVmCount": visibleCount, "scannedVmCount": scannedCount, "items": items, "issues": issues, "health": gin.H{"status": healthStatus, "source": healthSource, "temperature": healthStatus, "utilization": healthStatus, "memory": healthStatus, "driverBinding": "reported_when_collected"}})
}
func rawOptionText(value json.RawMessage) string {