package redfishprofile import "strings" func CollectSignals(serviceRootDoc, systemDoc, chassisDoc, managerDoc map[string]interface{}, resourceHints []string, hintDocs ...map[string]interface{}) MatchSignals { resourceHints = append([]string{}, resourceHints...) docHints := make([]string, 0) for _, doc := range append([]map[string]interface{}{serviceRootDoc, systemDoc, chassisDoc, managerDoc}, hintDocs...) { embeddedPaths, embeddedHints := collectDocSignalHints(doc) resourceHints = append(resourceHints, embeddedPaths...) docHints = append(docHints, embeddedHints...) } signals := MatchSignals{ ServiceRootVendor: lookupString(serviceRootDoc, "Vendor"), ServiceRootProduct: lookupString(serviceRootDoc, "Product"), SystemManufacturer: lookupString(systemDoc, "Manufacturer"), SystemModel: lookupString(systemDoc, "Model"), SystemSKU: lookupString(systemDoc, "SKU"), ChassisManufacturer: lookupString(chassisDoc, "Manufacturer"), ChassisModel: lookupString(chassisDoc, "Model"), ManagerManufacturer: lookupString(managerDoc, "Manufacturer"), ResourceHints: resourceHints, DocHints: docHints, } signals.OEMNamespaces = dedupeSorted(append( oemNamespaces(serviceRootDoc), append(oemNamespaces(systemDoc), append(oemNamespaces(chassisDoc), oemNamespaces(managerDoc)...)...)..., )) return normalizeSignals(signals) } func CollectSignalsFromTree(tree map[string]interface{}) MatchSignals { getDoc := func(path string) map[string]interface{} { if v, ok := tree[path]; ok { if doc, ok := v.(map[string]interface{}); ok { return doc } } return nil } memberPath := func(collectionPath, fallbackPath string) string { collection := getDoc(collectionPath) if len(collection) != 0 { if members, ok := collection["Members"].([]interface{}); ok && len(members) > 0 { if ref, ok := members[0].(map[string]interface{}); ok { if path := lookupString(ref, "@odata.id"); path != "" { return path } } } } return fallbackPath } systemPath := memberPath("/redfish/v1/Systems", "/redfish/v1/Systems/1") chassisPath := memberPath("/redfish/v1/Chassis", "/redfish/v1/Chassis/1") managerPath := memberPath("/redfish/v1/Managers", "/redfish/v1/Managers/1") resourceHints := make([]string, 0, len(tree)) hintDocs := make([]map[string]interface{}, 0, len(tree)) for path := range tree { path = strings.TrimSpace(path) if path == "" { continue } resourceHints = append(resourceHints, path) } for _, v := range tree { doc, ok := v.(map[string]interface{}) if !ok { continue } hintDocs = append(hintDocs, doc) } return CollectSignals( getDoc("/redfish/v1"), getDoc(systemPath), getDoc(chassisPath), getDoc(managerPath), resourceHints, hintDocs..., ) } func collectDocSignalHints(doc map[string]interface{}) ([]string, []string) { if len(doc) == 0 { return nil, nil } paths := make([]string, 0) hints := make([]string, 0) var walk func(any) walk = func(v any) { switch x := v.(type) { case map[string]interface{}: for rawKey, child := range x { key := strings.TrimSpace(rawKey) if key != "" { hints = append(hints, key) } if s, ok := child.(string); ok { s = strings.TrimSpace(s) if s != "" { switch key { case "@odata.id", "target": paths = append(paths, s) case "@odata.type": hints = append(hints, s) default: if isInterestingSignalString(s) { hints = append(hints, s) if strings.HasPrefix(s, "/") { paths = append(paths, s) } } } } } walk(child) } case []interface{}: for _, child := range x { walk(child) } } } walk(doc) return paths, hints } func isInterestingSignalString(s string) bool { switch { case strings.HasPrefix(s, "/"): return true case strings.HasPrefix(s, "#"): return true case strings.Contains(s, "COMMONb"): return true case strings.Contains(s, "EnvironmentMetrcs"): return true case strings.Contains(s, "GetServerAllUSBStatus"): return true default: return false } } func lookupString(doc map[string]interface{}, key string) string { if len(doc) == 0 { return "" } value, _ := doc[key] if s, ok := value.(string); ok { return strings.TrimSpace(s) } return "" } func oemNamespaces(doc map[string]interface{}) []string { if len(doc) == 0 { return nil } oem, ok := doc["Oem"].(map[string]interface{}) if !ok { return nil } out := make([]string, 0, len(oem)) for key := range oem { key = strings.TrimSpace(key) if key == "" { continue } out = append(out, key) } return out }