178 lines
4.6 KiB
Go
178 lines
4.6 KiB
Go
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
|
|
}
|