From e6325719f4266210f3fefd53c0c9066e43cc4bcd Mon Sep 17 00:00:00 2001 From: Alex Lovell-Troy Date: Fri, 28 Jun 2024 06:17:22 +0200 Subject: [PATCH] Update crawler to better handle odd Redfish implementations --- go.mod | 6 ++++ go.sum | 13 +++++++ pkg/crawler/main.go | 87 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 88 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 703858f..f830790 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,11 @@ require ( golang.org/x/exp v0.0.0-20230905200255-921286631fa9 ) +require ( + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect +) + require ( github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 // indirect github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 // indirect @@ -42,6 +47,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rs/zerolog v1.33.0 github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect diff --git a/go.sum b/go.sum index 12da651..887feb4 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= @@ -86,6 +87,7 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -187,6 +189,11 @@ github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -205,6 +212,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= @@ -406,10 +416,13 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/pkg/crawler/main.go b/pkg/crawler/main.go index 6d876a6..d2d5b64 100644 --- a/pkg/crawler/main.go +++ b/pkg/crawler/main.go @@ -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