Implement the full architectural plan: unified ingest.Service entry point for archive and Redfish payloads, modular redfishprofile package with composable profiles (generic, ami-family, msi, supermicro, dell, hgx-topology), score-based profile matching with fallback expansion mode, and profile-driven acquisition/analysis plans. Vendor-specific logic moved out of common executors and into profile hooks. GPU chassis lookup strategies and known storage recovery collections (IntelVROC/HA-RAID/MRVL) now live in ResolvedAnalysisPlan, populated by profiles at analysis time. Replay helpers read from the plan; no hardcoded path lists remain in generic code. Also splits redfish_replay.go into domain modules (gpu, storage, inventory, fru, profiles) and adds full fixture/matcher/directive test coverage including Dell, AMI, unknown-vendor fallback, and deterministic ordering. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
165 lines
5.7 KiB
Go
165 lines
5.7 KiB
Go
package collector
|
|
|
|
import (
|
|
"git.mchus.pro/mchus/logpile/internal/collector/redfishprofile"
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
func (r redfishSnapshotReader) collectStorage(systemPath string, plan redfishprofile.ResolvedAnalysisPlan) []models.Storage {
|
|
var out []models.Storage
|
|
storageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/Storage"))
|
|
for _, member := range storageMembers {
|
|
if driveCollection, ok := member["Drives"].(map[string]interface{}); ok {
|
|
if driveCollectionPath := asString(driveCollection["@odata.id"]); driveCollectionPath != "" {
|
|
driveDocs, err := r.getCollectionMembers(driveCollectionPath)
|
|
if err == nil {
|
|
for _, driveDoc := range driveDocs {
|
|
if !isVirtualStorageDrive(driveDoc) {
|
|
supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
|
|
out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
|
|
}
|
|
}
|
|
if len(driveDocs) == 0 {
|
|
for _, driveDoc := range r.probeDirectDiskBayChildren(driveCollectionPath) {
|
|
supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
|
|
out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
|
|
}
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
if drives, ok := member["Drives"].([]interface{}); ok {
|
|
for _, driveAny := range drives {
|
|
driveRef, ok := driveAny.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
odata := asString(driveRef["@odata.id"])
|
|
if odata == "" {
|
|
continue
|
|
}
|
|
driveDoc, err := r.getJSON(odata)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if !isVirtualStorageDrive(driveDoc) {
|
|
supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
|
|
out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if looksLikeDrive(member) {
|
|
if isVirtualStorageDrive(member) {
|
|
continue
|
|
}
|
|
supplementalDocs := r.getLinkedSupplementalDocs(member, "DriveMetrics", "EnvironmentMetrics", "Metrics")
|
|
out = append(out, parseDriveWithSupplementalDocs(member, supplementalDocs...))
|
|
}
|
|
|
|
if plan.Directives.EnableStorageEnclosureRecovery {
|
|
for _, enclosurePath := range redfishLinkRefs(member, "Links", "Enclosures") {
|
|
driveDocs, err := r.getCollectionMembers(joinPath(enclosurePath, "/Drives"))
|
|
if err == nil {
|
|
for _, driveDoc := range driveDocs {
|
|
if looksLikeDrive(driveDoc) && !isVirtualStorageDrive(driveDoc) {
|
|
supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
|
|
out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
|
|
}
|
|
}
|
|
if len(driveDocs) == 0 {
|
|
for _, driveDoc := range r.probeDirectDiskBayChildren(joinPath(enclosurePath, "/Drives")) {
|
|
if isVirtualStorageDrive(driveDoc) {
|
|
continue
|
|
}
|
|
out = append(out, parseDrive(driveDoc))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(plan.KnownStorageDriveCollections) > 0 {
|
|
for _, driveDoc := range r.collectKnownStorageMembers(systemPath, plan.KnownStorageDriveCollections) {
|
|
if looksLikeDrive(driveDoc) && !isVirtualStorageDrive(driveDoc) {
|
|
supplementalDocs := r.getLinkedSupplementalDocs(driveDoc, "DriveMetrics", "EnvironmentMetrics", "Metrics")
|
|
out = append(out, parseDriveWithSupplementalDocs(driveDoc, supplementalDocs...))
|
|
}
|
|
}
|
|
}
|
|
|
|
simpleStorageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/SimpleStorage"))
|
|
for _, member := range simpleStorageMembers {
|
|
devices, ok := member["Devices"].([]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
for _, devAny := range devices {
|
|
devDoc, ok := devAny.(map[string]interface{})
|
|
if !ok || !looksLikeDrive(devDoc) || isVirtualStorageDrive(devDoc) {
|
|
continue
|
|
}
|
|
out = append(out, parseDrive(devDoc))
|
|
}
|
|
}
|
|
|
|
chassisPaths := r.discoverMemberPaths("/redfish/v1/Chassis", "/redfish/v1/Chassis/1")
|
|
for _, chassisPath := range chassisPaths {
|
|
driveDocs, err := r.getCollectionMembers(joinPath(chassisPath, "/Drives"))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, driveDoc := range driveDocs {
|
|
if !looksLikeDrive(driveDoc) || isVirtualStorageDrive(driveDoc) {
|
|
continue
|
|
}
|
|
out = append(out, parseDrive(driveDoc))
|
|
}
|
|
}
|
|
if plan.Directives.EnableSupermicroNVMeBackplane {
|
|
for _, chassisPath := range chassisPaths {
|
|
if !isSupermicroNVMeBackplanePath(chassisPath) {
|
|
continue
|
|
}
|
|
for _, driveDoc := range r.probeSupermicroNVMeDiskBays(chassisPath) {
|
|
if !looksLikeDrive(driveDoc) || isVirtualStorageDrive(driveDoc) {
|
|
continue
|
|
}
|
|
out = append(out, parseDrive(driveDoc))
|
|
}
|
|
}
|
|
}
|
|
return dedupeStorage(out)
|
|
}
|
|
|
|
func (r redfishSnapshotReader) collectStorageVolumes(systemPath string, plan redfishprofile.ResolvedAnalysisPlan) []models.StorageVolume {
|
|
var out []models.StorageVolume
|
|
storageMembers, _ := r.getCollectionMembers(joinPath(systemPath, "/Storage"))
|
|
for _, member := range storageMembers {
|
|
controller := firstNonEmpty(asString(member["Id"]), asString(member["Name"]))
|
|
volumeCollectionPath := redfishLinkedPath(member, "Volumes")
|
|
if volumeCollectionPath == "" {
|
|
continue
|
|
}
|
|
volumeDocs, err := r.getCollectionMembers(volumeCollectionPath)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, volDoc := range volumeDocs {
|
|
if looksLikeVolume(volDoc) {
|
|
out = append(out, parseStorageVolume(volDoc, controller))
|
|
}
|
|
}
|
|
}
|
|
if len(plan.KnownStorageVolumeCollections) > 0 {
|
|
for _, volDoc := range r.collectKnownStorageMembers(systemPath, plan.KnownStorageVolumeCollections) {
|
|
if looksLikeVolume(volDoc) {
|
|
out = append(out, parseStorageVolume(volDoc, storageControllerFromPath(asString(volDoc["@odata.id"]))))
|
|
}
|
|
}
|
|
}
|
|
return dedupeStorageVolumes(out)
|
|
}
|