Update crawler to better handle odd Redfish implementations

This commit is contained in:
Alex Lovell-Troy 2024-06-28 06:17:22 +02:00
parent a7d5b0ebbb
commit e6325719f4
No known key found for this signature in database
3 changed files with 88 additions and 18 deletions

View file

@ -1,6 +1,12 @@
package crawler
import "github.com/stmcginnis/gofish"
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/stmcginnis/gofish"
"github.com/stmcginnis/gofish/redfish"
)
type CrawlerConfig struct {
URI string // URI of the BMC
@ -18,17 +24,24 @@ type EthernetInterface struct {
}
type InventoryDetail struct {
URI string `json:"uri,omitempty"` // URI of the BMC
Manufacturer string `json:"manufacturer,omitempty"` // Manufacturer of the Node
Name string `json:"name,omitempty"` // Name of the Node
Model string `json:"model,omitempty"` // Model of the Node
Serial string `json:"serial,omitempty"` // Serial number of the Node
BiosVersion string `json:"bios_version,omitempty"` // Version of the BIOS
EthernetInterfaces []EthernetInterface `json:"ethernet_interfaces,omitempty"` // Ethernet interfaces of the Node
PowerState string `json:"power_state,omitempty"` // Power state of the Node
ProcessorCount int `json:"processor_count,omitempty"` // Processors of the Node
ProcessorType string `json:"processor_type,omitempty"` // Processor type of the Node
MemoryTotal float32 `json:"memory_total,omitempty"` // Total memory of the Node in Gigabytes
URI string `json:"uri,omitempty"` // URI of the BMC
Manufacturer string `json:"manufacturer,omitempty"` // Manufacturer of the Node
Name string `json:"name,omitempty"` // Name of the Node
Model string `json:"model,omitempty"` // Model of the Node
Serial string `json:"serial,omitempty"` // Serial number of the Node
BiosVersion string `json:"bios_version,omitempty"` // Version of the BIOS
EthernetInterfaces []EthernetInterface `json:"ethernet_interfaces,omitempty"` // Ethernet interfaces of the Node
PowerState string `json:"power_state,omitempty"` // Power state of the Node
ProcessorCount int `json:"processor_count,omitempty"` // Processors of the Node
ProcessorType string `json:"processor_type,omitempty"` // Processor type of the Node
MemoryTotal float32 `json:"memory_total,omitempty"` // Total memory of the Node in Gigabytes
TrustedModules []string `json:"trusted_modules,omitempty"` // Trusted modules of the Node
TrustedComponents []string `json:"trusted_components,omitempty"` // Trusted components of the Chassis
Chassis_SKU string `json:"chassis_sku,omitempty"` // SKU of the Chassis
Chassis_Serial string `json:"chassis_serial,omitempty"` // Serial number of the Chassis
Chassis_AssetTag string `json:"chassis_asset_tag,omitempty"` // Asset tag of the Chassis
Chassis_Manufacturer string `json:"chassis_manufacturer,omitempty"` // Manufacturer of the Chassis
Chassis_Model string `json:"chassis_model,omitempty"` // Model of the Chassis
}
// CrawlBMC pulls all pertinent information from a BMC. It accepts a CrawlerConfig and returns a list of InventoryDetail structs.
@ -43,19 +56,45 @@ func CrawlBMC(config CrawlerConfig) ([]InventoryDetail, error) {
BasicAuth: true,
})
if err != nil {
event := log.Error()
event.Err(err)
event.Msg("failed to connect to BMC")
return systems, err
}
defer client.Logout()
// Get the list of systems from the BMC
// Obtain the ServiceRoot
rf_service := client.GetService()
rf_systems, err := rf_service.Systems()
if err != nil {
return systems, err
var rf_systems []*redfish.ComputerSystem
// Nodes are sometimes only found under Chassis, but they should be found under Systems.
rf_chassis, err := rf_service.Chassis()
if err == nil {
log.Info().Msgf("found %d chassis in ServiceRoot", len(rf_chassis))
for _, chassis := range rf_chassis {
rf_chassis_systems, err := chassis.ComputerSystems()
if err == nil {
rf_systems = append(rf_systems, rf_chassis_systems...)
log.Info().Msgf("found %d systems in chassis %s", len(rf_chassis_systems), chassis.ID)
}
}
}
rf_root_systems, err := rf_service.Systems()
if err != nil {
log.Error().Err(err).Msg("failed to get systems from ServiceRoot")
}
log.Info().Msgf("found %d systems in ServiceRoot", len(rf_root_systems))
rf_systems = append(rf_systems, rf_root_systems...)
systems, err = walkSystems(rf_systems, nil, config.URI)
return systems, err
}
func walkSystems(rf_systems []*redfish.ComputerSystem, rf_chassis *redfish.Chassis, baseURI string) ([]InventoryDetail, error) {
systems := []InventoryDetail{}
for _, rf_computersystem := range rf_systems {
system := InventoryDetail{
URI: config.URI + "/redfish/v1/Systems/" + rf_computersystem.ID,
URI: baseURI + "/redfish/v1/Systems/" + rf_computersystem.ID,
Name: rf_computersystem.Name,
Manufacturer: rf_computersystem.Manufacturer,
Model: rf_computersystem.Model,
@ -66,10 +105,19 @@ func CrawlBMC(config CrawlerConfig) ([]InventoryDetail, error) {
ProcessorType: rf_computersystem.ProcessorSummary.Model,
MemoryTotal: rf_computersystem.MemorySummary.TotalSystemMemoryGiB,
}
// Get the list of ethernet interfaces for the system
if rf_chassis != nil {
system.Chassis_SKU = rf_chassis.SKU
system.Chassis_Serial = rf_chassis.SerialNumber
system.Chassis_AssetTag = rf_chassis.AssetTag
system.Chassis_Manufacturer = rf_chassis.Manufacturer
system.Chassis_Model = rf_chassis.Model
}
rf_ethernetinterfaces, err := rf_computersystem.EthernetInterfaces()
if err != nil {
log.Error().Err(err).Msg("failed to get ethernet interfaces from computer system")
return systems, err
}
for _, rf_ethernetinterface := range rf_ethernetinterfaces {
ethernetinterface := EthernetInterface{
@ -82,6 +130,9 @@ func CrawlBMC(config CrawlerConfig) ([]InventoryDetail, error) {
}
system.EthernetInterfaces = append(system.EthernetInterfaces, ethernetinterface)
}
for _, rf_trustedmodule := range rf_computersystem.TrustedModules {
system.TrustedModules = append(system.TrustedModules, fmt.Sprintf("%s %s", rf_trustedmodule.InterfaceType, rf_trustedmodule.FirmwareVersion))
}
systems = append(systems, system)
}
return systems, nil