Expand Redfish best-effort snapshot crawling
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -64,6 +64,8 @@ go.work.sum
|
||||
dist/
|
||||
|
||||
# Release artifacts
|
||||
release/
|
||||
releases/
|
||||
releases/**/SHA256SUMS.txt
|
||||
releases/**/*.tar.gz
|
||||
releases/**/*.zip
|
||||
|
||||
@@ -678,6 +678,16 @@ func (c *RedfishConnector) collectRawRedfishTree(ctx context.Context, client *ht
|
||||
c.debugSnapshotf("snapshot nvme bay probe hit path=%s", bayPath)
|
||||
}
|
||||
}
|
||||
// Some BMCs under-report collection Members for sensors/PSU subresources but still serve
|
||||
// direct numeric child endpoints. Probe common collections to maximize raw snapshot fidelity.
|
||||
for path := range out {
|
||||
for childPath, doc := range c.probeDirectRedfishCollectionChildren(ctx, client, req, baseURL, path) {
|
||||
if _, exists := out[childPath]; exists {
|
||||
continue
|
||||
}
|
||||
out[childPath] = doc
|
||||
}
|
||||
}
|
||||
|
||||
if emit != nil {
|
||||
emit(Progress{
|
||||
@@ -738,6 +748,106 @@ func directDiskBayCandidates(drivesCollectionPath string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func (c *RedfishConnector) probeDirectRedfishCollectionChildren(ctx context.Context, client *http.Client, req Request, baseURL, collectionPath string) map[string]map[string]interface{} {
|
||||
normalized := normalizeRedfishPath(collectionPath)
|
||||
maxItems, startIndex, missBudget := directNumericProbePlan(normalized)
|
||||
if maxItems <= 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]map[string]interface{})
|
||||
consecutiveMisses := 0
|
||||
for i := startIndex; i <= maxItems; i++ {
|
||||
path := fmt.Sprintf("%s/%d", normalized, i)
|
||||
doc, err := c.getJSON(ctx, client, req, baseURL, path)
|
||||
if err != nil {
|
||||
consecutiveMisses++
|
||||
if consecutiveMisses >= missBudget {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
consecutiveMisses = 0
|
||||
if !looksLikeRedfishResource(doc) {
|
||||
continue
|
||||
}
|
||||
out[normalizeRedfishPath(path)] = doc
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func directNumericProbePlan(collectionPath string) (maxItems, startIndex, missBudget int) {
|
||||
switch {
|
||||
case strings.HasSuffix(collectionPath, "/Systems"):
|
||||
return 32, 1, 8
|
||||
case strings.HasSuffix(collectionPath, "/Chassis"):
|
||||
return 64, 1, 12
|
||||
case strings.HasSuffix(collectionPath, "/Managers"):
|
||||
return 16, 1, 6
|
||||
case strings.HasSuffix(collectionPath, "/Processors"):
|
||||
return 32, 1, 12
|
||||
case strings.HasSuffix(collectionPath, "/Memory"):
|
||||
return 512, 1, 48
|
||||
case strings.HasSuffix(collectionPath, "/Storage"):
|
||||
return 128, 1, 24
|
||||
case strings.HasSuffix(collectionPath, "/Drives"):
|
||||
return 256, 0, 24
|
||||
case strings.HasSuffix(collectionPath, "/Volumes"):
|
||||
return 128, 1, 16
|
||||
case strings.HasSuffix(collectionPath, "/PCIeDevices"):
|
||||
return 256, 1, 24
|
||||
case strings.HasSuffix(collectionPath, "/PCIeFunctions"):
|
||||
return 512, 1, 32
|
||||
case strings.HasSuffix(collectionPath, "/NetworkAdapters"):
|
||||
return 128, 1, 20
|
||||
case strings.HasSuffix(collectionPath, "/NetworkPorts"):
|
||||
return 256, 1, 24
|
||||
case strings.HasSuffix(collectionPath, "/Ports"):
|
||||
return 256, 1, 24
|
||||
case strings.HasSuffix(collectionPath, "/EthernetInterfaces"):
|
||||
return 256, 1, 24
|
||||
case strings.HasSuffix(collectionPath, "/Certificates"):
|
||||
return 256, 1, 24
|
||||
case strings.HasSuffix(collectionPath, "/Accounts"):
|
||||
return 128, 1, 16
|
||||
case strings.HasSuffix(collectionPath, "/LogServices"):
|
||||
return 32, 1, 8
|
||||
case strings.HasSuffix(collectionPath, "/Sensors"):
|
||||
return 512, 1, 48
|
||||
case strings.HasSuffix(collectionPath, "/Temperatures"):
|
||||
return 256, 1, 32
|
||||
case strings.HasSuffix(collectionPath, "/Fans"):
|
||||
return 256, 1, 32
|
||||
case strings.HasSuffix(collectionPath, "/Voltages"):
|
||||
return 256, 1, 32
|
||||
case strings.HasSuffix(collectionPath, "/PowerSupplies"):
|
||||
return 64, 1, 16
|
||||
default:
|
||||
return 0, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
func looksLikeRedfishResource(doc map[string]interface{}) bool {
|
||||
if len(doc) == 0 {
|
||||
return false
|
||||
}
|
||||
if asString(doc["@odata.id"]) != "" {
|
||||
return true
|
||||
}
|
||||
if asString(doc["Id"]) != "" || asString(doc["Name"]) != "" {
|
||||
return true
|
||||
}
|
||||
if _, ok := doc["Status"]; ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := doc["Reading"]; ok {
|
||||
return true
|
||||
}
|
||||
if _, ok := doc["ReadingCelsius"]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func redfishLinkRefs(doc map[string]interface{}, topKey, nestedKey string) []string {
|
||||
top, ok := doc[topKey].(map[string]interface{})
|
||||
if !ok {
|
||||
@@ -1856,27 +1966,44 @@ func redfishSnapshotPrioritySeeds(systemPaths, chassisPaths, managerPaths []stri
|
||||
add(joinPath(p, "/SecureBoot"))
|
||||
add(joinPath(p, "/Processors"))
|
||||
add(joinPath(p, "/Memory"))
|
||||
add(joinPath(p, "/EthernetInterfaces"))
|
||||
add(joinPath(p, "/NetworkInterfaces"))
|
||||
add(joinPath(p, "/BootOptions"))
|
||||
add(joinPath(p, "/Certificates"))
|
||||
add(joinPath(p, "/PCIeDevices"))
|
||||
add(joinPath(p, "/PCIeFunctions"))
|
||||
add(joinPath(p, "/Accelerators"))
|
||||
add(joinPath(p, "/Storage"))
|
||||
add(joinPath(p, "/SimpleStorage"))
|
||||
add(joinPath(p, "/Storage/IntelVROC"))
|
||||
add(joinPath(p, "/Storage/IntelVROC/Drives"))
|
||||
add(joinPath(p, "/Storage/IntelVROC/Volumes"))
|
||||
}
|
||||
for _, p := range chassisPaths {
|
||||
add(p)
|
||||
add(joinPath(p, "/Sensors"))
|
||||
add(joinPath(p, "/Thermal"))
|
||||
add(joinPath(p, "/EnvironmentMetrics"))
|
||||
add(joinPath(p, "/PCIeDevices"))
|
||||
add(joinPath(p, "/PCIeSlots"))
|
||||
add(joinPath(p, "/NetworkAdapters"))
|
||||
add(joinPath(p, "/Drives"))
|
||||
add(joinPath(p, "/Temperatures"))
|
||||
add(joinPath(p, "/Fans"))
|
||||
add(joinPath(p, "/Voltages"))
|
||||
add(joinPath(p, "/PowerSubsystem"))
|
||||
add(joinPath(p, "/PowerSubsystem/PowerSupplies"))
|
||||
add(joinPath(p, "/PowerSubsystem/Voltages"))
|
||||
add(joinPath(p, "/ThermalSubsystem"))
|
||||
add(joinPath(p, "/ThermalSubsystem/Fans"))
|
||||
add(joinPath(p, "/ThermalSubsystem/Temperatures"))
|
||||
add(joinPath(p, "/Power"))
|
||||
}
|
||||
for _, p := range managerPaths {
|
||||
add(p)
|
||||
add(joinPath(p, "/EthernetInterfaces"))
|
||||
add(joinPath(p, "/NetworkProtocol/HTTPS/Certificates"))
|
||||
add(joinPath(p, "/LogServices"))
|
||||
add(joinPath(p, "/NetworkProtocol"))
|
||||
}
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user