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/
|
dist/
|
||||||
|
|
||||||
# Release artifacts
|
# Release artifacts
|
||||||
|
release/
|
||||||
|
releases/
|
||||||
releases/**/SHA256SUMS.txt
|
releases/**/SHA256SUMS.txt
|
||||||
releases/**/*.tar.gz
|
releases/**/*.tar.gz
|
||||||
releases/**/*.zip
|
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)
|
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 {
|
if emit != nil {
|
||||||
emit(Progress{
|
emit(Progress{
|
||||||
@@ -738,6 +748,106 @@ func directDiskBayCandidates(drivesCollectionPath string) []string {
|
|||||||
return out
|
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 {
|
func redfishLinkRefs(doc map[string]interface{}, topKey, nestedKey string) []string {
|
||||||
top, ok := doc[topKey].(map[string]interface{})
|
top, ok := doc[topKey].(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -1856,27 +1966,44 @@ func redfishSnapshotPrioritySeeds(systemPaths, chassisPaths, managerPaths []stri
|
|||||||
add(joinPath(p, "/SecureBoot"))
|
add(joinPath(p, "/SecureBoot"))
|
||||||
add(joinPath(p, "/Processors"))
|
add(joinPath(p, "/Processors"))
|
||||||
add(joinPath(p, "/Memory"))
|
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, "/PCIeDevices"))
|
||||||
add(joinPath(p, "/PCIeFunctions"))
|
add(joinPath(p, "/PCIeFunctions"))
|
||||||
add(joinPath(p, "/Accelerators"))
|
add(joinPath(p, "/Accelerators"))
|
||||||
add(joinPath(p, "/Storage"))
|
add(joinPath(p, "/Storage"))
|
||||||
|
add(joinPath(p, "/SimpleStorage"))
|
||||||
add(joinPath(p, "/Storage/IntelVROC"))
|
add(joinPath(p, "/Storage/IntelVROC"))
|
||||||
add(joinPath(p, "/Storage/IntelVROC/Drives"))
|
add(joinPath(p, "/Storage/IntelVROC/Drives"))
|
||||||
add(joinPath(p, "/Storage/IntelVROC/Volumes"))
|
add(joinPath(p, "/Storage/IntelVROC/Volumes"))
|
||||||
}
|
}
|
||||||
for _, p := range chassisPaths {
|
for _, p := range chassisPaths {
|
||||||
add(p)
|
add(p)
|
||||||
|
add(joinPath(p, "/Sensors"))
|
||||||
|
add(joinPath(p, "/Thermal"))
|
||||||
|
add(joinPath(p, "/EnvironmentMetrics"))
|
||||||
add(joinPath(p, "/PCIeDevices"))
|
add(joinPath(p, "/PCIeDevices"))
|
||||||
add(joinPath(p, "/PCIeSlots"))
|
add(joinPath(p, "/PCIeSlots"))
|
||||||
add(joinPath(p, "/NetworkAdapters"))
|
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"))
|
||||||
add(joinPath(p, "/PowerSubsystem/PowerSupplies"))
|
add(joinPath(p, "/PowerSubsystem/PowerSupplies"))
|
||||||
|
add(joinPath(p, "/PowerSubsystem/Voltages"))
|
||||||
add(joinPath(p, "/ThermalSubsystem"))
|
add(joinPath(p, "/ThermalSubsystem"))
|
||||||
add(joinPath(p, "/ThermalSubsystem/Fans"))
|
add(joinPath(p, "/ThermalSubsystem/Fans"))
|
||||||
|
add(joinPath(p, "/ThermalSubsystem/Temperatures"))
|
||||||
add(joinPath(p, "/Power"))
|
add(joinPath(p, "/Power"))
|
||||||
}
|
}
|
||||||
for _, p := range managerPaths {
|
for _, p := range managerPaths {
|
||||||
add(p)
|
add(p)
|
||||||
|
add(joinPath(p, "/EthernetInterfaces"))
|
||||||
|
add(joinPath(p, "/NetworkProtocol/HTTPS/Certificates"))
|
||||||
|
add(joinPath(p, "/LogServices"))
|
||||||
add(joinPath(p, "/NetworkProtocol"))
|
add(joinPath(p, "/NetworkProtocol"))
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|||||||
Reference in New Issue
Block a user