Skip to content

Commit

Permalink
Merge pull request #378 from bmc-toolbox/asrr
Browse files Browse the repository at this point in the history
Asrockrack firmware support
  • Loading branch information
joelrebel authored Dec 5, 2023
2 parents 3688b8c + 8340289 commit 764ac9e
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 138 deletions.
10 changes: 6 additions & 4 deletions constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ const (
FirmwareInstallPowerCycleHost = "powercycle-host"
PowerCycleHost TaskState = "powercycle-host"

// FirmwareInstallPowerCycleBMC indicates the firmware install requires a BMC power cycle
FirmwareInstallPowerCycleBMC = "powercycle-bmc"
PowerCycleBMC TaskState = "powercycle-bmc"

FirmwareInstallUnknown = "unknown"
Unknown TaskState = "unknown"

Expand All @@ -103,6 +99,12 @@ const (
// FirmwareInstallStepPowerOffHost indicates the host requires to be powered off.
FirmwareInstallStepPowerOffHost FirmwareInstallStep = "power-off-host"

// FirmwareInstallStepResetBMCPostInstall indicates the BMC requires a reset after the install.
FirmwareInstallStepResetBMCPostInstall FirmwareInstallStep = "reset-bmc-post-install"

// FirmwareInstallStepResetBMCOnInstallFailure indicates the BMC requires a reset if an install fails.
FirmwareInstallStepResetBMCOnInstallFailure FirmwareInstallStep = "reset-bmc-on-install-failure"

// device BIOS/UEFI POST code bmclib identifiers
POSTStateBootINIT = "boot-init/pxe"
POSTStateUEFI = "uefi"
Expand Down
3 changes: 3 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ var (

// ErrRedfishNoSystems is returned when the API of the device provides and empty array of systems.
ErrRedfishNoSystems = errors.New("redfish: no Systems were found on the device")

// ErrBMCUpdating is returned when the BMC is going through an update and will not serve other queries.
ErrBMCUpdating = errors.New("a BMC firmware update is in progress")
)

type ErrUnsupportedHardware struct {
Expand Down
67 changes: 50 additions & 17 deletions providers/asrockrack/asrockrack.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
package asrockrack

import (
"bytes"
"context"
"crypto/x509"
"fmt"
"net/http"
"strings"

"github.com/bmc-toolbox/bmclib/v2/constants"
"github.com/bmc-toolbox/bmclib/v2/internal/httpclient"
"github.com/bmc-toolbox/bmclib/v2/providers"
"github.com/bmc-toolbox/common"
"github.com/go-logr/logr"
"github.com/jacobweinstock/registrar"
"github.com/pkg/errors"
)

const (
// ProviderName for the provider implementation
ProviderName = "asrockrack"
// ProviderProtocol for the provider implementation
ProviderProtocol = "vendorapi"

E3C256D4ID_NL = "E3C256D4ID-NL"
E3C246D4ID_NL = "E3C246D4ID-NL"
E3C246D4I_NL = "E3C246D4I-NL"
)

var (
// Features implemented by asrockrack https
Features = registrar.Features{
providers.FeatureInventoryRead,
providers.FeatureFirmwareInstall,
providers.FeatureFirmwareInstallStatus,
providers.FeaturePostCodeRead,
providers.FeatureBmcReset,
providers.FeatureUserCreate,
providers.FeatureUserUpdate,
providers.FeatureFirmwareUpload,
providers.FeatureFirmwareInstallUploaded,
providers.FeatureFirmwareTaskStatus,
providers.FeatureFirmwareInstallSteps,
providers.FeatureInventoryRead,
providers.FeaturePowerSet,
providers.FeaturePowerState,
}
)

Expand All @@ -38,6 +49,7 @@ type ASRockRack struct {
ip string
username string
password string
deviceModel string
loginSession *loginSession
httpClient *http.Client
resetRequired bool // Indicates if the BMC requires a reset
Expand Down Expand Up @@ -100,24 +112,45 @@ func (a *ASRockRack) Name() string {
return ProviderName
}

// Compatible implements the registrar.Verifier interface
// returns true if the BMC is identified to be an asrockrack
func (a *ASRockRack) Compatible(ctx context.Context) bool {
resp, statusCode, err := a.queryHTTPS(ctx, "/", "GET", nil, nil, 0)
if err != nil {
return false
// Open a connection to a BMC, implements the Opener interface
func (a *ASRockRack) Open(ctx context.Context) (err error) {
if err := a.httpsLogin(ctx); err != nil {
return err
}

if statusCode != 200 {
return false
return a.supported(ctx)
}

func (a *ASRockRack) supported(ctx context.Context) error {
supported := []string{
E3C256D4ID_NL,
E3C246D4ID_NL,
E3C246D4I_NL,
}

return bytes.Contains(resp, []byte(`ASRockRack`))
}
if a.deviceModel == "" {
device := common.NewDevice()
device.Metadata = map[string]string{}

// Open a connection to a BMC, implements the Opener interface
func (a *ASRockRack) Open(ctx context.Context) (err error) {
return a.httpsLogin(ctx)
err := a.fruAttributes(ctx, &device)
if err != nil {
return errors.Wrap(err, "failed to identify device model")
}

if device.Model == "" {
return errors.Wrap(err, "failed to identify device model - empty model attribute")
}

a.deviceModel = device.Model
}

for _, s := range supported {
if strings.EqualFold(a.deviceModel, s) {
return nil
}
}

return fmt.Errorf("device model not supported: %s", a.deviceModel)
}

// Close a connection to a BMC, implements the Closer interface
Expand Down
19 changes: 8 additions & 11 deletions providers/asrockrack/asrockrack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@ import (
"context"
"os"
"testing"
"time"

"gopkg.in/go-playground/assert.v1"
)

func Test_Compatible(t *testing.T) {
b := aClient.Compatible(context.TODO())
if !b {
t.Errorf("expected true, got false")
}
}

func Test_httpLogin(t *testing.T) {
func TestHttpLogin(t *testing.T) {
err := aClient.httpsLogin(context.TODO())
if err != nil {
t.Errorf(err.Error())
Expand All @@ -24,7 +18,7 @@ func Test_httpLogin(t *testing.T) {
assert.Equal(t, "l5L29IP7", aClient.loginSession.CSRFToken)
}

func Test_Close(t *testing.T) {
func TestClose(t *testing.T) {
err := aClient.httpsLogin(context.TODO())
if err != nil {
t.Errorf(err.Error())
Expand All @@ -36,7 +30,7 @@ func Test_Close(t *testing.T) {
}
}

func Test_FirwmwareUpdateBMC(t *testing.T) {
func TestFirwmwareUpdateBMC(t *testing.T) {
err := aClient.httpsLogin(context.TODO())
if err != nil {
t.Errorf(err.Error())
Expand All @@ -54,7 +48,10 @@ func Test_FirwmwareUpdateBMC(t *testing.T) {
}

defer fh.Close()
err = aClient.firmwareInstallBMC(context.TODO(), fh, 0)
ctx, cancel := context.WithTimeout(context.TODO(), time.Minute*15)
defer cancel()

err = aClient.firmwareUploadBMC(ctx, fh)
if err != nil {
t.Errorf(err.Error())
}
Expand Down
Loading

0 comments on commit 764ac9e

Please sign in to comment.