diff --git a/internal/collect.go b/internal/collect.go index f5e6480..7d381af 100644 --- a/internal/collect.go +++ b/internal/collect.go @@ -2,7 +2,6 @@ package magellan import ( - "context" "crypto/tls" "encoding/json" "fmt" @@ -18,7 +17,6 @@ import ( "github.com/OpenCHAMI/magellan/internal/util" "github.com/Cray-HPE/hms-xname/xnames" - bmclib "github.com/bmc-toolbox/bmclib/v2" _ "github.com/mattn/go-sqlite3" "github.com/stmcginnis/gofish" _ "github.com/stmcginnis/gofish" @@ -228,101 +226,6 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err return nil } -// CollectInventory() fetches inventory data from all of the BMC hosts provided. -func CollectInventory(client *bmclib.Client, q *QueryParams) ([]byte, error) { - // open BMC session and update driver registry - ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout)) - client.Registry.FilterForCompatible(ctx) - err := client.PreferProvider(q.Preferred).Open(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to open client: %v", err) - } - - inventory, err := client.Inventory(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to get inventory: %v", err) - } - - // retrieve inventory data - data := map[string]any{"Inventory": inventory} - b, err := json.MarshalIndent(data, "", " ") - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to marshal JSON: %v", err) - } - - ctxCancel() - return b, nil -} - -// TODO: DELETE ME!!! -func CollectPowerState(client *bmclib.Client, q *QueryParams) ([]byte, error) { - ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout)) - client.Registry.FilterForCompatible(ctx) - err := client.PreferProvider(q.Preferred).Open(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to open client: %v", err) - } - - powerState, err := client.GetPowerState(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to get inventory: %v", err) - } - - // retrieve inventory data - data := map[string]any{"PowerState": powerState} - b, err := json.MarshalIndent(data, "", " ") - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to marshal JSON: %v", err) - } - - ctxCancel() - return b, nil - -} - -// TODO: DELETE ME!!! -func CollectUsers(client *bmclib.Client, q *QueryParams) ([]byte, error) { - // open BMC session and update driver registry - ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout)) - client.Registry.FilterForCompatible(ctx) - err := client.Open(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to connect to bmc: %v", err) - } - - defer client.Close(ctx) - - users, err := client.ReadUsers(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to get users: %v", err) - } - - // retrieve inventory data - data := map[string]any{"Users": users} - b, err := json.MarshalIndent(data, "", " ") - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to marshal JSON: %v", err) - } - - ctxCancel() - return b, nil -} - -// TODO: DELETE ME!!! -func CollectBios(client *bmclib.Client, q *QueryParams) ([]byte, error) { - b, err := makeRequest(client, client.GetBiosConfiguration, q.Timeout) - return b, err -} - // CollectEthernetInterfaces() collects all of the ethernet interfaces found // from all systems from under the "/redfish/v1/Systems" endpoint. // @@ -454,9 +357,13 @@ func CollectSystems(c *gofish.APIClient, q *QueryParams) ([]map[string]any, erro if q.Verbose { fmt.Printf("no system ethernet interfaces found...trying to get from managers interface\n") } - for _, managerLink := range system.ManagedBy { + managedBy, err := system.ManagedBy() + if err != nil { + return nil, fmt.Errorf("failed to get system managers for '%s': %w", system.Name, err) + } + for _, manager := range managedBy { // try getting ethernet interface from all managers until one is found - eths, err = redfish.ListReferencedEthernetInterfaces(c, managerLink+"/EthernetInterfaces") + eths, err = manager.EthernetInterfaces() if err != nil { return nil, fmt.Errorf("failed to get system manager ethernet interfaces: %v", err) } @@ -711,27 +618,6 @@ func makeGofishConfig(q *QueryParams) (gofish.ClientConfig, error) { }, nil } -func makeRequest[T any](client *bmclib.Client, fn func(context.Context) (T, error), timeout int) ([]byte, error) { - ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(timeout)) - client.Registry.FilterForCompatible(ctx) - err := client.Open(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to open client: %v", err) - } - - defer client.Close(ctx) - - response, err := fn(ctx) - if err != nil { - ctxCancel() - return nil, fmt.Errorf("failed to get response: %v", err) - } - - ctxCancel() - return makeJson(response) -} - func makeJson(object any) ([]byte, error) { b, err := json.MarshalIndent(object, "", " ") if err != nil { diff --git a/internal/update.go b/internal/update.go index 35ed4c4..252eba0 100644 --- a/internal/update.go +++ b/internal/update.go @@ -1,21 +1,11 @@ package magellan import ( - "context" "encoding/json" - "errors" "fmt" "net/http" - "os" - "strings" - "time" - "github.com/OpenCHAMI/magellan/internal/log" "github.com/OpenCHAMI/magellan/internal/util" - bmclib "github.com/bmc-toolbox/bmclib/v2" - "github.com/bmc-toolbox/bmclib/v2/constants" - bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors" - "github.com/sirupsen/logrus" ) type UpdateParams struct { @@ -34,102 +24,6 @@ type UpdateParams struct { // uses underneath, did not support support multipart updates. This was changed with the // inclusion of support for MultipartHttpPushUri in OpenBMC (https://gerrit.openbmc.org/c/openbmc/bmcweb/+/32174). // Also, related to bmclib: https://github.com/bmc-toolbox/bmclib/issues/341 -func UpdateFirmware(client *bmclib.Client, l *log.Logger, q *UpdateParams) error { - if q.Component == "" { - return fmt.Errorf("component is required") - } - - // open BMC session and update driver registry - ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout)) - client.Registry.FilterForCompatible(ctx) - err := client.Open(ctx) - if err != nil { - ctxCancel() - return fmt.Errorf("failed toconnect to bmc: %v", err) - } - - defer client.Close(ctx) - - file, err := os.Open(q.FirmwarePath) - if err != nil { - ctxCancel() - return fmt.Errorf("failed toopen firmware path: %v", err) - } - - defer file.Close() - - taskId, err := client.FirmwareInstall(ctx, q.Component, constants.FirmwareApplyOnReset, true, file) - if err != nil { - ctxCancel() - return fmt.Errorf("failed toinstall firmware: %v", err) - } - - for { - if ctx.Err() != nil { - ctxCancel() - return fmt.Errorf("context error: %v", ctx.Err()) - } - - state, err := client.FirmwareInstallStatus(ctx, q.FirmwareVersion, q.Component, taskId) - if err != nil { - // when its under update a connection refused is returned - if strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "operation timed out") { - l.Log.Info("BMC refused connection, BMC most likely resetting...") - time.Sleep(2 * time.Second) - - continue - } - - if errors.Is(err, bmclibErrs.ErrSessionExpired) || strings.Contains(err.Error(), "session expired") { - err := client.Open(ctx) - if err != nil { - l.Log.Fatal(err, "bmc re-login failed") - } - - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("BMC session expired, logging in...") - - continue - } - - l.Log.Fatal(err) - } - - switch state { - case constants.FirmwareInstallRunning, constants.FirmwareInstallInitializing: - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("firmware install running") - - case constants.FirmwareInstallFailed: - ctxCancel() - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("firmware install failed") - return fmt.Errorf("failed to install firmware") - - case constants.FirmwareInstallComplete: - ctxCancel() - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("firmware install completed") - return nil - - case constants.FirmwareInstallPowerCyleHost: - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("host powercycle required") - - if _, err := client.SetPowerState(ctx, "cycle"); err != nil { - ctxCancel() - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("error power cycling host for install") - return fmt.Errorf("failed to install firmware") - } - - ctxCancel() - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("host power cycled, all done!") - return nil - default: - l.Log.WithFields(logrus.Fields{"state": state, "component": q.Component}).Info("unknown state returned") - } - - time.Sleep(2 * time.Second) - } - - return nil -} - func UpdateFirmwareRemote(q *UpdateParams) error { url := baseRedfishUrl(&q.QueryParams) + "/redfish/v1/UpdateService/Actions/SimpleUpdate" headers := map[string]string{ @@ -172,27 +66,3 @@ func GetUpdateStatus(q *UpdateParams) error { } return nil } - -// func UpdateFirmwareLocal(q *UpdateParams) error { -// fwUrl := baseUrl(&q.QueryParams) + "" -// url := baseUrl(&q.QueryParams) + "UpdateService/Actions/" -// headers := map[string]string { - -// } - -// // get etag from FW inventory -// response, err := util.MakeRequest() - -// // load file from disk -// file, err := os.ReadFile(q.FirmwarePath) -// if err != nil { -// return fmt.Errorf("failed toread file: %v", err) -// } - -// switch q.TransferProtocol { -// case "HTTP": -// default: -// return fmt.Errorf("transfer protocol not supported") -// } -// return nil -// }