package collector import ( "strings" "time" "git.mchus.pro/mchus/logpile/internal/models" ) // collectLicenses reads the standard DMTF LicenseService/Licenses collection // (Redfish License.v1_x schema). Seen first on Dell iDRAC10-generation // firmware, which exposes it alongside the legacy Oem/Dell license resources. // Entries are system-level licenses unless AuthorizationScope is "Device", // in which case Links.AuthorizedDevices identifies the licensed component. func (r redfishSnapshotReader) collectLicenses() []models.License { memberDocs, err := r.getCollectionMembers("/redfish/v1/LicenseService/Licenses") if err != nil || len(memberDocs) == 0 { return nil } out := make([]models.License, 0, len(memberDocs)) for _, doc := range memberDocs { lic, ok := parseRedfishLicense(doc) if !ok { continue } out = append(out, lic) } return out } func parseRedfishLicense(doc map[string]interface{}) (models.License, bool) { name := strings.TrimSpace(firstNonEmpty( asString(doc["Description"]), asString(doc["Name"]), asString(doc["Id"]), )) if name == "" { return models.License{}, false } origin := strings.ToLower(strings.TrimSpace(asString(doc["LicenseOrigin"]))) present := origin == "" || origin == "installed" lic := models.License{ Name: name, LicenseKey: strings.TrimSpace(asString(doc["EntitlementId"])), Type: strings.TrimSpace(asString(doc["LicenseType"])), ComponentRef: redfishLicenseComponentRef(doc), Present: present, Status: mapStatus(doc["Status"]), ActivatedAt: parseRedfishLicenseTime(doc["InstallDate"]), ExpiresAt: parseRedfishLicenseTime(doc["ExpirationDate"]), } return lic, true } func parseRedfishLicenseTime(v interface{}) time.Time { raw := strings.TrimSpace(asString(v)) if raw == "" { return time.Time{} } for _, layout := range []string{time.RFC3339, time.RFC3339Nano} { if ts, err := time.Parse(layout, raw); err == nil { return ts.UTC() } } return time.Time{} } func redfishLicenseComponentRef(doc map[string]interface{}) string { if !strings.EqualFold(strings.TrimSpace(asString(doc["AuthorizationScope"])), "Device") { return "" } links, ok := doc["Links"].(map[string]interface{}) if !ok { return "" } devices, ok := links["AuthorizedDevices"].([]interface{}) if !ok || len(devices) == 0 { return "" } first, ok := devices[0].(map[string]interface{}) if !ok { return "" } return strings.TrimSpace(asString(first["@odata.id"])) }