From a9e2dff7343732711d62ab2e374f90e79f8ca063 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Feb 2021 16:48:02 +0100 Subject: [PATCH 01/42] Add methods, initial work to probe for ASRR BMCs --- discover/discover.go | 3 +++ discover/discovery_test.go | 5 +++++ discover/probe.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/discover/discover.go b/discover/discover.go index 7c4473e4..73d8d9e8 100644 --- a/discover/discover.go +++ b/discover/discover.go @@ -22,6 +22,7 @@ const ( ProbeM1000e = "m1000e" ProbeQuanta = "quanta" ProbeHpCl100 = "hpcl100" + ProbeASRockRack = "asrockrack" ) // ScanAndConnect will scan the bmc trying to learn the device type and return a working connection. @@ -63,6 +64,7 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e: probe.m1000e, ProbeQuanta: probe.quanta, ProbeHpCl100: probe.hpCl100, + ProbeASRockRack: probe.asRockRack, } order := []string{ProbeHpIlo, @@ -74,6 +76,7 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e, ProbeQuanta, ProbeHpCl100, + ProbeASRockRack, } if opts.Hint != "" { diff --git a/discover/discovery_test.go b/discover/discovery_test.go index 0aa885d7..bf4806c1 100644 --- a/discover/discovery_test.go +++ b/discover/discovery_test.go @@ -113,6 +113,11 @@ func TestProbes(t *testing.T) { wantHint: ProbeHpIlo, wantType: (*ilo.Ilo)(nil), }, + { + name: "ASRockRack", + wantHint: ProbeASRockRack, + wantType: nil, + }, } for _, tt := range testt { diff --git a/discover/probe.go b/discover/probe.go index 050e09d9..81cce646 100644 --- a/discover/probe.go +++ b/discover/probe.go @@ -13,6 +13,7 @@ import ( "github.com/bmc-toolbox/bmclib/devices" "github.com/bmc-toolbox/bmclib/errors" + "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/dell/idrac8" "github.com/bmc-toolbox/bmclib/providers/dell/idrac9" "github.com/bmc-toolbox/bmclib/providers/dell/m1000e" @@ -332,6 +333,33 @@ func (p *Probe) quanta(ctx context.Context, log logr.Logger) (bmcConnection inte return bmcConnection, errors.ErrDeviceNotMatched } +func (p *Probe) asRockRack(ctx context.Context, log logr.Logger) (bmcConnection interface{}, err error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s", p.host), nil) + if err != nil { + return bmcConnection, err + } + resp, err := p.client.Do(req) + if err != nil { + return bmcConnection, err + } + + defer resp.Body.Close() + defer io.Copy(ioutil.Discard, resp.Body) // nolint + + payload, err := ioutil.ReadAll(resp.Body) + if err != nil { + return bmcConnection, err + } + + // ensure the response we got included a png + if resp.StatusCode == 200 && bytes.Contains(payload, []byte("ASRockRack")) { + log.V(1).Info("step", "ScanAndConnect", "host", p.host, "vendor", string(devices.ASRockRack), "msg", "it's a ASRockRack") + return asrockrack.New(ctx, p.host, p.username, p.password, log) + } + + return bmcConnection, errors.ErrDeviceNotMatched +} + func containsAnySubStr(data []byte, subStrs []string) bool { for _, subStr := range subStrs { if bytes.Contains(data, []byte(subStr)) { From d7ddf5d5055c12669b376ec889ad0fa7087853f2 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Feb 2021 16:48:45 +0100 Subject: [PATCH 02/42] providers/asrockrack: Implment BMC firmware update, version info methods --- providers/asrockrack/asrockrack.go | 206 +++++++++++++++ providers/asrockrack/asrockrack_test.go | 78 ++++++ providers/asrockrack/firmware_update.md | 34 +++ providers/asrockrack/helpers.go | 338 ++++++++++++++++++++++++ providers/asrockrack/mock.go | 215 +++++++++++++++ providers/providers.go | 8 + 6 files changed, 879 insertions(+) create mode 100644 providers/asrockrack/asrockrack.go create mode 100644 providers/asrockrack/asrockrack_test.go create mode 100644 providers/asrockrack/firmware_update.md create mode 100644 providers/asrockrack/helpers.go create mode 100644 providers/asrockrack/mock.go diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go new file mode 100644 index 00000000..d6e16d2b --- /dev/null +++ b/providers/asrockrack/asrockrack.go @@ -0,0 +1,206 @@ +package asrockrack + +import ( + "context" + "fmt" + "net/http" + "os" + "strings" + "time" + + "github.com/bmc-toolbox/bmclib/internal/httpclient" + "github.com/bmc-toolbox/bmclib/providers" + "github.com/go-logr/logr" + "github.com/jacobweinstock/registrar" +) + +const ( + // BmcType defines the bmc model that is supported by this package + BmcType = "asrockrack" + // VendorID represents the id of the vendor across all packages + VendorID = "ASRockRack" + // ProviderName for the provider implementation + ProviderName = "asrockrack" + // ProviderProtocol for the provider implementation + ProviderProtocol = "https" +) + +var ( + // Features implemented by asrockrack https + Features = registrar.Features{ + providers.FeatureBiosVersionRead, + providers.FeatureBmcVersionRead, + providers.FeatureBiosFirmwareUpdate, + providers.FeatureBmcFirmwareUpdate, + } +) + +// ASRockRack holds the status and properties of a connection to a asrockrack bmc +type ASRockRack struct { + ip string + username string + password string + sid *http.Cookie + loginSession *loginSession + httpClient *http.Client + fwInfo *firmwareInfo + flashModeSet bool + ctx context.Context + log logr.Logger +} + +// New returns a new SupermicroX instance ready to be used +func New(ctx context.Context, ip string, username string, password string, log logr.Logger) (*ASRockRack, error) { + + client, err := httpclient.Build() + if err != nil { + return nil, err + } + + return &ASRockRack{ + ip: ip, + username: username, + password: password, + ctx: ctx, + log: log, + loginSession: &loginSession{}, + httpClient: client, + }, nil +} + +// Open a connection to a BMC +func (a *ASRockRack) Open(ctx context.Context) (err error) { + + err = a.httpsLogin() + if err != nil { + return err + } + + return nil +} + +// Close a connection to a BMC +func (a *ASRockRack) Close(ctx context.Context) (err error) { + + err = a.httpsLogout() + if err != nil { + return err + } + + return nil +} + +// BiosVersion returns the BIOS version from the BMC +func (a *ASRockRack) BiosVersion() (string, error) { + + var err error + if a.fwInfo == nil { + a.fwInfo, err = a.firmwareInfo() + if err != nil { + return "", err + } + } + + return a.fwInfo.BIOSVersion, nil +} + +// BMCVersion returns the BMC version +func (a *ASRockRack) BMCVersion() (string, error) { + + var err error + if a.fwInfo == nil { + a.fwInfo, err = a.firmwareInfo() + if err != nil { + return "", err + } + } + + return a.fwInfo.BIOSVersion, nil +} + +// nolint: gocyclo +// BMC firmware update is a multi step process +// this method initiates the upgrade process and waits in a loop until the device has been upgraded +func (a *ASRockRack) FirmwareUpdateBMC(filePath string) error { + + // The BMC needs to be reset once set into flash mode + defer func() { + if a.flashModeSet { + a.log.V(1).Info("info", "resetting BMC, this takes a few minutes") + err := a.reset() + if err != nil { + a.log.Error(err, "failed to reset BMC") + } + } + }() + + // 0. validate the given filePath exists + _, err := os.Stat(filePath) + if os.IsNotExist(err) { + return err + } + + // 1. set the device to flash mode - prepares the flash + a.log.V(1).Info("info", "step 1/5 - setting device into flash mode.. this takes a minute", "filePath", filePath) + err = a.setFlashMode() + if err != nil { + return fmt.Errorf("failed in step 1/5 - set device in flash mode: " + err.Error()) + } + + // 2. upload firmware image file + a.log.V(1).Info("info", "step 2/5 - uploading firmware image", "filePath", filePath) + err = a.uploadFirmware(filePath) + if err != nil { + return fmt.Errorf("failed in step 2/5 - upload firmware image: " + err.Error()) + } + + // 3. BMC to verify the uploaded file + err = a.verifyUploadedFirmware() + a.log.V(1).Info("info", "step 3/5 - verify uploaded firmware", "filePath", filePath) + if err != nil { + return fmt.Errorf("failed in step 3/5 - verify uploaded firmware: " + err.Error()) + } + + startTS := time.Now() + // 4. Run the upgrade - preserving current config + a.log.V(1).Info("info", "step 4/5 - run the upgrade, preserving current configuration", "filePath", filePath) + err = a.upgradeBMC() + if err != nil { + return fmt.Errorf("failed in step 4/5 - verify uploaded firmware: " + err.Error()) + } + + // progress check interval + progressT := time.NewTicker(10 * time.Second).C + // timeout interval + timeoutT := time.NewTicker(30 * time.Minute).C + maxErrors := 20 + var errorsCount int + + // 5.loop until firmware was updated - with a timeout + for { + select { + case <-progressT: + // check progress + p, err := a.flashProgress() + if err != nil { + errorsCount++ + a.log.Error(err, "step 5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + } + + a.log.V(1).Info("info", "step 5/5 - flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + + // all done! + if strings.Contains(p.Progress, "100% done") { + return nil + } + case <-timeoutT: + return fmt.Errorf("timeout in step 5/5 - flash progress, error count: %d, elapsed time: %s", errorsCount, time.Since(startTS).String()) + } + } + +} + +func (a *ASRockRack) FirmwareUpdateBIOS(filePath string) error { + + return nil +} diff --git a/providers/asrockrack/asrockrack_test.go b/providers/asrockrack/asrockrack_test.go new file mode 100644 index 00000000..52c48f0a --- /dev/null +++ b/providers/asrockrack/asrockrack_test.go @@ -0,0 +1,78 @@ +package asrockrack + +import ( + "os" + "testing" + + "gopkg.in/go-playground/assert.v1" +) + +func Test_httpLogin(t *testing.T) { + + err := aClient.httpsLogin() + if err != nil { + t.Errorf(err.Error()) + } + + assert.Equal(t, "l5L29IP7", aClient.loginSession.CSRFToken) +} + +func Test_Close(t *testing.T) { + + err := aClient.httpsLogin() + if err != nil { + t.Errorf(err.Error()) + } + + err = aClient.httpsLogout() + if err != nil { + t.Errorf(err.Error()) + } +} + +func Test_FirmwareInfo(t *testing.T) { + + expected := firmwareInfo{ + BMCVersion: "0.01.00", + BIOSVersion: "L2.07B", + MEVersion: "5.1.3.78", + MicrocodeVersion: "000000ca", + CPLDVersion: "N/A", + CMVersion: "0.13.01", + BPBVersion: "0.0.002.0", + NodeID: "2", + } + + err := aClient.httpsLogin() + if err != nil { + t.Errorf(err.Error()) + } + + fwInfo, err := aClient.firmwareInfo() + if err != nil { + t.Error(err.Error()) + } + + assert.Equal(t, expected, fwInfo) + +} + +func Test_FirwmwareUpdateBMC(t *testing.T) { + + err := aClient.httpsLogin() + if err != nil { + t.Errorf(err.Error()) + } + + upgradeFile := "/tmp/dummy-E3C246D4I-NL_L0.01.00.ima" + _, err = os.Create(upgradeFile) + if err != nil { + t.Errorf(err.Error()) + } + + defer os.Remove(upgradeFile) + err = aClient.FirmwareUpdateBMC(upgradeFile) + if err != nil { + t.Errorf(err.Error()) + } +} diff --git a/providers/asrockrack/firmware_update.md b/providers/asrockrack/firmware_update.md new file mode 100644 index 00000000..91af108e --- /dev/null +++ b/providers/asrockrack/firmware_update.md @@ -0,0 +1,34 @@ + + Flashing a BMC firmware seems to be a multi step process + + + 1. PUT /api/maintenance/flash + no payload (seems to set the device to be in flash mode or such) + 200 OK - takes about a minute to return + + 2. POST /api/maintenance/firmware + Content-Type: multipart/form-data + ------WebKitFormBoundaryESKCgdjyLnqUPHBK + Content-Disposition: form-data; name="fwimage"; filename="E3C246D4I-NL_L0.01.00.ima" + Content-Type: application/octet-stream + ------WebKitFormBoundaryESKCgdjyLnqUPHBK-- + . response - '{"cc": 0}' - successful upload + + 3. GET /api/maintenance/firmware/verification + 500 - Bad firmware payload -> invoke reset + 200 - OK + [ { "id": 1, "current_image_name": "ast2500e", "current_image_version1": "0.01.00", "current_image_version2": "", "new_image_version": "0.03.00", "section_status": 0, "verification_status": 5 } ] + + 4. If verificaion fails OR firmware update progress is at 100% done - invoke reset + + GET /api/maintenance/reset + 200 OK + + 5. PUT /api/maintenance/firmware/upgrade + payload {"preserve_config":1,"preserve_network":0,"preserve_user":0,"flash_status":1} + 200 OK + response - same as payload + + 6. GET https://10.230.148.171/api/maintenance/firmware/flash-progress + { "id": 1, "action": "Flashing...", "progress": "12% done ", "state": 0 } + { "id": 1, "action": "Flashing...", "progress": "100% done", "state": 0 } \ No newline at end of file diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go new file mode 100644 index 00000000..0b00a4f9 --- /dev/null +++ b/providers/asrockrack/helpers.go @@ -0,0 +1,338 @@ +package asrockrack + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "net/http/httputil" + "os" + "path" + + "github.com/bmc-toolbox/bmclib/errors" + log "github.com/sirupsen/logrus" +) + +// API session setup response payload +type loginSession struct { + CSRFToken string `json:"csrftoken,omitempty"` + Privilege int `json:"privilege,omitempty"` + RACSessionID int `json:"racsession_id,omitempty"` + ExtendedPrivilege int `json:"extendedpriv,omitempty"` +} + +// Firmware info endpoint response payload +type firmwareInfo struct { + BMCVersion string `json:"BMC_fw_version"` + BIOSVersion string `json:"BIOS_fw_version"` + MEVersion string `json:"ME_fw_version"` + MicrocodeVersion string `json:"Micro_Code_version"` + CPLDVersion string `json:"CPLD_version"` + CMVersion string `json:"CM_version"` + BPBVersion string `json:"BPB_version"` + NodeID string `json:"Node_id"` +} + +// Payload to preseve config when updating the BMC firmware +type preserveConfig struct { + PreserveConfig int `json:"preserve_config,omitempty"` + PreserveNetwork int `json:"preserve_network"` + PreserveUser int `json:"preserve_user"` + FlashStatus int `json:"flash_status"` // 1 = full firmware flash, 2 = section based flash, 3 - version compare flash +} + +// Firmware flash progress +//{ "id": 1, "action": "Flashing...", "progress": "12% done ", "state": 0 } +//{ "id": 1, "action": "Flashing...", "progress": "100% done", "state": 0 } +type upgradeProgress struct { + ID int `json:"id,omitempty"` + Action string `json:"action,omitempty"` + Progress string `json:"progress,omitempty"` + State int `json:"state,omitempty"` +} + +// 1 Set BMC to flash mode and prepare flash area +func (a *ASRockRack) setFlashMode() error { + + endpoint := "api/maintenance/flash" + + _, statusCode, err := a.queryHTTPS(endpoint, "PUT", nil, nil) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + a.flashModeSet = true + + return nil +} + +// 2 Upload the firmware file +func (a *ASRockRack) uploadFirmware(filePath string) error { + + endpoint := "api/maintenance/firmware" + + // setup a buffer for our multipart form + var form bytes.Buffer + w := multipart.NewWriter(&form) + + // create form data from update image + fwWriter, err := w.CreateFormFile("fwimage", path.Base(filePath)) + if err != nil { + return err + } + + // open file handle + fh, err := os.Open(filePath) + if err != nil { + return err + } + + // copy file contents into form payload + fReader := bufio.NewReader(fh) + _, err = io.Copy(fwWriter, fReader) + if err != nil { + return err + } + + // multi-part content type + headers := map[string]string{"Content-Type": w.FormDataContentType()} + + // close multipart writer - adds the teminating boundary. + w.Close() + + // POST payload + _, statusCode, err := a.queryHTTPS(endpoint, "POST", form.Bytes(), headers) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + return nil +} + +// 3. Verify uploaded firmware file - to be invoked after uploadFirmware() +func (a *ASRockRack) verifyUploadedFirmware() error { + + endpoint := "api/maintenance/firmware/verification" + + _, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + return nil + +} + +// 4. Start firmware flashing process - to be invoked after verifyUploadedFirmware +func (a *ASRockRack) upgradeBMC() error { + + endpoint := "api/maintenance/firmware/upgrade" + + // preserve all configuration during upgrade, full flash + pConfig := &preserveConfig{PreserveConfig: 1, FlashStatus: 1} + payload, err := json.Marshal(pConfig) + if err != nil { + return err + } + + _, statusCode, err := a.queryHTTPS(endpoint, "PUT", payload, nil) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + return nil + +} + +// 4. reset BMC +func (a *ASRockRack) reset() error { + + endpoint := "api/maintenance/reset" + + _, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + return nil + +} + +// 5. firmware flash progress +func (a *ASRockRack) flashProgress() (*upgradeProgress, error) { + + endpoint := "api/maintenance/firmware/flash-progress" + resp, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) + if err != nil { + return nil, err + } + + if statusCode != 200 { + return nil, fmt.Errorf("Non 200 response: %d", statusCode) + } + + p := &upgradeProgress{} + err = json.Unmarshal(resp, p) + if err != nil { + return nil, err + } + + return p, nil + +} + +// Query firmware information from the BMC +func (a *ASRockRack) firmwareInfo() (*firmwareInfo, error) { + + endpoint := "api/asrr/fw-info" + + resp, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) + if err != nil { + return nil, err + } + + if statusCode != 200 { + return nil, fmt.Errorf("Non 200 response: %d", statusCode) + } + + f := &firmwareInfo{} + err = json.Unmarshal(resp, f) + if err != nil { + return nil, err + } + + return f, nil + +} + +// Aquires a session id cookie and a csrf token +func (a *ASRockRack) httpsLogin() error { + + urlEndpoint := "api/session" + + // login payload + payload := []byte( + fmt.Sprintf("username=%s&password=%s&certlogin=0", + a.username, + a.password, + ), + ) + + headers := map[string]string{"Content-Type": "application/x-www-form-urlencoded"} + + resp, statusCode, err := a.queryHTTPS(urlEndpoint, "POST", payload, headers) + if err != nil { + return fmt.Errorf("Error logging in: " + err.Error()) + } + + if statusCode == 401 { + return errors.ErrLoginFailed + } + + // Unmarshal login session + err = json.Unmarshal(resp, a.loginSession) + if err != nil { + return fmt.Errorf("error unmarshalling response payload: " + err.Error()) + } + + return nil +} + +// Close ends the BMC session +func (a *ASRockRack) httpsLogout() error { + + urlEndpoint := "api/session" + log.WithFields(log.Fields{"step": "bmc connection", "vendor": VendorID, "ip": a.ip}).Debug("logout from bmc") + + _, statusCode, err := a.queryHTTPS(urlEndpoint, "DELETE", nil, nil) + if err != nil { + return fmt.Errorf("Error logging out: " + err.Error()) + } + + if err != nil { + return fmt.Errorf("Error logging out: " + err.Error()) + } + + if statusCode != 200 { + return fmt.Errorf("Error logging out: " + err.Error()) + } + + return nil +} + +// queryHTTPS run the HTTPS query passing in the required headers +// the / suffix should be excluded from the URLendpoint +// returns - response body, http status code, error if any +func (a *ASRockRack) queryHTTPS(URLendpoint, method string, payload []byte, headers map[string]string) ([]byte, int, error) { + + var body []byte + var err error + var req *http.Request + + URL := fmt.Sprintf("https://%s/%s", a.ip, URLendpoint) + if len(payload) > 0 { + req, err = http.NewRequest(method, URL, bytes.NewReader(payload)) + } else { + req, err = http.NewRequest(method, URL, nil) + } + + // + if err != nil { + return nil, 0, err + } + + // add headers + req.Header.Add("X-CSRFTOKEN", a.loginSession.CSRFToken) + if headers != nil { + for k, v := range headers { + req.Header.Add(k, v) + } + } + + // debug dump request + reqDump, _ := httputil.DumpRequestOut(req, true) + a.log.V(2).Info("trace", "url", URL, "requestDump", string(reqDump)) + + resp, err := a.httpClient.Do(req) + if err != nil { + return body, 0, err + } + + // debug dump response + respDump, _ := httputil.DumpResponse(resp, true) + a.log.V(2).Info("trace", "responseDump", string(respDump)) + + body, err = ioutil.ReadAll(resp.Body) + if err != nil { + return body, 0, err + } + + defer resp.Body.Close() + + return body, resp.StatusCode, nil + +} diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go new file mode 100644 index 00000000..e49a7c41 --- /dev/null +++ b/providers/asrockrack/mock.go @@ -0,0 +1,215 @@ +package asrockrack + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + + "github.com/bombsimon/logrusr" + "github.com/sirupsen/logrus" +) + +var ( + loginPayload = []byte(`username=foo&password=bar&certlogin=0`) + loginResponse = []byte(`{ "ok": 0, "privilege": 4, "extendedpriv": 259, "racsession_id": 10, "remote_addr": "136.144.50.145", "server_name": "10.230.148.171", "server_addr": "10.230.148.171", "HTTPSEnabled": 1, "CSRFToken": "l5L29IP7" }`) + fwinfoResponse = []byte(`{ "BMC_fw_version": "0.01.00", "BIOS_fw_version": "L2.07B", "ME_fw_version": "5.1.3.78", "Micro_Code_version": "000000ca", "CPLD_version": "N\/A", "CM_version": "0.13.01", "BPB_version": "0.0.002.0", "Node_id": "2" }`) + fwUploadResponse = []byte(`{"cc": 0}`) + fwVerificationResponse = []byte(`[ { "id": 1, "current_image_name": "ast2500e", "current_image_version1": "0.01.00", "current_image_version2": "", "new_image_version": "0.03.00", "section_status": 0, "verification_status": 5 } ]`) + fwUpgradeResponse = []byte(`{"preserve_config":1,"preserve_network":0,"preserve_user":0,"flash_status":1}`) + fwUpgradeProgress = []byte(`{ "id": 1, "action": "Flashing...", "progress": "__PERCENT__% done ", "state": 0 }`) +) + +// setup test BMC +var server *httptest.Server +var bmcURL *url.URL +var fwUpgradeState *testFwUpgradeState + +type testFwUpgradeState struct { + FlashModeSet bool + FirmwareUploaded bool + FirmwareVerified bool + UpgradeInitiated bool + UpgradePercent int + ResetDone bool +} + +// the bmc lib client +var aClient *ASRockRack + +func init() { + + var err error + // setup mock server + server = mockASRockBMC() + bmcURL, _ = url.Parse(server.URL) + + l := logrus.New() + l.Level = logrus.InfoLevel + // setup bmc client + tLog := logrusr.NewLogger(l) + aClient, err = New(context.TODO(), bmcURL.Host, "foo", "bar", tLog) + if err != nil { + log.Fatal(err.Error()) + } + + // firmware update test state + fwUpgradeState = &testFwUpgradeState{} +} + +/////////////// mock bmc service /////////////////////////// +func mockASRockBMC() *httptest.Server { + handler := http.NewServeMux() + handler.HandleFunc("/api/session", session) + handler.HandleFunc("/api/asrr/fw-info", fwinfo) + + // fw update endpoints - in order of invocation + handler.HandleFunc("/api/maintenance/flash", firmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware", firmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware/verification", firmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware/upgrade", firmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware/flash-progress", firmwareUpgrade) + handler.HandleFunc("/api/maintenance/reset", firmwareUpgrade) + + return httptest.NewTLSServer(handler) +} + +func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { + fmt.Printf("%s -> %s\n", r.Method, r.RequestURI) + switch r.Method { + case "GET": + switch r.RequestURI { + // 3. bmc verifies uploaded firmware image + case "/api/maintenance/firmware/verification": + if !fwUpgradeState.FirmwareUploaded { + w.WriteHeader(http.StatusBadRequest) + } + fwUpgradeState.FirmwareVerified = true + w.Write(fwVerificationResponse) + case "/api/maintenance/reset": + w.WriteHeader(http.StatusOK) + // 5. flash progress + case "/api/maintenance/firmware/flash-progress": + if !fwUpgradeState.UpgradeInitiated { + w.WriteHeader(http.StatusBadRequest) + } + + if fwUpgradeState.UpgradePercent >= 100 { + fwUpgradeState.UpgradePercent = 100 + } else { + fwUpgradeState.UpgradePercent += 50 + } + + resp := bytes.Replace(fwUpgradeProgress, []byte("__PERCENT__"), []byte(strconv.Itoa(fwUpgradeState.UpgradePercent)), 1) + w.Write(resp) + } + case "PUT": + + switch r.RequestURI { + // 1. set device to flash mode + case "/api/maintenance/flash": + fwUpgradeState.FlashModeSet = true + w.WriteHeader(http.StatusOK) + // 4. run the upgrade + case "/api/maintenance/firmware/upgrade": + if !fwUpgradeState.FirmwareVerified { + w.WriteHeader(http.StatusBadRequest) + } + + p := &preserveConfig{} + err := json.NewDecoder(r.Body).Decode(&p) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + // config should be preserved + if p.PreserveConfig != 1 { + w.WriteHeader(http.StatusBadRequest) + } + + // full firmware flash + if p.FlashStatus != 1 { + w.WriteHeader(http.StatusBadRequest) + } + + fwUpgradeState.UpgradeInitiated = true + // respond with request body + b := new(bytes.Buffer) + b.ReadFrom(r.Body) + w.Write(b.Bytes()) + } + case "POST": + switch r.RequestURI { + // 2. upload firmware + case "/api/maintenance/firmware": + + // validate flash mode set + if !fwUpgradeState.FlashModeSet { + w.WriteHeader(http.StatusBadRequest) + } + + // validate content type + if !strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") { + w.WriteHeader(http.StatusBadRequest) + } + + // parse multipart form + err := r.ParseMultipartForm(100) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + } + + fwUpgradeState.FirmwareUploaded = true + w.Write(fwUploadResponse) + } + default: + w.WriteHeader(http.StatusBadRequest) + } +} + +func fwinfo(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + _, _ = w.Write(fwinfoResponse) + } + +} + +func session(w http.ResponseWriter, r *http.Request) { + + switch r.Method { + case "POST": + // login to BMC + b, _ := ioutil.ReadAll(r.Body) + if string(b) == string(loginPayload) { + + // login request needs to be of the right content-typ + if r.Header.Get("Content-Type") != "application/x-www-form-urlencoded" { + w.WriteHeader(http.StatusBadRequest) + } + + w.Header().Set("Content-Type", "application/json") + http.SetCookie(w, &http.Cookie{Name: "QSESSIONID", Value: "94ed00f482249dd77arIcp6eBBJaik", Path: "/"}) + _, _ = w.Write(loginResponse) + } else { + w.WriteHeader(http.StatusBadRequest) + } + case "DELETE": + //1for h, values := range r.Header { + //1 for _, v := range values { + //1 fmt.Println(h, v) + //1 } + //1} + if r.Header.Get("X-Csrftoken") != "l5L29IP7" { + w.WriteHeader(http.StatusBadRequest) + } + } +} diff --git a/providers/providers.go b/providers/providers.go index a4577c83..887fa01a 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -21,4 +21,12 @@ const ( FeatureBmcReset registrar.Feature = "bmcreset" // FeatureBootDeviceSet means an implementation the next boot device FeatureBootDeviceSet registrar.Feature = "bootdeviceset" + // FeatureBmcVersionRead means an implementation that returns the BMC firmware version + FeatureBmcVersionRead registrar.Feature = "bmcversionread" + // FeatureBiosVersionRead means an implementation that returns the BIOS firmware version + FeatureBiosVersionRead registrar.Feature = "biosversionread" + // FeatureBmcFirmwareUpdate means an implementation that updates the BMC firmware + FeatureBmcFirmwareUpdate registrar.Feature = "bmcfirwareupdate" + // FeatureBiosFirmwareUpdate means an implementation that updates the BIOS firmware + FeatureBiosFirmwareUpdate registrar.Feature = "biosfirwareupdate" ) From 323d4d68ec6479bc4c91ec27bd27f40390b89b69 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Feb 2021 16:49:24 +0100 Subject: [PATCH 03/42] bmc: Add firmware update/getter interface methods --- bmc/firmware.go | 104 ++++++++++++++++++++++++++++++++++++++ bmc/firmware_test.go | 117 +++++++++++++++++++++++++++++++++++++++++++ client.go | 6 +++ 3 files changed, 227 insertions(+) create mode 100644 bmc/firmware.go create mode 100644 bmc/firmware_test.go diff --git a/bmc/firmware.go b/bmc/firmware.go new file mode 100644 index 00000000..d5d92c56 --- /dev/null +++ b/bmc/firmware.go @@ -0,0 +1,104 @@ +package bmc + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/go-multierror" +) + +// BMCVersionGetter retrieves the current BMC firmware version information +type BMCVersionGetter interface { + FirmwareVersionBMC(ctx context.Context) (version string, err error) +} + +// BMCFirmwareUpdater upgrades the BMC firmware +type BMCFirmwareUpdater interface { + FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) +} + +// GetBMCVersion returns the BMC firmware version, trying all interface implementations passed in +func GetBMCVersion(ctx context.Context, p []BMCVersionGetter) (version string, err error) { +Loop: + for _, elem := range p { + select { + case <-ctx.Done(): + err = multierror.Append(err, ctx.Err()) + break Loop + default: + if elem != nil { + version, vErr := elem.FirmwareVersionBMC(ctx) + if vErr != nil { + err = multierror.Append(err, vErr) + continue + } + return version, nil + } + } + } + + return version, multierror.Append(err, errors.New("failed to get BMC version")) +} + +// GetBMCVersionFromInterfaces pass through to library function +func GetBMCVersionFromInterfaces(ctx context.Context, generic []interface{}) (version string, err error) { + bmcVersionGetter := make([]BMCVersionGetter, 0) + for _, elem := range generic { + switch p := elem.(type) { + case BMCVersionGetter: + bmcVersionGetter = append(bmcVersionGetter, p) + default: + e := fmt.Sprintf("not a BMCVersionGetter implementation: %T", p) + err = multierror.Append(err, errors.New(e)) + } + } + if len(bmcVersionGetter) == 0 { + return version, multierror.Append(err, errors.New("no BMCVersionGetter implementations found")) + } + + return GetBMCVersion(ctx, bmcVersionGetter) +} + +// UpdateBMCFirmware upgrades the BMC firmware, trying all interface implementations passed ini +func UpdateBMCFirmware(ctx context.Context, updateFileName string, p []BMCFirmwareUpdater) (err error) { +Loop: + for _, elem := range p { + select { + case <-ctx.Done(): + err = multierror.Append(err, ctx.Err()) + break Loop + default: + if elem != nil { + uErr := elem.FirmwareUpdateBMC(ctx, updateFileName) + if uErr != nil { + err = multierror.Append(err, uErr) + continue + } + return nil + } + } + } + + return multierror.Append(err, errors.New("failed to update BMC firmware")) + +} + +// GetBMCVersionFromInterfaces pass through to library function +func UpdateBMCFirmwareFromInterfaces(ctx context.Context, updateFileName string, generic []interface{}) (err error) { + bmcFirmwareUpdater := make([]BMCFirmwareUpdater, 0) + for _, elem := range generic { + switch p := elem.(type) { + case BMCFirmwareUpdater: + bmcFirmwareUpdater = append(bmcFirmwareUpdater, p) + default: + e := fmt.Sprintf("not a BMCFirmwareUpdater implementation: %T", p) + err = multierror.Append(err, errors.New(e)) + } + } + if len(bmcFirmwareUpdater) == 0 { + return multierror.Append(err, errors.New("no BMCFirmwareUpdater implementations found")) + } + + return UpdateBMCFirmware(ctx, updateFileName, bmcFirmwareUpdater) +} diff --git a/bmc/firmware_test.go b/bmc/firmware_test.go new file mode 100644 index 00000000..cf91989e --- /dev/null +++ b/bmc/firmware_test.go @@ -0,0 +1,117 @@ +package bmc + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/go-multierror" +) + +type firmwareTester struct { + MakeNotOK bool + MakeErrorOut bool +} + +func (f *firmwareTester) FirmwareVersionBMC(ctx context.Context) (version string, err error) { + if f.MakeErrorOut { + return "", errors.New("failed to get BMC version") + } + if f.MakeNotOK { + return "", nil + } + return "1.33.7", nil +} + +func (f *firmwareTester) FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) { + if f.MakeErrorOut { + return errors.New("failed update") + } + + return nil +} + +func TestGetBMCVersion(t *testing.T) { + testCases := []struct { + name string + version string + makeFail bool + err error + ctxTimeout time.Duration + }{ + {name: "success", version: "1.33.7", err: nil}, + {name: "failure", version: "", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("failed to get BMC version"), errors.New("failed to get BMC version")}}}, + {name: "fail context timeout", version: "", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded"), errors.New("failed to get BMC version")}}, ctxTimeout: time.Nanosecond * 1}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + testImplementation := firmwareTester{MakeErrorOut: tc.makeFail} + expectedResult := tc.version + if tc.ctxTimeout == 0 { + tc.ctxTimeout = time.Second * 3 + } + ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout) + defer cancel() + result, err := GetBMCVersion(ctx, []BMCVersionGetter{&testImplementation}) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + + } else { + diff := cmp.Diff(expectedResult, result) + if diff != "" { + t.Fatal(diff) + } + } + + }) + } +} + +func TestGetBMCVersionFromInterfaces(t *testing.T) { + testCases := []struct { + name string + version string + err error + badImplementation bool + want string + }{ + {name: "success", version: "1.33.7", err: nil}, + {name: "no implementations found", version: "", want: "", badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a BMCVersionGetter implementation: *struct {}"), errors.New("no BMCVersionGetter implementations found")}}}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + var generic []interface{} + if tc.badImplementation { + badImplementation := struct{}{} + generic = []interface{}{&badImplementation} + } else { + testImplementation := firmwareTester{} + generic = []interface{}{&testImplementation} + } + expectedResult := tc.version + result, err := GetBMCVersionFromInterfaces(context.Background(), generic) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + + } else { + diff := cmp.Diff(expectedResult, result) + if diff != "" { + t.Fatal(diff) + } + } + + }) + } +} diff --git a/client.go b/client.go index 17e0e004..9a57af02 100644 --- a/client.go +++ b/client.go @@ -6,7 +6,9 @@ import ( "context" "github.com/bmc-toolbox/bmclib/bmc" + "github.com/bmc-toolbox/bmclib/internal/httpclient" "github.com/bmc-toolbox/bmclib/logging" + "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/ipmitool" "github.com/go-logr/logr" "github.com/jacobweinstock/registrar" @@ -68,6 +70,10 @@ func (c *Client) registerProviders() { // register ipmitool provider driverIpmitool := &ipmitool.Conn{Host: c.Auth.Host, Port: c.Auth.Port, User: c.Auth.User, Pass: c.Auth.Pass, Log: c.Logger} c.Registry.Register(ipmitool.ProviderName, ipmitool.ProviderProtocol, ipmitool.Features, nil, driverIpmitool) + + // setup https provider - we don't expect Build() to fail + driverHttps, _ := httpclient.Build() + c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, driverHttps) } // Open pass through to library function From 096dd807fbb70c52ea98efc653c0256922c9dc5f Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Feb 2021 17:59:38 +0100 Subject: [PATCH 04/42] lint fixes --- examples/main.go | 8 ++++---- go.mod | 3 ++- providers/asrockrack/asrockrack.go | 1 - providers/asrockrack/helpers.go | 6 ++---- providers/asrockrack/mock.go | 11 +++++------ 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/examples/main.go b/examples/main.go index 9850c328..16ac02e7 100644 --- a/examples/main.go +++ b/examples/main.go @@ -21,9 +21,9 @@ import ( // github.com/wojas/genericr: genericr func main() { - ip := "" - user := "user" - pass := "password" + ip := "10.230.148.171" + user := "admin" + pass := "admin" logger := logrus.New() logger.SetLevel(logrus.DebugLevel) @@ -37,7 +37,7 @@ func main() { printStatus(conn, logger) logger.Info("printing status with the default builtin logger") - os.Setenv("BMCLIB_LOG_LEVEL", "debug") + os.Setenv("BMCLIB_LOG_LEVEL", "gTtrace") conn, err = withDefaultBuiltinLogger(ip, user, pass) if err != nil { logger.Fatal(err) diff --git a/go.mod b/go.mod index 0130060a..8f35542c 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( bou.ke/monkey v1.0.2 github.com/bombsimon/logrusr v1.0.0 + github.com/davecgh/go-spew v1.1.1 github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-logr/logr v0.4.0 github.com/go-logr/zapr v0.4.0 // indirect @@ -31,7 +32,7 @@ require ( golang.org/x/net v0.0.0-20210119194325-5f4716e94777 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect golang.org/x/text v0.3.5 // indirect - gopkg.in/go-playground/assert.v1 v1.2.1 // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index d6e16d2b..b8b30c39 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -40,7 +40,6 @@ type ASRockRack struct { ip string username string password string - sid *http.Cookie loginSession *loginSession httpClient *http.Client fwInfo *firmwareInfo diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 0b00a4f9..59df802f 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -307,10 +307,8 @@ func (a *ASRockRack) queryHTTPS(URLendpoint, method string, payload []byte, head // add headers req.Header.Add("X-CSRFTOKEN", a.loginSession.CSRFToken) - if headers != nil { - for k, v := range headers { - req.Header.Add(k, v) - } + for k, v := range headers { + req.Header.Add(k, v) } // debug dump request diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go index e49a7c41..bac60a9f 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock.go @@ -23,7 +23,6 @@ var ( fwinfoResponse = []byte(`{ "BMC_fw_version": "0.01.00", "BIOS_fw_version": "L2.07B", "ME_fw_version": "5.1.3.78", "Micro_Code_version": "000000ca", "CPLD_version": "N\/A", "CM_version": "0.13.01", "BPB_version": "0.0.002.0", "Node_id": "2" }`) fwUploadResponse = []byte(`{"cc": 0}`) fwVerificationResponse = []byte(`[ { "id": 1, "current_image_name": "ast2500e", "current_image_version1": "0.01.00", "current_image_version2": "", "new_image_version": "0.03.00", "section_status": 0, "verification_status": 5 } ]`) - fwUpgradeResponse = []byte(`{"preserve_config":1,"preserve_network":0,"preserve_user":0,"flash_status":1}`) fwUpgradeProgress = []byte(`{ "id": 1, "action": "Flashing...", "progress": "__PERCENT__% done ", "state": 0 }`) ) @@ -92,7 +91,7 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) } fwUpgradeState.FirmwareVerified = true - w.Write(fwVerificationResponse) + _, _ = w.Write(fwVerificationResponse) case "/api/maintenance/reset": w.WriteHeader(http.StatusOK) // 5. flash progress @@ -108,7 +107,7 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { } resp := bytes.Replace(fwUpgradeProgress, []byte("__PERCENT__"), []byte(strconv.Itoa(fwUpgradeState.UpgradePercent)), 1) - w.Write(resp) + _, _ = w.Write(resp) } case "PUT": @@ -143,8 +142,8 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { fwUpgradeState.UpgradeInitiated = true // respond with request body b := new(bytes.Buffer) - b.ReadFrom(r.Body) - w.Write(b.Bytes()) + _, _ = b.ReadFrom(r.Body) + _, _ = w.Write(b.Bytes()) } case "POST": switch r.RequestURI { @@ -168,7 +167,7 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { } fwUpgradeState.FirmwareUploaded = true - w.Write(fwUploadResponse) + _, _ = w.Write(fwUploadResponse) } default: w.WriteHeader(http.StatusBadRequest) From 7307fa046b1c83d3b03550271bccd89a68de8256 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 08:40:53 +0100 Subject: [PATCH 05/42] asrockrack: firmware updates - Fix up bmclib v2 interface implementation - Firmware update method fixes - Firmware update test fixes --- bmc/firmware.go | 56 +++++++++++++++++++++- bmc/firmware_test.go | 2 +- client.go | 5 ++ providers/asrockrack/asrockrack.go | 64 +++++++++++++++---------- providers/asrockrack/asrockrack_test.go | 14 +++++- providers/asrockrack/helpers.go | 12 +++-- providers/asrockrack/mock.go | 12 ++++- 7 files changed, 130 insertions(+), 35 deletions(-) diff --git a/bmc/firmware.go b/bmc/firmware.go index d5d92c56..892c4992 100644 --- a/bmc/firmware.go +++ b/bmc/firmware.go @@ -10,7 +10,7 @@ import ( // BMCVersionGetter retrieves the current BMC firmware version information type BMCVersionGetter interface { - FirmwareVersionBMC(ctx context.Context) (version string, err error) + GetBMCVersion(ctx context.Context) (version string, err error) } // BMCFirmwareUpdater upgrades the BMC firmware @@ -28,7 +28,7 @@ Loop: break Loop default: if elem != nil { - version, vErr := elem.FirmwareVersionBMC(ctx) + version, vErr := elem.GetBMCVersion(ctx) if vErr != nil { err = multierror.Append(err, vErr) continue @@ -102,3 +102,55 @@ func UpdateBMCFirmwareFromInterfaces(ctx context.Context, updateFileName string, return UpdateBMCFirmware(ctx, updateFileName, bmcFirmwareUpdater) } + +// BIOSVersionGetter retrieves the current BIOS firmware version information +type BIOSVersionGetter interface { + GetBIOSVersion(ctx context.Context) (version string, err error) +} + +// BIOSFirmwareUpdater upgrades the BIOS firmware +type BIOSFirmwareUpdater interface { + FirmwareUpdateBIOS(ctx context.Context, fileName string) (err error) +} + +// GetBIOSVersion returns the BMC firmware version, trying all interface implementations passed in +func GetBIOSVersion(ctx context.Context, p []BIOSVersionGetter) (version string, err error) { +Loop: + for _, elem := range p { + select { + case <-ctx.Done(): + err = multierror.Append(err, ctx.Err()) + break Loop + default: + if elem != nil { + version, vErr := elem.GetBIOSVersion(ctx) + if vErr != nil { + err = multierror.Append(err, vErr) + continue + } + return version, nil + } + } + } + + return version, multierror.Append(err, errors.New("failed to get BMC version")) +} + +// GetBIOSVersionFromInterfaces pass through to library function +func GetBIOSVersionFromInterfaces(ctx context.Context, generic []interface{}) (version string, err error) { + biosVersionGetter := make([]BIOSVersionGetter, 0) + for _, elem := range generic { + switch p := elem.(type) { + case BIOSVersionGetter: + biosVersionGetter = append(biosVersionGetter, p) + default: + e := fmt.Sprintf("not a BIOSVersionGetter implementation: %T", p) + err = multierror.Append(err, errors.New(e)) + } + } + if len(biosVersionGetter) == 0 { + return version, multierror.Append(err, errors.New("no BIOSVersionGetter implementations found")) + } + + return GetBIOSVersion(ctx, biosVersionGetter) +} diff --git a/bmc/firmware_test.go b/bmc/firmware_test.go index cf91989e..b13d1025 100644 --- a/bmc/firmware_test.go +++ b/bmc/firmware_test.go @@ -15,7 +15,7 @@ type firmwareTester struct { MakeErrorOut bool } -func (f *firmwareTester) FirmwareVersionBMC(ctx context.Context) (version string, err error) { +func (f *firmwareTester) GetBMCVersion(ctx context.Context) (version string, err error) { if f.MakeErrorOut { return "", errors.New("failed to get BMC version") } diff --git a/client.go b/client.go index 9a57af02..450b3270 100644 --- a/client.go +++ b/client.go @@ -125,3 +125,8 @@ func (c *Client) SetBootDevice(ctx context.Context, bootDevice string, setPersis func (c *Client) ResetBMC(ctx context.Context, resetType string) (ok bool, err error) { return bmc.ResetBMCFromInterfaces(ctx, resetType, c.Registry.GetDriverInterfaces()) } + +// GetBMCVersion pass through library function +func (c *Client) GetBMCVersion(ctx context.Context) (version string, err error) { + return bmc.GetBMCVersionFromInterfaces(ctx, c.Registry.GetDriverInterfaces()) +} diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index b8b30c39..a4e3fd91 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "os" - "strings" "time" "github.com/bmc-toolbox/bmclib/internal/httpclient" @@ -22,7 +21,7 @@ const ( // ProviderName for the provider implementation ProviderName = "asrockrack" // ProviderProtocol for the provider implementation - ProviderProtocol = "https" + ProviderProtocol = "vendorapi" ) var ( @@ -37,18 +36,19 @@ var ( // ASRockRack holds the status and properties of a connection to a asrockrack bmc type ASRockRack struct { - ip string - username string - password string - loginSession *loginSession - httpClient *http.Client - fwInfo *firmwareInfo - flashModeSet bool - ctx context.Context - log logr.Logger + ip string + username string + password string + loginSession *loginSession + httpClient *http.Client + fwInfo *firmwareInfo + resetRequired bool + bMCFirmwareUpdated bool + ctx context.Context + log logr.Logger } -// New returns a new SupermicroX instance ready to be used +// New returns a new ASRockRack instance ready to be used func New(ctx context.Context, ip string, username string, password string, log logr.Logger) (*ASRockRack, error) { client, err := httpclient.Build() @@ -89,8 +89,17 @@ func (a *ASRockRack) Close(ctx context.Context) (err error) { return nil } +// CheckCredentials verify whether the credentials are valid or not +func (a *ASRockRack) CheckCredentials() (err error) { + err = a.httpsLogin() + if err != nil { + return err + } + return err +} + // BiosVersion returns the BIOS version from the BMC -func (a *ASRockRack) BiosVersion() (string, error) { +func (a *ASRockRack) GetBIOSVersion(ctx context.Context) (string, error) { var err error if a.fwInfo == nil { @@ -104,7 +113,7 @@ func (a *ASRockRack) BiosVersion() (string, error) { } // BMCVersion returns the BMC version -func (a *ASRockRack) BMCVersion() (string, error) { +func (a *ASRockRack) GetBMCVersion(ctx context.Context) (string, error) { var err error if a.fwInfo == nil { @@ -120,11 +129,13 @@ func (a *ASRockRack) BMCVersion() (string, error) { // nolint: gocyclo // BMC firmware update is a multi step process // this method initiates the upgrade process and waits in a loop until the device has been upgraded -func (a *ASRockRack) FirmwareUpdateBMC(filePath string) error { +func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - // The BMC needs to be reset once set into flash mode defer func() { - if a.flashModeSet { + // The device needs to be reset to be removed from flash mode, + // this is required once setFlashMode() is invoked. + // The BMC resets itself once a firmware flash is successful or failed. + if a.resetRequired { a.log.V(1).Info("info", "resetting BMC, this takes a few minutes") err := a.reset() if err != nil { @@ -140,14 +151,14 @@ func (a *ASRockRack) FirmwareUpdateBMC(filePath string) error { } // 1. set the device to flash mode - prepares the flash - a.log.V(1).Info("info", "step 1/5 - setting device into flash mode.. this takes a minute", "filePath", filePath) + a.log.V(0).Info("info", "step 1/5 - setting device into flash mode.. this takes a minute", "filePath", filePath) err = a.setFlashMode() if err != nil { return fmt.Errorf("failed in step 1/5 - set device in flash mode: " + err.Error()) } // 2. upload firmware image file - a.log.V(1).Info("info", "step 2/5 - uploading firmware image", "filePath", filePath) + a.log.V(0).Info("info", "step 2/5 - uploading firmware image", "filePath", filePath) err = a.uploadFirmware(filePath) if err != nil { return fmt.Errorf("failed in step 2/5 - upload firmware image: " + err.Error()) @@ -155,21 +166,21 @@ func (a *ASRockRack) FirmwareUpdateBMC(filePath string) error { // 3. BMC to verify the uploaded file err = a.verifyUploadedFirmware() - a.log.V(1).Info("info", "step 3/5 - verify uploaded firmware", "filePath", filePath) + a.log.V(0).Info("info", "step 3/5 - verify uploaded firmware", "filePath", filePath) if err != nil { return fmt.Errorf("failed in step 3/5 - verify uploaded firmware: " + err.Error()) } startTS := time.Now() // 4. Run the upgrade - preserving current config - a.log.V(1).Info("info", "step 4/5 - run the upgrade, preserving current configuration", "filePath", filePath) + a.log.V(0).Info("info", "step 4/5 - run the upgrade, preserving current configuration", "filePath", filePath) err = a.upgradeBMC() if err != nil { return fmt.Errorf("failed in step 4/5 - verify uploaded firmware: " + err.Error()) } // progress check interval - progressT := time.NewTicker(10 * time.Second).C + progressT := time.NewTicker(2 * time.Second).C // timeout interval timeoutT := time.NewTicker(30 * time.Minute).C maxErrors := 20 @@ -183,13 +194,16 @@ func (a *ASRockRack) FirmwareUpdateBMC(filePath string) error { p, err := a.flashProgress() if err != nil { errorsCount++ - a.log.Error(err, "step 5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + a.log.V(0).Info("error", "step 5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + continue } - a.log.V(1).Info("info", "step 5/5 - flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(0).Info("info", "step 5/5 - flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) // all done! - if strings.Contains(p.Progress, "100% done") { + if p.State == 2 { + a.log.V(0).Info("info", "step 5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.resetRequired = false return nil } case <-timeoutT: diff --git a/providers/asrockrack/asrockrack_test.go b/providers/asrockrack/asrockrack_test.go index 52c48f0a..90096dca 100644 --- a/providers/asrockrack/asrockrack_test.go +++ b/providers/asrockrack/asrockrack_test.go @@ -1,12 +1,24 @@ package asrockrack import ( + "context" "os" "testing" "gopkg.in/go-playground/assert.v1" ) +//func TestBmcInterface(t *testing.T) { + +//c, err := New(context.TODO(), ip, username, password, logrusr.NewLogger(testLog)) +//if err != nil { +//return c, err +//} +//_ = devices.Bmc(c) +//_ = devices.Configure(c) +//_ = devices.Firmware(c) +//} + func Test_httpLogin(t *testing.T) { err := aClient.httpsLogin() @@ -71,7 +83,7 @@ func Test_FirwmwareUpdateBMC(t *testing.T) { } defer os.Remove(upgradeFile) - err = aClient.FirmwareUpdateBMC(upgradeFile) + err = aClient.FirmwareUpdateBMC(context.TODO(), upgradeFile) if err != nil { t.Errorf(err.Error()) } diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 59df802f..5b67579a 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -39,10 +39,10 @@ type firmwareInfo struct { // Payload to preseve config when updating the BMC firmware type preserveConfig struct { - PreserveConfig int `json:"preserve_config,omitempty"` + FlashStatus int `json:"flash_status"` // 1 = full firmware flash, 2 = section based flash, 3 - version compare flash + PreserveConfig int `json:"preserve_config"` PreserveNetwork int `json:"preserve_network"` PreserveUser int `json:"preserve_user"` - FlashStatus int `json:"flash_status"` // 1 = full firmware flash, 2 = section based flash, 3 - version compare flash } // Firmware flash progress @@ -56,6 +56,8 @@ type upgradeProgress struct { } // 1 Set BMC to flash mode and prepare flash area +// at this point all logged in sessions are terminated +// and no logins are permitted func (a *ASRockRack) setFlashMode() error { endpoint := "api/maintenance/flash" @@ -69,7 +71,7 @@ func (a *ASRockRack) setFlashMode() error { return fmt.Errorf("Non 200 response: %d", statusCode) } - a.flashModeSet = true + a.resetRequired = true return nil } @@ -151,7 +153,8 @@ func (a *ASRockRack) upgradeBMC() error { return err } - _, statusCode, err := a.queryHTTPS(endpoint, "PUT", payload, nil) + headers := map[string]string{"Content-Type": "application/json"} + _, statusCode, err := a.queryHTTPS(endpoint, "PUT", payload, headers) if err != nil { return err } @@ -186,6 +189,7 @@ func (a *ASRockRack) reset() error { func (a *ASRockRack) flashProgress() (*upgradeProgress, error) { endpoint := "api/maintenance/firmware/flash-progress" + resp, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) if err != nil { return nil, err diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go index bac60a9f..e3f0d528 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock.go @@ -23,7 +23,7 @@ var ( fwinfoResponse = []byte(`{ "BMC_fw_version": "0.01.00", "BIOS_fw_version": "L2.07B", "ME_fw_version": "5.1.3.78", "Micro_Code_version": "000000ca", "CPLD_version": "N\/A", "CM_version": "0.13.01", "BPB_version": "0.0.002.0", "Node_id": "2" }`) fwUploadResponse = []byte(`{"cc": 0}`) fwVerificationResponse = []byte(`[ { "id": 1, "current_image_name": "ast2500e", "current_image_version1": "0.01.00", "current_image_version2": "", "new_image_version": "0.03.00", "section_status": 0, "verification_status": 5 } ]`) - fwUpgradeProgress = []byte(`{ "id": 1, "action": "Flashing...", "progress": "__PERCENT__% done ", "state": 0 }`) + fwUpgradeProgress = []byte(`{ "id": 1, "action": "Flashing...", "progress": "__PERCENT__% done ", "state": __STATE__ }`) ) // setup test BMC @@ -96,17 +96,21 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) // 5. flash progress case "/api/maintenance/firmware/flash-progress": + spew.Dump(r.Cookies()) if !fwUpgradeState.UpgradeInitiated { w.WriteHeader(http.StatusBadRequest) } + resp := fwUpgradeProgress if fwUpgradeState.UpgradePercent >= 100 { fwUpgradeState.UpgradePercent = 100 + resp = bytes.Replace(fwUpgradeProgress, []byte("__STATE__"), []byte(strconv.Itoa(2)), 1) } else { fwUpgradeState.UpgradePercent += 50 } - resp := bytes.Replace(fwUpgradeProgress, []byte("__PERCENT__"), []byte(strconv.Itoa(fwUpgradeState.UpgradePercent)), 1) + resp = bytes.Replace(fwUpgradeProgress, []byte("__PERCENT__"), []byte(strconv.Itoa(fwUpgradeState.UpgradePercent)), 1) + _, _ = w.Write(resp) } case "PUT": @@ -122,6 +126,10 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) } + if r.Header.Get("Content-Type") != "application/json" { + w.WriteHeader(http.StatusBadRequest) + } + p := &preserveConfig{} err := json.NewDecoder(r.Body).Decode(&p) if err != nil { From 9ba38e6d3baf8be6b59674549c25238425185500 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 08:43:50 +0100 Subject: [PATCH 06/42] asrockrack: implement bmclib (older) v0 interface methods for compatibility --- providers/asrockrack/implementations.go | 234 ++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 providers/asrockrack/implementations.go diff --git a/providers/asrockrack/implementations.go b/providers/asrockrack/implementations.go new file mode 100644 index 00000000..37b66809 --- /dev/null +++ b/providers/asrockrack/implementations.go @@ -0,0 +1,234 @@ +package asrockrack + +import ( + "crypto/x509" + + "github.com/bmc-toolbox/bmclib/cfgresources" + "github.com/bmc-toolbox/bmclib/devices" +) + +// ApplyCfg implements the Bmc interface +func (a *ASRockRack) ApplyCfg(config *cfgresources.ResourcesConfig) (err error) { + return nil +} + +// BiosVersion implements the Bmc interface +func (a *ASRockRack) BiosVersion() (string, error) { + return "", nil +} + +// HardwareType implements the Bmc interface +func (a *ASRockRack) HardwareType() string { + return "" +} + +// Version implements the Bmc interface +func (a *ASRockRack) Version() (string, error) { + return "", nil +} + +// CPU implements the Bmc interface +func (a *ASRockRack) CPU() (string, int, int, int, error) { + return "", 0, 0, 0, nil +} + +// Disks implements the Bmc interface +func (a *ASRockRack) Disks() ([]*devices.Disk, error) { + return make([]*devices.Disk, 0), nil +} + +// IsBlade implements the Bmc interface +func (a *ASRockRack) IsBlade() (bool, error) { + return false, nil +} + +// License implements the Bmc interface +func (a *ASRockRack) License() (string, string, error) { + return "", "", nil +} + +// Memory implements the Bmc interface +func (a *ASRockRack) Memory() (int, error) { + return 0, nil +} + +// Model implements the Bmc interface +func (a *ASRockRack) Model() (string, error) { + return "", nil +} + +// Name implements the Bmc interface +func (a *ASRockRack) Name() (string, error) { + return "", nil +} + +// Nics implements the Bmc interface +func (a *ASRockRack) Nics() ([]*devices.Nic, error) { + return make([]*devices.Nic, 0), nil +} + +// PowerKw implements the Bmc interface +func (a *ASRockRack) PowerKw() (float64, error) { + return 0.0, nil +} + +// PowerState implements the Bmc interface +func (a *ASRockRack) PowerState() (string, error) { + return "", nil +} + +// PowerCycleBmc implements the Bmc interface +func (a *ASRockRack) PowerCycleBmc() (status bool, err error) { + return false, nil +} + +// PowerCycle implements the Bmc interface +func (a *ASRockRack) PowerCycle() (status bool, err error) { + return false, nil +} + +// PowerOff implements the Bmc interface +func (a *ASRockRack) PowerOff() (status bool, err error) { + return false, nil +} + +// PowerOn implements the Bmc interface +func (a *ASRockRack) PowerOn() (status bool, err error) { + return false, nil +} + +// PxeOnce implements the Bmc interface +func (a *ASRockRack) PxeOnce() (status bool, err error) { + return false, nil +} + +// Serial implements the Bmc interface +func (a *ASRockRack) Serial() (string, error) { + return "", nil +} + +// ChassisSerial implements the Bmc interface +func (a *ASRockRack) ChassisSerial() (string, error) { + return "", nil +} + +// Status implements the Bmc interface +func (a *ASRockRack) Status() (string, error) { + return "", nil +} + +// TempC implements the Bmc interface +func (a *ASRockRack) TempC() (int, error) { + return 0, nil +} + +// Vendor implements the Bmc interface +func (a *ASRockRack) Vendor() string { + return "" +} + +// Screenshot implements the Bmc interface +func (a *ASRockRack) Screenshot() ([]byte, string, error) { + return []byte{}, "", nil +} + +// ServerSnapshot implements the Bmc interface +func (a *ASRockRack) ServerSnapshot() (interface{}, error) { + return nil, nil +} + +// UpdateCredentials implements the Bmc interface +func (a *ASRockRack) UpdateCredentials(string, string) { +} + +// Slot implements the Bmc interface +func (a *ASRockRack) Slot() (int, error) { + return -1, nil +} + +// UpdateFirmware implements the Bmc inteface +func (a *ASRockRack) UpdateFirmware(string, string) (b bool, e error) { + return b, e +} + +// IsOn implements the Bmc interface +func (a *ASRockRack) IsOn() (status bool, err error) { + return false, nil +} + +// Resources returns a slice of supported resources and +// the order they are to be applied in. +func (a *ASRockRack) Resources() []string { + return []string{ + "user", + "syslog", + "ntp", + "ldap", + "ldap_group", + "network", + } +} + +// Power implemented the Configure interface +func (a *ASRockRack) Power(cfg *cfgresources.Power) (err error) { + return err +} + +// User method implements the Configure interface +func (a *ASRockRack) User(cfg []*cfgresources.User) error { + return nil +} + +// Syslog method implements the Configure interface +func (a *ASRockRack) Syslog(cfg *cfgresources.Syslog) error { + return nil +} + +// Ntp method implements the Configure interface +func (a *ASRockRack) Ntp(cfg *cfgresources.Ntp) error { + return nil +} + +// Ldap method implements the Configure interface +func (a *ASRockRack) Ldap(cfg *cfgresources.Ldap) error { + return nil +} + +// LdapGroup method implements the Configure interface +func (a *ASRockRack) LdapGroup(cfgGroup []*cfgresources.LdapGroup, cfgLdap *cfgresources.Ldap) error { + return nil +} + +// Network method implements the Configure interface +func (a *ASRockRack) Network(cfg *cfgresources.Network) (bool, error) { + return false, nil +} + +// SetLicense implements the Configure interface +func (a *ASRockRack) SetLicense(*cfgresources.License) error { + return nil +} + +// Bios method implements the Configure interface +func (a *ASRockRack) Bios(cfg *cfgresources.Bios) error { + return nil +} + +// GenerateCSR generates a CSR request on the BMC. +// GenerateCSR implements the Configure interface. +func (a *ASRockRack) GenerateCSR(cert *cfgresources.HTTPSCertAttributes) ([]byte, error) { + return []byte{}, nil +} + +// UploadHTTPSCert uploads the given CRT cert, +// UploadHTTPSCert implements the Configure interface. +func (a *ASRockRack) UploadHTTPSCert(cert []byte, certFileName string, key []byte, keyFileName string) (bool, error) { + return false, nil +} + +// CurrentHTTPSCert returns the current x509 certficates configured on the BMC +// The bool value returned indicates if the BMC supports CSR generation. +// CurrentHTTPSCert implements the Configure interface. +func (a *ASRockRack) CurrentHTTPSCert() ([]*x509.Certificate, bool, error) { + return nil, false, nil +} From 3d049a55981130f9e5c1655d7a4a314e219b75ca Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 10:08:36 +0100 Subject: [PATCH 07/42] asrockrack: update info logging non-even logr k/v fields results in empty logging lines with just the prefix 'INFO' being logged, here we ensure all values are in pairs. --- providers/asrockrack/asrockrack.go | 16 ++++++++-------- providers/asrockrack/helpers.go | 2 +- providers/asrockrack/mock.go | 3 +-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index a4e3fd91..35bb2c78 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -151,14 +151,14 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err } // 1. set the device to flash mode - prepares the flash - a.log.V(0).Info("info", "step 1/5 - setting device into flash mode.. this takes a minute", "filePath", filePath) + a.log.V(0).Info("info", "step", "1/5 - setting device into flash mode.. this takes a minute") err = a.setFlashMode() if err != nil { return fmt.Errorf("failed in step 1/5 - set device in flash mode: " + err.Error()) } // 2. upload firmware image file - a.log.V(0).Info("info", "step 2/5 - uploading firmware image", "filePath", filePath) + a.log.V(0).Info("info", "step", "2/5 uploading firmware image", "filePath", filePath) err = a.uploadFirmware(filePath) if err != nil { return fmt.Errorf("failed in step 2/5 - upload firmware image: " + err.Error()) @@ -166,14 +166,14 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err // 3. BMC to verify the uploaded file err = a.verifyUploadedFirmware() - a.log.V(0).Info("info", "step 3/5 - verify uploaded firmware", "filePath", filePath) + a.log.V(0).Info("info", "step", "3/5 - bmc to verify uploaded firmware") if err != nil { return fmt.Errorf("failed in step 3/5 - verify uploaded firmware: " + err.Error()) } startTS := time.Now() // 4. Run the upgrade - preserving current config - a.log.V(0).Info("info", "step 4/5 - run the upgrade, preserving current configuration", "filePath", filePath) + a.log.V(0).Info("info", "step 4/5", "run the upgrade, preserving current configuration") err = a.upgradeBMC() if err != nil { return fmt.Errorf("failed in step 4/5 - verify uploaded firmware: " + err.Error()) @@ -194,15 +194,16 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err p, err := a.flashProgress() if err != nil { errorsCount++ - a.log.V(0).Info("error", "step 5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + a.log.V(0).Error(err, "step", "5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) continue } - a.log.V(0).Info("info", "step 5/5 - flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(0).Info("info", "step", "5/5 - check flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) // all done! if p.State == 2 { - a.log.V(0).Info("info", "step 5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(0).Info("info", "step", "5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + // The BMC resets by itself after a successful flash a.resetRequired = false return nil } @@ -210,7 +211,6 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err return fmt.Errorf("timeout in step 5/5 - flash progress, error count: %d, elapsed time: %s", errorsCount, time.Since(startTS).String()) } } - } func (a *ASRockRack) FirmwareUpdateBIOS(filePath string) error { diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 5b67579a..774d407e 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -282,7 +282,7 @@ func (a *ASRockRack) httpsLogout() error { } if statusCode != 200 { - return fmt.Errorf("Error logging out: " + err.Error()) + return fmt.Errorf("Non 200 response at https logout: %d", statusCode) } return nil diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go index e3f0d528..35c3736e 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock.go @@ -51,7 +51,7 @@ func init() { bmcURL, _ = url.Parse(server.URL) l := logrus.New() - l.Level = logrus.InfoLevel + l.Level = logrus.DebugLevel // setup bmc client tLog := logrusr.NewLogger(l) aClient, err = New(context.TODO(), bmcURL.Host, "foo", "bar", tLog) @@ -96,7 +96,6 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) // 5. flash progress case "/api/maintenance/firmware/flash-progress": - spew.Dump(r.Cookies()) if !fwUpgradeState.UpgradeInitiated { w.WriteHeader(http.StatusBadRequest) } From 04bd8fd0a794800b38c9f308ee61522bd6db05da Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 10:09:59 +0100 Subject: [PATCH 08/42] asrockrack: add skipLogout bool to ignore Close() invocation requests after a firmware flash, since the BMC is resetting at that point --- providers/asrockrack/asrockrack.go | 9 ++++++++- providers/asrockrack/mock.go | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index 35bb2c78..3019729d 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -42,7 +42,8 @@ type ASRockRack struct { loginSession *loginSession httpClient *http.Client fwInfo *firmwareInfo - resetRequired bool + resetRequired bool // Indicates if the BMC requires a reset + skipLogout bool // A Close() / httpsLogout() request is ignored if the BMC was just flashed - since the sessions are terminated either way bMCFirmwareUpdated bool ctx context.Context log logr.Logger @@ -81,6 +82,10 @@ func (a *ASRockRack) Open(ctx context.Context) (err error) { // Close a connection to a BMC func (a *ASRockRack) Close(ctx context.Context) (err error) { + if a.skipLogout { + return nil + } + err = a.httpsLogout() if err != nil { return err @@ -205,6 +210,8 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err a.log.V(0).Info("info", "step", "5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) // The BMC resets by itself after a successful flash a.resetRequired = false + // HTTP sessions are terminated once the BMC resets after an upgrade + a.skipLogout = true return nil } case <-timeoutT: diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go index 35c3736e..4293c2be 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock.go @@ -103,13 +103,15 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { resp := fwUpgradeProgress if fwUpgradeState.UpgradePercent >= 100 { fwUpgradeState.UpgradePercent = 100 + // state: 2 indicates firmware flash complete resp = bytes.Replace(fwUpgradeProgress, []byte("__STATE__"), []byte(strconv.Itoa(2)), 1) } else { + // state: 0 indicates firmware flash in progress + resp = bytes.Replace(fwUpgradeProgress, []byte("__STATE__"), []byte(strconv.Itoa(0)), 1) fwUpgradeState.UpgradePercent += 50 } - resp = bytes.Replace(fwUpgradeProgress, []byte("__PERCENT__"), []byte(strconv.Itoa(fwUpgradeState.UpgradePercent)), 1) - + resp = bytes.Replace(resp, []byte("__PERCENT__"), []byte(strconv.Itoa(fwUpgradeState.UpgradePercent)), 1) _, _ = w.Write(resp) } case "PUT": From 08f6ec431a98837f1ef46770fa3163b7d0e8cb5f Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 10:21:19 +0100 Subject: [PATCH 09/42] discover: fix ASRR probe test and rename file for consistency --- discover/{discovery_test.go => discover_test.go} | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) rename discover/{discovery_test.go => discover_test.go} (98%) diff --git a/discover/discovery_test.go b/discover/discover_test.go similarity index 98% rename from discover/discovery_test.go rename to discover/discover_test.go index bf4806c1..0ab24b42 100644 --- a/discover/discovery_test.go +++ b/discover/discover_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/dell/idrac8" "github.com/bmc-toolbox/bmclib/providers/dell/idrac9" "github.com/bmc-toolbox/bmclib/providers/hp/c7000" @@ -116,7 +117,7 @@ func TestProbes(t *testing.T) { { name: "ASRockRack", wantHint: ProbeASRockRack, - wantType: nil, + wantType: (*asrockrack.ASRockRack)(nil), }, } @@ -183,10 +184,12 @@ var ( ProbeM1000e, ProbeQuanta, ProbeHpCl100, + ProbeASRockRack, } _answers = map[string]map[string][]byte{ - "IDrac8": {"/session": []byte(`{"aimGetProp" : {"hostname" :"machine","gui_str_title_bar" :"","OEMHostName" :"machine.example.com","fwVersion" :"2.50.33","sysDesc" :"PowerEdge M630","status" : "OK"}}`)}, + "ASRockRack": {"/": []byte(`ASRockRack`)}, + "IDrac8": {"/session": []byte(`{"aimGetProp" : {"hostname" :"machine","gui_str_title_bar" :"","OEMHostName" :"machine.example.com","fwVersion" :"2.50.33","sysDesc" :"PowerEdge M630","status" : "OK"}}`)}, "IDrac9": { "/sysmgmt/2015/bmc/info": []byte(`{"Attributes":{"ADEnabled":"Disabled","BuildVersion":"37","FwVer":"3.15.15.15","GUITitleBar":"spare-H16Z4M2","IsOEMBranded":"0","License":"Enterprise","SSOEnabled":"Disabled","SecurityPolicyMessage":"By accessing this computer, you confirm that such access complies with your organization's security policy.","ServerGen":"14G","SrvPrcName":"NULL","SystemLockdown":"Disabled","SystemModelName":"PowerEdge M640","TFAEnabled":"Disabled","iDRACName":"spare-H16Z4M2"}}`), "/sysmgmt/2015/bmc/session": []byte(`{"status": "good", "authResult": 7, "forwardUrl": "something", "errorMsg": "none"}`), From 4e6ac594b14714a31a0b90017ad60795289753e0 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 12:04:39 +0100 Subject: [PATCH 10/42] asrockrack: fix minor lint issues --- providers/asrockrack/asrockrack.go | 21 ++++++++++----------- providers/asrockrack/mock.go | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index 3019729d..6949f696 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -36,17 +36,16 @@ var ( // ASRockRack holds the status and properties of a connection to a asrockrack bmc type ASRockRack struct { - ip string - username string - password string - loginSession *loginSession - httpClient *http.Client - fwInfo *firmwareInfo - resetRequired bool // Indicates if the BMC requires a reset - skipLogout bool // A Close() / httpsLogout() request is ignored if the BMC was just flashed - since the sessions are terminated either way - bMCFirmwareUpdated bool - ctx context.Context - log logr.Logger + ip string + username string + password string + loginSession *loginSession + httpClient *http.Client + fwInfo *firmwareInfo + resetRequired bool // Indicates if the BMC requires a reset + skipLogout bool // A Close() / httpsLogout() request is ignored if the BMC was just flashed - since the sessions are terminated either way + ctx context.Context + log logr.Logger } // New returns a new ASRockRack instance ready to be used diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go index 4293c2be..59c964b4 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock.go @@ -104,10 +104,10 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { if fwUpgradeState.UpgradePercent >= 100 { fwUpgradeState.UpgradePercent = 100 // state: 2 indicates firmware flash complete - resp = bytes.Replace(fwUpgradeProgress, []byte("__STATE__"), []byte(strconv.Itoa(2)), 1) + resp = bytes.Replace(resp, []byte("__STATE__"), []byte(strconv.Itoa(2)), 1) } else { // state: 0 indicates firmware flash in progress - resp = bytes.Replace(fwUpgradeProgress, []byte("__STATE__"), []byte(strconv.Itoa(0)), 1) + resp = bytes.Replace(resp, []byte("__STATE__"), []byte(strconv.Itoa(0)), 1) fwUpgradeState.UpgradePercent += 50 } From acb54b4317fee994b743a184b43d6b80482e2dbc Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 12:05:12 +0100 Subject: [PATCH 11/42] providers: implement stub Firmware interface methods --- devices/interfaces.go | 9 +++++++++ providers/dell/idrac8/idrac8.go | 15 +++++++++++++++ providers/dell/idrac9/idrac9.go | 15 +++++++++++++++ providers/dummy/ibmc/ibmc.go | 16 ++++++++++++++++ providers/hp/ilo/ilo.go | 15 +++++++++++++++ providers/supermicro/supermicrox/supermicrox.go | 15 +++++++++++++++ .../supermicro/supermicrox11/supermicrox.go | 15 +++++++++++++++ .../supermicro/supermicrox11/supermicrox_test.go | 1 + 8 files changed, 101 insertions(+) diff --git a/devices/interfaces.go b/devices/interfaces.go index 26ceb0a7..b628dd8c 100644 --- a/devices/interfaces.go +++ b/devices/interfaces.go @@ -15,6 +15,9 @@ type Bmc interface { // BmcCollection interface BmcCollection + // Firmware getter/updater interface + Firmware + CheckCredentials() error Close(context.Context) error PowerOn() (bool, error) // PowerSetter @@ -134,3 +137,9 @@ type Configure interface { GenerateCSR(*cfgresources.HTTPSCertAttributes) ([]byte, error) UploadHTTPSCert([]byte, string, []byte, string) (bool, error) } + +type Firmware interface { + GetBIOSVersion(context.Context) (version string, err error) + GetBMCVersion(context.Context) (version string, err error) + FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) +} diff --git a/providers/dell/idrac8/idrac8.go b/providers/dell/idrac8/idrac8.go index c894c530..04af8dec 100644 --- a/providers/dell/idrac8/idrac8.go +++ b/providers/dell/idrac8/idrac8.go @@ -882,3 +882,18 @@ func (i *IDrac8) UpdateCredentials(username string, password string) { i.username = username i.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *IDrac8) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *IDrac8) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *IDrac8) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/dell/idrac9/idrac9.go b/providers/dell/idrac9/idrac9.go index 80999cfa..fc3fc9a5 100644 --- a/providers/dell/idrac9/idrac9.go +++ b/providers/dell/idrac9/idrac9.go @@ -925,3 +925,18 @@ func (i *IDrac9) UpdateCredentials(username string, password string) { i.username = username i.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *IDrac9) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *IDrac9) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *IDrac9) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/dummy/ibmc/ibmc.go b/providers/dummy/ibmc/ibmc.go index 2a069432..9225b033 100644 --- a/providers/dummy/ibmc/ibmc.go +++ b/providers/dummy/ibmc/ibmc.go @@ -5,6 +5,7 @@ import ( "github.com/bmc-toolbox/bmclib/cfgresources" "github.com/bmc-toolbox/bmclib/devices" + "github.com/bmc-toolbox/bmclib/errors" ) // The ibmc model is part of the dummy vendor, @@ -186,3 +187,18 @@ func (i *Ibmc) UpdateFirmware(string, string) (b bool, e error) { func (i *Ibmc) IsOn() (status bool, err error) { return false, nil } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *Ibmc) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *Ibmc) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *Ibmc) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/hp/ilo/ilo.go b/providers/hp/ilo/ilo.go index b904041f..12e53a4a 100644 --- a/providers/hp/ilo/ilo.go +++ b/providers/hp/ilo/ilo.go @@ -843,3 +843,18 @@ func (i *Ilo) UpdateCredentials(username string, password string) { i.username = username i.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *Ilo) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *Ilo) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *Ilo) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/supermicro/supermicrox/supermicrox.go b/providers/supermicro/supermicrox/supermicrox.go index 2b871274..5194cb12 100644 --- a/providers/supermicro/supermicrox/supermicrox.go +++ b/providers/supermicro/supermicrox/supermicrox.go @@ -721,3 +721,18 @@ func (s *SupermicroX) UpdateCredentials(username string, password string) { s.username = username s.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (s *SupermicroX) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (s *SupermicroX) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (s *SupermicroX) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/supermicro/supermicrox11/supermicrox.go b/providers/supermicro/supermicrox11/supermicrox.go index dc44674d..0ecbe543 100644 --- a/providers/supermicro/supermicrox11/supermicrox.go +++ b/providers/supermicro/supermicrox11/supermicrox.go @@ -724,3 +724,18 @@ func (s *SupermicroX) UpdateCredentials(username string, password string) { s.username = username s.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (s *SupermicroX) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (s *SupermicroX) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (s *SupermicroX) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/supermicro/supermicrox11/supermicrox_test.go b/providers/supermicro/supermicrox11/supermicrox_test.go index eeb7094c..75d3b042 100644 --- a/providers/supermicro/supermicrox11/supermicrox_test.go +++ b/providers/supermicro/supermicrox11/supermicrox_test.go @@ -597,6 +597,7 @@ func TestIBmcInterface(t *testing.T) { } _ = devices.Bmc(bmc) _ = devices.Configure(bmc) + _ = devices.Firmware(bmc) tearDown() } From 6b410524aa3fe296491994a3f797f9c55b5d905a Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 12 Feb 2021 12:14:32 +0100 Subject: [PATCH 12/42] bmc/firmware: Add BIOS firmware interface methods --- bmc/firmware.go | 67 ++++++++++--- bmc/firmware_test.go | 230 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 285 insertions(+), 12 deletions(-) diff --git a/bmc/firmware.go b/bmc/firmware.go index 892c4992..b7b198d9 100644 --- a/bmc/firmware.go +++ b/bmc/firmware.go @@ -18,6 +18,16 @@ type BMCFirmwareUpdater interface { FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) } +// BIOSVersionGetter retrieves the current BIOS firmware version information +type BIOSVersionGetter interface { + GetBIOSVersion(ctx context.Context) (version string, err error) +} + +// BIOSFirmwareUpdater upgrades the BIOS firmware +type BIOSFirmwareUpdater interface { + FirmwareUpdateBIOS(ctx context.Context, fileName string) (err error) +} + // GetBMCVersion returns the BMC firmware version, trying all interface implementations passed in func GetBMCVersion(ctx context.Context, p []BMCVersionGetter) (version string, err error) { Loop: @@ -84,7 +94,7 @@ Loop: } -// GetBMCVersionFromInterfaces pass through to library function +// UpdateBMCFirmwareFromInterfaces pass through to library function func UpdateBMCFirmwareFromInterfaces(ctx context.Context, updateFileName string, generic []interface{}) (err error) { bmcFirmwareUpdater := make([]BMCFirmwareUpdater, 0) for _, elem := range generic { @@ -103,16 +113,6 @@ func UpdateBMCFirmwareFromInterfaces(ctx context.Context, updateFileName string, return UpdateBMCFirmware(ctx, updateFileName, bmcFirmwareUpdater) } -// BIOSVersionGetter retrieves the current BIOS firmware version information -type BIOSVersionGetter interface { - GetBIOSVersion(ctx context.Context) (version string, err error) -} - -// BIOSFirmwareUpdater upgrades the BIOS firmware -type BIOSFirmwareUpdater interface { - FirmwareUpdateBIOS(ctx context.Context, fileName string) (err error) -} - // GetBIOSVersion returns the BMC firmware version, trying all interface implementations passed in func GetBIOSVersion(ctx context.Context, p []BIOSVersionGetter) (version string, err error) { Loop: @@ -133,7 +133,7 @@ Loop: } } - return version, multierror.Append(err, errors.New("failed to get BMC version")) + return version, multierror.Append(err, errors.New("failed to get BIOS version")) } // GetBIOSVersionFromInterfaces pass through to library function @@ -154,3 +154,46 @@ func GetBIOSVersionFromInterfaces(ctx context.Context, generic []interface{}) (v return GetBIOSVersion(ctx, biosVersionGetter) } + +// UpdateBIOSFirmware upgrades the BIOS firmware, trying all interface implementations passed ini +func UpdateBIOSFirmware(ctx context.Context, updateFileName string, p []BIOSFirmwareUpdater) (err error) { +Loop: + for _, elem := range p { + select { + case <-ctx.Done(): + err = multierror.Append(err, ctx.Err()) + break Loop + default: + if elem != nil { + uErr := elem.FirmwareUpdateBIOS(ctx, updateFileName) + if uErr != nil { + err = multierror.Append(err, uErr) + continue + } + return nil + } + } + } + + return multierror.Append(err, errors.New("failed to update BIOS firmware")) + +} + +// GetBMCVersionFromInterfaces pass through to library function +func UpdateBIOSFirmwareFromInterfaces(ctx context.Context, updateFileName string, generic []interface{}) (err error) { + biosFirmwareUpdater := make([]BIOSFirmwareUpdater, 0) + for _, elem := range generic { + switch p := elem.(type) { + case BIOSFirmwareUpdater: + biosFirmwareUpdater = append(biosFirmwareUpdater, p) + default: + e := fmt.Sprintf("not a BIOSFirmwareUpdater implementation: %T", p) + err = multierror.Append(err, errors.New(e)) + } + } + if len(biosFirmwareUpdater) == 0 { + return multierror.Append(err, errors.New("no BIOSFirmwareUpdater implementations found")) + } + + return UpdateBIOSFirmware(ctx, updateFileName, biosFirmwareUpdater) +} diff --git a/bmc/firmware_test.go b/bmc/firmware_test.go index b13d1025..54f2b579 100644 --- a/bmc/firmware_test.go +++ b/bmc/firmware_test.go @@ -33,6 +33,23 @@ func (f *firmwareTester) FirmwareUpdateBMC(ctx context.Context, fileName string) return nil } +func (f *firmwareTester) FirmwareUpdateBIOS(ctx context.Context, fileName string) (err error) { + if f.MakeErrorOut { + return errors.New("failed update") + } + return nil +} + +func (f *firmwareTester) GetBIOSVersion(ctx context.Context) (version string, err error) { + if f.MakeErrorOut { + return "", errors.New("failed to get BIOS version") + } + if f.MakeNotOK { + return "", nil + } + return "1.44.7", nil +} + func TestGetBMCVersion(t *testing.T) { testCases := []struct { name string @@ -115,3 +132,216 @@ func TestGetBMCVersionFromInterfaces(t *testing.T) { }) } } + +func TestUpdateBMCFirmware(t *testing.T) { + testCases := []struct { + name string + makeFail bool + err error + ctxTimeout time.Duration + }{ + {name: "success", err: nil}, + {name: "failure", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("failed update"), errors.New("failed to update BMC firmware")}}}, + {name: "fail context timeout", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded"), errors.New("failed to update BMC firmware")}}, ctxTimeout: time.Nanosecond * 1}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + testImplementation := firmwareTester{MakeErrorOut: tc.makeFail} + if tc.ctxTimeout == 0 { + tc.ctxTimeout = time.Second * 3 + } + ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout) + defer cancel() + err := UpdateBMCFirmware(ctx, "foo", []BMCFirmwareUpdater{&testImplementation}) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + } + }) + } +} + +func TestUpdateBMCFirmwareFromInterfaces(t *testing.T) { + testCases := []struct { + name string + err error + badImplementation bool + want string + }{ + {name: "success", err: nil}, + {name: "no implementations found", want: "", badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a BMCFirmwareUpdater implementation: *struct {}"), errors.New("no BMCFirmwareUpdater implementations found")}}}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + var generic []interface{} + if tc.badImplementation { + badImplementation := struct{}{} + generic = []interface{}{&badImplementation} + } else { + testImplementation := firmwareTester{} + generic = []interface{}{&testImplementation} + } + err := UpdateBMCFirmwareFromInterfaces(context.Background(), "foo", generic) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + } + }) + } +} + +func TestGetBIOSVersion(t *testing.T) { + testCases := []struct { + name string + version string + makeFail bool + err error + ctxTimeout time.Duration + }{ + {name: "success", version: "1.44.7", err: nil}, + {name: "failure", version: "", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("failed to get BIOS version"), errors.New("failed to get BIOS version")}}}, + {name: "fail context timeout", version: "", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded"), errors.New("failed to get BIOS version")}}, ctxTimeout: time.Nanosecond * 1}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + testImplementation := firmwareTester{MakeErrorOut: tc.makeFail} + expectedResult := tc.version + if tc.ctxTimeout == 0 { + tc.ctxTimeout = time.Second * 3 + } + ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout) + defer cancel() + result, err := GetBIOSVersion(ctx, []BIOSVersionGetter{&testImplementation}) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + + } else { + diff := cmp.Diff(expectedResult, result) + if diff != "" { + t.Fatal(diff) + } + } + + }) + } +} + +func TestGetBIOSVersionFromInterfaces(t *testing.T) { + testCases := []struct { + name string + version string + err error + badImplementation bool + want string + }{ + {name: "success", version: "1.44.7", err: nil}, + {name: "no implementations found", version: "", want: "", badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a BIOSVersionGetter implementation: *struct {}"), errors.New("no BIOSVersionGetter implementations found")}}}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + var generic []interface{} + if tc.badImplementation { + badImplementation := struct{}{} + generic = []interface{}{&badImplementation} + } else { + testImplementation := firmwareTester{} + generic = []interface{}{&testImplementation} + } + expectedResult := tc.version + result, err := GetBIOSVersionFromInterfaces(context.Background(), generic) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + + } else { + diff := cmp.Diff(expectedResult, result) + if diff != "" { + t.Fatal(diff) + } + } + + }) + } +} + +func TestUpdateBIOSFirmware(t *testing.T) { + testCases := []struct { + name string + makeFail bool + err error + ctxTimeout time.Duration + }{ + {name: "success", err: nil}, + {name: "failure", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("failed update"), errors.New("failed to update BIOS firmware")}}}, + {name: "fail context timeout", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded"), errors.New("failed to update BIOS firmware")}}, ctxTimeout: time.Nanosecond * 1}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + testImplementation := firmwareTester{MakeErrorOut: tc.makeFail} + if tc.ctxTimeout == 0 { + tc.ctxTimeout = time.Second * 3 + } + ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout) + defer cancel() + err := UpdateBIOSFirmware(ctx, "foo", []BIOSFirmwareUpdater{&testImplementation}) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + } + }) + } +} + +func TestUpdateBIOSFirmwareFromInterfaces(t *testing.T) { + testCases := []struct { + name string + err error + badImplementation bool + want string + }{ + {name: "success", err: nil}, + {name: "no implementations found", want: "", badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a BIOSFirmwareUpdater implementation: *struct {}"), errors.New("no BIOSFirmwareUpdater implementations found")}}}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + var generic []interface{} + if tc.badImplementation { + badImplementation := struct{}{} + generic = []interface{}{&badImplementation} + } else { + testImplementation := firmwareTester{} + generic = []interface{}{&testImplementation} + } + err := UpdateBIOSFirmwareFromInterfaces(context.Background(), "foo", generic) + if err != nil { + diff := cmp.Diff(tc.err.Error(), err.Error()) + if diff != "" { + t.Fatal(diff) + } + } + }) + } +} From d2c1eaa9197a3713db51e02628b5c7b70879e693 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 12 Feb 2021 15:14:29 +0100 Subject: [PATCH 13/42] examples: purge testing leftovers --- examples/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/main.go b/examples/main.go index 16ac02e7..dd4b99fe 100644 --- a/examples/main.go +++ b/examples/main.go @@ -21,7 +21,7 @@ import ( // github.com/wojas/genericr: genericr func main() { - ip := "10.230.148.171" + ip := "" user := "admin" pass := "admin" @@ -37,7 +37,7 @@ func main() { printStatus(conn, logger) logger.Info("printing status with the default builtin logger") - os.Setenv("BMCLIB_LOG_LEVEL", "gTtrace") + os.Setenv("BMCLIB_LOG_LEVEL", "trace") conn, err = withDefaultBuiltinLogger(ip, user, pass) if err != nil { logger.Fatal(err) From a51c581902fc70e5140552cd530ac906ebfd174b Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 12 Feb 2021 15:15:32 +0100 Subject: [PATCH 14/42] client: Add remaining FirmwareBIOS* interface methods - purge unused driver registry --- client.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/client.go b/client.go index 450b3270..b29688b9 100644 --- a/client.go +++ b/client.go @@ -6,9 +6,7 @@ import ( "context" "github.com/bmc-toolbox/bmclib/bmc" - "github.com/bmc-toolbox/bmclib/internal/httpclient" "github.com/bmc-toolbox/bmclib/logging" - "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/ipmitool" "github.com/go-logr/logr" "github.com/jacobweinstock/registrar" @@ -71,9 +69,6 @@ func (c *Client) registerProviders() { driverIpmitool := &ipmitool.Conn{Host: c.Auth.Host, Port: c.Auth.Port, User: c.Auth.User, Pass: c.Auth.Pass, Log: c.Logger} c.Registry.Register(ipmitool.ProviderName, ipmitool.ProviderProtocol, ipmitool.Features, nil, driverIpmitool) - // setup https provider - we don't expect Build() to fail - driverHttps, _ := httpclient.Build() - c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, driverHttps) } // Open pass through to library function @@ -130,3 +125,18 @@ func (c *Client) ResetBMC(ctx context.Context, resetType string) (ok bool, err e func (c *Client) GetBMCVersion(ctx context.Context) (version string, err error) { return bmc.GetBMCVersionFromInterfaces(ctx, c.Registry.GetDriverInterfaces()) } + +// UpdateBMCFirmware pass through library function +func (c *Client) UpdateBMCFirmware(ctx context.Context, fileName string) (err error) { + return bmc.UpdateBMCFirmwareFromInterfaces(ctx, fileName, c.Registry.GetDriverInterfaces()) +} + +// GetBIOSVersion pass through library function +func (c *Client) GetBIOSVersion(ctx context.Context) (version string, err error) { + return bmc.GetBIOSVersionFromInterfaces(ctx, c.Registry.GetDriverInterfaces()) +} + +// UpdateBIOSFirmware pass through library function +func (c *Client) UpdateBIOSFirmware(ctx context.Context, fileName string) (err error) { + return bmc.UpdateBIOSFirmwareFromInterfaces(ctx, fileName, c.Registry.GetDriverInterfaces()) +} From c7a10f687c7c8fb3ab10c5b84296f4ea2aab7194 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 12 Feb 2021 15:18:12 +0100 Subject: [PATCH 15/42] asrockrack: update log levels to 1 --- providers/asrockrack/asrockrack.go | 19 ++++++++++--------- providers/asrockrack/helpers.go | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index 6949f696..ff662a65 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -155,29 +155,29 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err } // 1. set the device to flash mode - prepares the flash - a.log.V(0).Info("info", "step", "1/5 - setting device into flash mode.. this takes a minute") + a.log.V(1).Info("info", "step", "1/5 - setting device into flash mode.. this takes a minute") err = a.setFlashMode() if err != nil { return fmt.Errorf("failed in step 1/5 - set device in flash mode: " + err.Error()) } // 2. upload firmware image file - a.log.V(0).Info("info", "step", "2/5 uploading firmware image", "filePath", filePath) - err = a.uploadFirmware(filePath) + a.log.V(1).Info("info", "step", "2/5 uploading firmware image", "filePath", filePath) + err = a.uploadFirmware("api/maintenance/firmware", filePath) if err != nil { return fmt.Errorf("failed in step 2/5 - upload firmware image: " + err.Error()) } // 3. BMC to verify the uploaded file err = a.verifyUploadedFirmware() - a.log.V(0).Info("info", "step", "3/5 - bmc to verify uploaded firmware") + a.log.V(1).Info("info", "step", "3/5 - bmc to verify uploaded firmware") if err != nil { return fmt.Errorf("failed in step 3/5 - verify uploaded firmware: " + err.Error()) } startTS := time.Now() // 4. Run the upgrade - preserving current config - a.log.V(0).Info("info", "step 4/5", "run the upgrade, preserving current configuration") + a.log.V(1).Info("info", "step 4/5", "run the upgrade, preserving current configuration") err = a.upgradeBMC() if err != nil { return fmt.Errorf("failed in step 4/5 - verify uploaded firmware: " + err.Error()) @@ -195,18 +195,19 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err select { case <-progressT: // check progress - p, err := a.flashProgress() + endpoint := "api/maintenance/firmware/flash-progress" + p, err := a.flashProgress(endpoint) if err != nil { errorsCount++ - a.log.V(0).Error(err, "step", "5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Error(err, "step", "5/5 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) continue } - a.log.V(0).Info("info", "step", "5/5 - check flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Info("info", "step", "5/5 - check flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) // all done! if p.State == 2 { - a.log.V(0).Info("info", "step", "5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Info("info", "step", "5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) // The BMC resets by itself after a successful flash a.resetRequired = false // HTTP sessions are terminated once the BMC resets after an upgrade diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 774d407e..558dbd7e 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -317,7 +317,7 @@ func (a *ASRockRack) queryHTTPS(URLendpoint, method string, payload []byte, head // debug dump request reqDump, _ := httputil.DumpRequestOut(req, true) - a.log.V(2).Info("trace", "url", URL, "requestDump", string(reqDump)) + a.log.V(3).Info("trace", "url", URL, "requestDump", string(reqDump)) resp, err := a.httpClient.Do(req) if err != nil { @@ -326,7 +326,7 @@ func (a *ASRockRack) queryHTTPS(URLendpoint, method string, payload []byte, head // debug dump response respDump, _ := httputil.DumpResponse(resp, true) - a.log.V(2).Info("trace", "responseDump", string(respDump)) + a.log.V(3).Info("trace", "responseDump", string(respDump)) body, err = ioutil.ReadAll(resp.Body) if err != nil { From 2dcefc2fab7cde6a27db5673913983893b997852 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 12 Feb 2021 15:19:00 +0100 Subject: [PATCH 16/42] asrockrack: Add BIOS firmware update support --- providers/asrockrack/asrockrack.go | 77 +++++++++++++++++++++++- providers/asrockrack/firmware_update.md | 31 +++++++++- providers/asrockrack/helpers.go | 80 +++++++++++++++++++++++-- providers/asrockrack/mock.go | 37 +++++++++--- 4 files changed, 207 insertions(+), 18 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index ff662a65..1064f609 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -127,7 +127,7 @@ func (a *ASRockRack) GetBMCVersion(ctx context.Context) (string, error) { } } - return a.fwInfo.BIOSVersion, nil + return a.fwInfo.BMCVersion, nil } // nolint: gocyclo @@ -220,7 +220,78 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err } } -func (a *ASRockRack) FirmwareUpdateBIOS(filePath string) error { +func (a *ASRockRack) FirmwareUpdateBIOS(ctx context.Context, filePath string) error { + + defer func() { + if a.resetRequired { + a.log.V(1).Info("info", "resetting BMC, this takes a few minutes") + err := a.reset() + if err != nil { + a.log.Error(err, "failed to reset BMC") + } + } + }() + + // 0. validate the given filePath exists + _, err := os.Stat(filePath) + if os.IsNotExist(err) { + return err + } + + // 1. upload firmware image file + a.log.V(1).Info("info", "step", "1/4 uploading firmware image", "filePath", filePath) + err = a.uploadFirmware("api/asrr/maintenance/BIOS/firmware", filePath) + if err != nil { + return fmt.Errorf("failed in step 1/4 - upload firmware image: " + err.Error()) + } + + // 2. set update parameters to preserve configuratin + a.log.V(1).Info("info", "step", "2/4 set preserve configuration") + err = a.biosUpgradeConfiguration() + if err != nil { + return fmt.Errorf("failed in step 2/4 - set preserve configuration: " + err.Error()) + } + + startTS := time.Now() + // 3. run upgrade + a.log.V(1).Info("info", "step", "3/4 run upgrade") + err = a.biosUpgrade() + if err != nil { + return fmt.Errorf("failed in step 3/4 - run upgrade: " + err.Error()) + } + + // progress check interval + progressT := time.NewTicker(2 * time.Second).C + // timeout interval + timeoutT := time.NewTicker(30 * time.Minute).C + maxErrors := 20 + var errorsCount int + + // 5.loop until firmware was updated - with a timeout + for { + select { + case <-progressT: + // check progress + endpoint := "api/asrr/maintenance/BIOS/flash-progress" + p, err := a.flashProgress(endpoint) + if err != nil { + errorsCount++ + a.log.V(1).Error(err, "step", "4/4 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + continue + } + + a.log.V(1).Info("info", "step", "4/4 - check flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + + // all done! + if p.State == 2 { + a.log.V(1).Info("info", "step", "4/4 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + // Reset BMC after flash + a.resetRequired = true + return nil + } + case <-timeoutT: + return fmt.Errorf("timeout in step 5/5 - flash progress, error count: %d, elapsed time: %s", errorsCount, time.Since(startTS).String()) + } + } - return nil } diff --git a/providers/asrockrack/firmware_update.md b/providers/asrockrack/firmware_update.md index 91af108e..03b28b78 100644 --- a/providers/asrockrack/firmware_update.md +++ b/providers/asrockrack/firmware_update.md @@ -1,4 +1,4 @@ - +### BMC Flashing a BMC firmware seems to be a multi step process @@ -31,4 +31,31 @@ 6. GET https://10.230.148.171/api/maintenance/firmware/flash-progress { "id": 1, "action": "Flashing...", "progress": "12% done ", "state": 0 } - { "id": 1, "action": "Flashing...", "progress": "100% done", "state": 0 } \ No newline at end of file + { "id": 1, "action": "Flashing...", "progress": "100% done", "state": 0 } + + +### BIOS + +1. POST api/asrr/maintenance/BIOS/firmware + multipart payload: + +------WebKitFormBoundaryBet48KCtZK4gBlQz +Content-Disposition: form-data; name="fwimage"; filename="E6D4INL2.07B" +Content-Type: application/octet-stream + + +------WebKitFormBoundaryBet48KCtZK4gBlQz-- + + +2. POST api/asrr/maintenance/BIOS/configuration + payload {"action":"2"} + 200 OK + {"response": 1} + +3. POST api/asrr/maintenance/BIOS/upgrade + payload {action: 3} + 200 oK + +4. GET api/asrr/maintenance/BIOS/flash-progress + + diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 558dbd7e..208b6d2c 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -55,6 +55,13 @@ type upgradeProgress struct { State int `json:"state,omitempty"` } +// BIOS upgrade commands +// 2 == configure +// 3 == apply upgrade +type biosUpdateAction struct { + Action int `json:"action"` +} + // 1 Set BMC to flash mode and prepare flash area // at this point all logged in sessions are terminated // and no logins are permitted @@ -77,9 +84,7 @@ func (a *ASRockRack) setFlashMode() error { } // 2 Upload the firmware file -func (a *ASRockRack) uploadFirmware(filePath string) error { - - endpoint := "api/maintenance/firmware" +func (a *ASRockRack) uploadFirmware(endpoint string, filePath string) error { // setup a buffer for our multipart form var form bytes.Buffer @@ -186,9 +191,7 @@ func (a *ASRockRack) reset() error { } // 5. firmware flash progress -func (a *ASRockRack) flashProgress() (*upgradeProgress, error) { - - endpoint := "api/maintenance/firmware/flash-progress" +func (a *ASRockRack) flashProgress(endpoint string) (*upgradeProgress, error) { resp, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) if err != nil { @@ -233,6 +236,71 @@ func (a *ASRockRack) firmwareInfo() (*firmwareInfo, error) { } +// Set the BIOS upgrade configuration +// - preserve current configuration +func (a *ASRockRack) biosUpgradeConfiguration() error { + + endpoint := "api/asrr/maintenance/BIOS/configuration" + + // Preserve existing configuration? + p := biosUpdateAction{Action: 2} + payload, err := json.Marshal(p) + if err != nil { + return err + } + + headers := map[string]string{"Content-Type": "application/json"} + resp, statusCode, err := a.queryHTTPS(endpoint, "POST", payload, headers) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + f := &firmwareInfo{} + err = json.Unmarshal(resp, f) + if err != nil { + return err + } + + return nil + +} + +// Run BIOS upgrade +func (a *ASRockRack) biosUpgrade() error { + + endpoint := "api/asrr/maintenance/BIOS/upgrade" + + // Run upgrade + p := biosUpdateAction{Action: 3} + payload, err := json.Marshal(p) + if err != nil { + return err + } + + headers := map[string]string{"Content-Type": "application/json"} + resp, statusCode, err := a.queryHTTPS(endpoint, "POST", payload, headers) + if err != nil { + return err + } + + if statusCode != 200 { + return fmt.Errorf("Non 200 response: %d", statusCode) + } + + f := &firmwareInfo{} + err = json.Unmarshal(resp, f) + if err != nil { + return err + } + + return nil + +} + // Aquires a session id cookie and a csrf token func (a *ASRockRack) httpsLogin() error { diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock.go index 59c964b4..c6a11ca1 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock.go @@ -70,17 +70,39 @@ func mockASRockBMC() *httptest.Server { handler.HandleFunc("/api/asrr/fw-info", fwinfo) // fw update endpoints - in order of invocation - handler.HandleFunc("/api/maintenance/flash", firmwareUpgrade) - handler.HandleFunc("/api/maintenance/firmware", firmwareUpgrade) - handler.HandleFunc("/api/maintenance/firmware/verification", firmwareUpgrade) - handler.HandleFunc("/api/maintenance/firmware/upgrade", firmwareUpgrade) - handler.HandleFunc("/api/maintenance/firmware/flash-progress", firmwareUpgrade) - handler.HandleFunc("/api/maintenance/reset", firmwareUpgrade) + handler.HandleFunc("/api/maintenance/flash", bmcFirmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware", bmcFirmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware/verification", bmcFirmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware/upgrade", bmcFirmwareUpgrade) + handler.HandleFunc("/api/maintenance/firmware/flash-progress", bmcFirmwareUpgrade) + handler.HandleFunc("/api/maintenance/reset", bmcFirmwareUpgrade) + handler.HandleFunc("/api/asrr/maintenance/BIOS/firmware", biosFirmwareUpgrade) return httptest.NewTLSServer(handler) } -func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { +func biosFirmwareUpgrade(w http.ResponseWriter, r *http.Request) { + fmt.Printf("%s -> %s\n", r.Method, r.RequestURI) + switch r.Method { + case "POST": + switch r.RequestURI { + case "/api/asrr/maintenance/BIOS/firmware": + + // validate content type + if !strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") { + w.WriteHeader(http.StatusBadRequest) + } + + // parse multipart form + err := r.ParseMultipartForm(100) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + } + } + } +} + +func bmcFirmwareUpgrade(w http.ResponseWriter, r *http.Request) { fmt.Printf("%s -> %s\n", r.Method, r.RequestURI) switch r.Method { case "GET": @@ -156,6 +178,7 @@ func firmwareUpgrade(w http.ResponseWriter, r *http.Request) { } case "POST": switch r.RequestURI { + // 2. upload firmware case "/api/maintenance/firmware": From 22835e578647f8545864e419d72d78514bf5851a Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 12 Feb 2021 16:45:01 +0100 Subject: [PATCH 17/42] Add v1, v2 bmclib client examples --- examples/v1/main.go | 59 ++++++++++++++++++++++++++++++++ examples/v2/main.go | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 examples/v1/main.go create mode 100644 examples/v2/main.go diff --git a/examples/v1/main.go b/examples/v1/main.go new file mode 100644 index 00000000..1d639f99 --- /dev/null +++ b/examples/v1/main.go @@ -0,0 +1,59 @@ +package main + +// This snippet utilizes the 'v1' older bmclib interface methods +// it connects to the bmc and retries its version + +import ( + "context" + "fmt" + "os" + + "github.com/bmc-toolbox/bmclib/devices" + "github.com/bmc-toolbox/bmclib/discover" + "github.com/bombsimon/logrusr" + "github.com/sirupsen/logrus" +) + +func main() { + //ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx := context.TODO() + //defer cancel() + host := "" + user := "" + pass := "" + + l := logrus.New() + l.Level = logrus.TraceLevel + logger := logrusr.NewLogger(l) + + c, err := discover.ScanAndConnect( + host, + user, + pass, + discover.WithContext(ctx), + discover.WithLogger(logger), + discover.WithProbeHint(discover.ProbeASRockRack), + ) + + if err != nil { + logger.Error(err, "Error connecting to bmc") + } + + bmc := c.(devices.Bmc) + + err = bmc.CheckCredentials() + if err != nil { + logger.Error(err, "Failed to validate credentials") + os.Exit(1) + } + + defer bmc.Close(ctx) + + v, err := bmc.GetBMCVersion(ctx) + if err != nil { + logger.Error(err, "Error getting bmc version") + os.Exit(1) + } + fmt.Println(v) + +} diff --git a/examples/v2/main.go b/examples/v2/main.go new file mode 100644 index 00000000..68294104 --- /dev/null +++ b/examples/v2/main.go @@ -0,0 +1,82 @@ +package main + +/* + This utilizes the 'v2' bmclib interface methods +*/ + +import ( + "context" + "fmt" + "time" + + "github.com/bmc-toolbox/bmclib" + "github.com/bmc-toolbox/bmclib/logging" + "github.com/bmc-toolbox/bmclib/providers/asrockrack" + "github.com/bombsimon/logrusr" + "github.com/jacobweinstock/registrar" + "github.com/sirupsen/logrus" +) + +func main() { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Hour) + defer cancel() + host := "" + port := "" + user := "" + pass := "" + + log := logging.DefaultLogger() + + asrockRack, err := asrockrack.New(ctx, host, user, pass, log) + if err != nil { + log.Error(err, "failed to init asrockrack instance") + } + + // how do I get logr to log at trace/debug level + l := logrus.New() + l.Level = logrus.InfoLevel + logg := logrusr.NewLogger(l) + + // define and register driver + drivers := registrar.NewRegistry() + + // The driver interface being provided could implement methods for ProviderName, ProviderProtocol etc + // that way we don't have to pass all of these in individually? + drivers.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, asrockRack) + regOptions := bmclib.WithRegistry(drivers) + + // bmclib client - setting the logger as a param doesn't work - its overwritten by the default logger + cl := bmclib.NewClient(host, port, user, pass, regOptions) + cl.Registry.Logger = logg + + // open connection + err = cl.Open(ctx) + if err != nil { + log.Error(err, "bmc login failed") + } + + defer cl.Close(ctx) + + v, err := cl.GetBMCVersion(ctx) + if err != nil { + log.Error(err, "unable to retrieve BMC version") + } + + fmt.Println("BMC version: " + v) + // err = cl.UpdateBMCFirmware(ctx, "/tmp/E3C246D4I-NL_L0.03.00.ima") + // if err != nil { + // log.Error(err, "error updating BMC firmware") + // } + + // v, err = cl.GetBIOSVersion(ctx) + // if err != nil { + // log.Error(err, "unable to retrieve BIOS version") + // } + // + // fmt.Println("BIOS version: " + v) + // + // err = cl.UpdateBIOSFirmware(ctx, "/tmp/E6D4INL2.07B") + // if err != nil { + // log.Error(err, "error updating BIOS firmware") + // } +} From 8422ccd7c2f581ade68b45b22317e4e0e1396f52 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Wed, 17 Feb 2021 09:52:50 +0100 Subject: [PATCH 18/42] devices/interfaces: purge Firmware interface, its now made available in the v2 interface --- devices/interfaces.go | 9 - discover/discover.go | 3 - discover/discover_test.go | 10 +- discover/probe.go | 28 --- examples/v1/main.go | 7 +- providers/asrockrack/implementations.go | 234 ------------------ providers/dell/idrac8/idrac8.go | 15 -- providers/dell/idrac9/idrac9.go | 15 -- providers/dummy/ibmc/ibmc.go | 16 -- providers/hp/ilo/ilo.go | 15 -- .../supermicro/supermicrox/supermicrox.go | 15 -- .../supermicro/supermicrox11/supermicrox.go | 15 -- .../supermicrox11/supermicrox_test.go | 1 - 13 files changed, 4 insertions(+), 379 deletions(-) delete mode 100644 providers/asrockrack/implementations.go diff --git a/devices/interfaces.go b/devices/interfaces.go index b628dd8c..26ceb0a7 100644 --- a/devices/interfaces.go +++ b/devices/interfaces.go @@ -15,9 +15,6 @@ type Bmc interface { // BmcCollection interface BmcCollection - // Firmware getter/updater interface - Firmware - CheckCredentials() error Close(context.Context) error PowerOn() (bool, error) // PowerSetter @@ -137,9 +134,3 @@ type Configure interface { GenerateCSR(*cfgresources.HTTPSCertAttributes) ([]byte, error) UploadHTTPSCert([]byte, string, []byte, string) (bool, error) } - -type Firmware interface { - GetBIOSVersion(context.Context) (version string, err error) - GetBMCVersion(context.Context) (version string, err error) - FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) -} diff --git a/discover/discover.go b/discover/discover.go index 73d8d9e8..7c4473e4 100644 --- a/discover/discover.go +++ b/discover/discover.go @@ -22,7 +22,6 @@ const ( ProbeM1000e = "m1000e" ProbeQuanta = "quanta" ProbeHpCl100 = "hpcl100" - ProbeASRockRack = "asrockrack" ) // ScanAndConnect will scan the bmc trying to learn the device type and return a working connection. @@ -64,7 +63,6 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e: probe.m1000e, ProbeQuanta: probe.quanta, ProbeHpCl100: probe.hpCl100, - ProbeASRockRack: probe.asRockRack, } order := []string{ProbeHpIlo, @@ -76,7 +74,6 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e, ProbeQuanta, ProbeHpCl100, - ProbeASRockRack, } if opts.Hint != "" { diff --git a/discover/discover_test.go b/discover/discover_test.go index 0ab24b42..0aa885d7 100644 --- a/discover/discover_test.go +++ b/discover/discover_test.go @@ -7,7 +7,6 @@ import ( "strings" "testing" - "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/dell/idrac8" "github.com/bmc-toolbox/bmclib/providers/dell/idrac9" "github.com/bmc-toolbox/bmclib/providers/hp/c7000" @@ -114,11 +113,6 @@ func TestProbes(t *testing.T) { wantHint: ProbeHpIlo, wantType: (*ilo.Ilo)(nil), }, - { - name: "ASRockRack", - wantHint: ProbeASRockRack, - wantType: (*asrockrack.ASRockRack)(nil), - }, } for _, tt := range testt { @@ -184,12 +178,10 @@ var ( ProbeM1000e, ProbeQuanta, ProbeHpCl100, - ProbeASRockRack, } _answers = map[string]map[string][]byte{ - "ASRockRack": {"/": []byte(`ASRockRack`)}, - "IDrac8": {"/session": []byte(`{"aimGetProp" : {"hostname" :"machine","gui_str_title_bar" :"","OEMHostName" :"machine.example.com","fwVersion" :"2.50.33","sysDesc" :"PowerEdge M630","status" : "OK"}}`)}, + "IDrac8": {"/session": []byte(`{"aimGetProp" : {"hostname" :"machine","gui_str_title_bar" :"","OEMHostName" :"machine.example.com","fwVersion" :"2.50.33","sysDesc" :"PowerEdge M630","status" : "OK"}}`)}, "IDrac9": { "/sysmgmt/2015/bmc/info": []byte(`{"Attributes":{"ADEnabled":"Disabled","BuildVersion":"37","FwVer":"3.15.15.15","GUITitleBar":"spare-H16Z4M2","IsOEMBranded":"0","License":"Enterprise","SSOEnabled":"Disabled","SecurityPolicyMessage":"By accessing this computer, you confirm that such access complies with your organization's security policy.","ServerGen":"14G","SrvPrcName":"NULL","SystemLockdown":"Disabled","SystemModelName":"PowerEdge M640","TFAEnabled":"Disabled","iDRACName":"spare-H16Z4M2"}}`), "/sysmgmt/2015/bmc/session": []byte(`{"status": "good", "authResult": 7, "forwardUrl": "something", "errorMsg": "none"}`), diff --git a/discover/probe.go b/discover/probe.go index 81cce646..050e09d9 100644 --- a/discover/probe.go +++ b/discover/probe.go @@ -13,7 +13,6 @@ import ( "github.com/bmc-toolbox/bmclib/devices" "github.com/bmc-toolbox/bmclib/errors" - "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/dell/idrac8" "github.com/bmc-toolbox/bmclib/providers/dell/idrac9" "github.com/bmc-toolbox/bmclib/providers/dell/m1000e" @@ -333,33 +332,6 @@ func (p *Probe) quanta(ctx context.Context, log logr.Logger) (bmcConnection inte return bmcConnection, errors.ErrDeviceNotMatched } -func (p *Probe) asRockRack(ctx context.Context, log logr.Logger) (bmcConnection interface{}, err error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s", p.host), nil) - if err != nil { - return bmcConnection, err - } - resp, err := p.client.Do(req) - if err != nil { - return bmcConnection, err - } - - defer resp.Body.Close() - defer io.Copy(ioutil.Discard, resp.Body) // nolint - - payload, err := ioutil.ReadAll(resp.Body) - if err != nil { - return bmcConnection, err - } - - // ensure the response we got included a png - if resp.StatusCode == 200 && bytes.Contains(payload, []byte("ASRockRack")) { - log.V(1).Info("step", "ScanAndConnect", "host", p.host, "vendor", string(devices.ASRockRack), "msg", "it's a ASRockRack") - return asrockrack.New(ctx, p.host, p.username, p.password, log) - } - - return bmcConnection, errors.ErrDeviceNotMatched -} - func containsAnySubStr(data []byte, subStrs []string) bool { for _, subStr := range subStrs { if bytes.Contains(data, []byte(subStr)) { diff --git a/examples/v1/main.go b/examples/v1/main.go index 1d639f99..1f129750 100644 --- a/examples/v1/main.go +++ b/examples/v1/main.go @@ -32,7 +32,6 @@ func main() { pass, discover.WithContext(ctx), discover.WithLogger(logger), - discover.WithProbeHint(discover.ProbeASRockRack), ) if err != nil { @@ -49,11 +48,11 @@ func main() { defer bmc.Close(ctx) - v, err := bmc.GetBMCVersion(ctx) + s, err := bmc.Serial() if err != nil { - logger.Error(err, "Error getting bmc version") + logger.Error(err, "Error getting bmc serial") os.Exit(1) } - fmt.Println(v) + fmt.Println(s) } diff --git a/providers/asrockrack/implementations.go b/providers/asrockrack/implementations.go deleted file mode 100644 index 37b66809..00000000 --- a/providers/asrockrack/implementations.go +++ /dev/null @@ -1,234 +0,0 @@ -package asrockrack - -import ( - "crypto/x509" - - "github.com/bmc-toolbox/bmclib/cfgresources" - "github.com/bmc-toolbox/bmclib/devices" -) - -// ApplyCfg implements the Bmc interface -func (a *ASRockRack) ApplyCfg(config *cfgresources.ResourcesConfig) (err error) { - return nil -} - -// BiosVersion implements the Bmc interface -func (a *ASRockRack) BiosVersion() (string, error) { - return "", nil -} - -// HardwareType implements the Bmc interface -func (a *ASRockRack) HardwareType() string { - return "" -} - -// Version implements the Bmc interface -func (a *ASRockRack) Version() (string, error) { - return "", nil -} - -// CPU implements the Bmc interface -func (a *ASRockRack) CPU() (string, int, int, int, error) { - return "", 0, 0, 0, nil -} - -// Disks implements the Bmc interface -func (a *ASRockRack) Disks() ([]*devices.Disk, error) { - return make([]*devices.Disk, 0), nil -} - -// IsBlade implements the Bmc interface -func (a *ASRockRack) IsBlade() (bool, error) { - return false, nil -} - -// License implements the Bmc interface -func (a *ASRockRack) License() (string, string, error) { - return "", "", nil -} - -// Memory implements the Bmc interface -func (a *ASRockRack) Memory() (int, error) { - return 0, nil -} - -// Model implements the Bmc interface -func (a *ASRockRack) Model() (string, error) { - return "", nil -} - -// Name implements the Bmc interface -func (a *ASRockRack) Name() (string, error) { - return "", nil -} - -// Nics implements the Bmc interface -func (a *ASRockRack) Nics() ([]*devices.Nic, error) { - return make([]*devices.Nic, 0), nil -} - -// PowerKw implements the Bmc interface -func (a *ASRockRack) PowerKw() (float64, error) { - return 0.0, nil -} - -// PowerState implements the Bmc interface -func (a *ASRockRack) PowerState() (string, error) { - return "", nil -} - -// PowerCycleBmc implements the Bmc interface -func (a *ASRockRack) PowerCycleBmc() (status bool, err error) { - return false, nil -} - -// PowerCycle implements the Bmc interface -func (a *ASRockRack) PowerCycle() (status bool, err error) { - return false, nil -} - -// PowerOff implements the Bmc interface -func (a *ASRockRack) PowerOff() (status bool, err error) { - return false, nil -} - -// PowerOn implements the Bmc interface -func (a *ASRockRack) PowerOn() (status bool, err error) { - return false, nil -} - -// PxeOnce implements the Bmc interface -func (a *ASRockRack) PxeOnce() (status bool, err error) { - return false, nil -} - -// Serial implements the Bmc interface -func (a *ASRockRack) Serial() (string, error) { - return "", nil -} - -// ChassisSerial implements the Bmc interface -func (a *ASRockRack) ChassisSerial() (string, error) { - return "", nil -} - -// Status implements the Bmc interface -func (a *ASRockRack) Status() (string, error) { - return "", nil -} - -// TempC implements the Bmc interface -func (a *ASRockRack) TempC() (int, error) { - return 0, nil -} - -// Vendor implements the Bmc interface -func (a *ASRockRack) Vendor() string { - return "" -} - -// Screenshot implements the Bmc interface -func (a *ASRockRack) Screenshot() ([]byte, string, error) { - return []byte{}, "", nil -} - -// ServerSnapshot implements the Bmc interface -func (a *ASRockRack) ServerSnapshot() (interface{}, error) { - return nil, nil -} - -// UpdateCredentials implements the Bmc interface -func (a *ASRockRack) UpdateCredentials(string, string) { -} - -// Slot implements the Bmc interface -func (a *ASRockRack) Slot() (int, error) { - return -1, nil -} - -// UpdateFirmware implements the Bmc inteface -func (a *ASRockRack) UpdateFirmware(string, string) (b bool, e error) { - return b, e -} - -// IsOn implements the Bmc interface -func (a *ASRockRack) IsOn() (status bool, err error) { - return false, nil -} - -// Resources returns a slice of supported resources and -// the order they are to be applied in. -func (a *ASRockRack) Resources() []string { - return []string{ - "user", - "syslog", - "ntp", - "ldap", - "ldap_group", - "network", - } -} - -// Power implemented the Configure interface -func (a *ASRockRack) Power(cfg *cfgresources.Power) (err error) { - return err -} - -// User method implements the Configure interface -func (a *ASRockRack) User(cfg []*cfgresources.User) error { - return nil -} - -// Syslog method implements the Configure interface -func (a *ASRockRack) Syslog(cfg *cfgresources.Syslog) error { - return nil -} - -// Ntp method implements the Configure interface -func (a *ASRockRack) Ntp(cfg *cfgresources.Ntp) error { - return nil -} - -// Ldap method implements the Configure interface -func (a *ASRockRack) Ldap(cfg *cfgresources.Ldap) error { - return nil -} - -// LdapGroup method implements the Configure interface -func (a *ASRockRack) LdapGroup(cfgGroup []*cfgresources.LdapGroup, cfgLdap *cfgresources.Ldap) error { - return nil -} - -// Network method implements the Configure interface -func (a *ASRockRack) Network(cfg *cfgresources.Network) (bool, error) { - return false, nil -} - -// SetLicense implements the Configure interface -func (a *ASRockRack) SetLicense(*cfgresources.License) error { - return nil -} - -// Bios method implements the Configure interface -func (a *ASRockRack) Bios(cfg *cfgresources.Bios) error { - return nil -} - -// GenerateCSR generates a CSR request on the BMC. -// GenerateCSR implements the Configure interface. -func (a *ASRockRack) GenerateCSR(cert *cfgresources.HTTPSCertAttributes) ([]byte, error) { - return []byte{}, nil -} - -// UploadHTTPSCert uploads the given CRT cert, -// UploadHTTPSCert implements the Configure interface. -func (a *ASRockRack) UploadHTTPSCert(cert []byte, certFileName string, key []byte, keyFileName string) (bool, error) { - return false, nil -} - -// CurrentHTTPSCert returns the current x509 certficates configured on the BMC -// The bool value returned indicates if the BMC supports CSR generation. -// CurrentHTTPSCert implements the Configure interface. -func (a *ASRockRack) CurrentHTTPSCert() ([]*x509.Certificate, bool, error) { - return nil, false, nil -} diff --git a/providers/dell/idrac8/idrac8.go b/providers/dell/idrac8/idrac8.go index 04af8dec..c894c530 100644 --- a/providers/dell/idrac8/idrac8.go +++ b/providers/dell/idrac8/idrac8.go @@ -882,18 +882,3 @@ func (i *IDrac8) UpdateCredentials(username string, password string) { i.username = username i.password = password } - -// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface -func (i *IDrac8) GetBIOSVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// BMCVersion returns the BMC version, implements the Firmware interface -func (i *IDrac8) GetBMCVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// Updates the BMC firmware, implements the Firmware interface -func (i *IDrac8) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - return errors.ErrNotImplemented -} diff --git a/providers/dell/idrac9/idrac9.go b/providers/dell/idrac9/idrac9.go index fc3fc9a5..80999cfa 100644 --- a/providers/dell/idrac9/idrac9.go +++ b/providers/dell/idrac9/idrac9.go @@ -925,18 +925,3 @@ func (i *IDrac9) UpdateCredentials(username string, password string) { i.username = username i.password = password } - -// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface -func (i *IDrac9) GetBIOSVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// BMCVersion returns the BMC version, implements the Firmware interface -func (i *IDrac9) GetBMCVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// Updates the BMC firmware, implements the Firmware interface -func (i *IDrac9) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - return errors.ErrNotImplemented -} diff --git a/providers/dummy/ibmc/ibmc.go b/providers/dummy/ibmc/ibmc.go index 9225b033..2a069432 100644 --- a/providers/dummy/ibmc/ibmc.go +++ b/providers/dummy/ibmc/ibmc.go @@ -5,7 +5,6 @@ import ( "github.com/bmc-toolbox/bmclib/cfgresources" "github.com/bmc-toolbox/bmclib/devices" - "github.com/bmc-toolbox/bmclib/errors" ) // The ibmc model is part of the dummy vendor, @@ -187,18 +186,3 @@ func (i *Ibmc) UpdateFirmware(string, string) (b bool, e error) { func (i *Ibmc) IsOn() (status bool, err error) { return false, nil } - -// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface -func (i *Ibmc) GetBIOSVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// BMCVersion returns the BMC version, implements the Firmware interface -func (i *Ibmc) GetBMCVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// Updates the BMC firmware, implements the Firmware interface -func (i *Ibmc) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - return errors.ErrNotImplemented -} diff --git a/providers/hp/ilo/ilo.go b/providers/hp/ilo/ilo.go index 12e53a4a..b904041f 100644 --- a/providers/hp/ilo/ilo.go +++ b/providers/hp/ilo/ilo.go @@ -843,18 +843,3 @@ func (i *Ilo) UpdateCredentials(username string, password string) { i.username = username i.password = password } - -// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface -func (i *Ilo) GetBIOSVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// BMCVersion returns the BMC version, implements the Firmware interface -func (i *Ilo) GetBMCVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// Updates the BMC firmware, implements the Firmware interface -func (i *Ilo) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - return errors.ErrNotImplemented -} diff --git a/providers/supermicro/supermicrox/supermicrox.go b/providers/supermicro/supermicrox/supermicrox.go index 5194cb12..2b871274 100644 --- a/providers/supermicro/supermicrox/supermicrox.go +++ b/providers/supermicro/supermicrox/supermicrox.go @@ -721,18 +721,3 @@ func (s *SupermicroX) UpdateCredentials(username string, password string) { s.username = username s.password = password } - -// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface -func (s *SupermicroX) GetBIOSVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// BMCVersion returns the BMC version, implements the Firmware interface -func (s *SupermicroX) GetBMCVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// Updates the BMC firmware, implements the Firmware interface -func (s *SupermicroX) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - return errors.ErrNotImplemented -} diff --git a/providers/supermicro/supermicrox11/supermicrox.go b/providers/supermicro/supermicrox11/supermicrox.go index 0ecbe543..dc44674d 100644 --- a/providers/supermicro/supermicrox11/supermicrox.go +++ b/providers/supermicro/supermicrox11/supermicrox.go @@ -724,18 +724,3 @@ func (s *SupermicroX) UpdateCredentials(username string, password string) { s.username = username s.password = password } - -// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface -func (s *SupermicroX) GetBIOSVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// BMCVersion returns the BMC version, implements the Firmware interface -func (s *SupermicroX) GetBMCVersion(ctx context.Context) (string, error) { - return "", errors.ErrNotImplemented -} - -// Updates the BMC firmware, implements the Firmware interface -func (s *SupermicroX) FirmwareUpdateBMC(ctx context.Context, filePath string) error { - return errors.ErrNotImplemented -} diff --git a/providers/supermicro/supermicrox11/supermicrox_test.go b/providers/supermicro/supermicrox11/supermicrox_test.go index 75d3b042..eeb7094c 100644 --- a/providers/supermicro/supermicrox11/supermicrox_test.go +++ b/providers/supermicro/supermicrox11/supermicrox_test.go @@ -597,7 +597,6 @@ func TestIBmcInterface(t *testing.T) { } _ = devices.Bmc(bmc) _ = devices.Configure(bmc) - _ = devices.Firmware(bmc) tearDown() } From d311fd610bef0906caef5f6d47dc11ae6f6f03e3 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 10:25:42 +0100 Subject: [PATCH 19/42] Add context paramter to Close() This enables the existing codebase to be implemented by both the current and newer interfaces. the current interface (bmclib v0) https://github.com/bmc-toolbox/bmclib/blob/c1fed9df833628df57796245d085c97187f06f9a/devices/interfaces.go the newer interface (bmclib v2) https://github.com/bmc-toolbox/bmclib/blob/c1fed9df833628df57796245d085c97187f06f9a/bmc/connection.go#L17 --- providers/dummy/ibmc/ibmc.go | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/dummy/ibmc/ibmc.go b/providers/dummy/ibmc/ibmc.go index 2a069432..0fca762a 100644 --- a/providers/dummy/ibmc/ibmc.go +++ b/providers/dummy/ibmc/ibmc.go @@ -5,6 +5,7 @@ import ( "github.com/bmc-toolbox/bmclib/cfgresources" "github.com/bmc-toolbox/bmclib/devices" + "github.com/bmc-toolbox/bmclib/errors" ) // The ibmc model is part of the dummy vendor, From 64415532a8b92bc1aef236b99e1560d86849fff0 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Feb 2021 16:48:02 +0100 Subject: [PATCH 20/42] Add methods, initial work to probe for ASRR BMCs --- discover/discover.go | 3 +++ discover/discover_test.go | 5 +++++ discover/probe.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/discover/discover.go b/discover/discover.go index 7c4473e4..73d8d9e8 100644 --- a/discover/discover.go +++ b/discover/discover.go @@ -22,6 +22,7 @@ const ( ProbeM1000e = "m1000e" ProbeQuanta = "quanta" ProbeHpCl100 = "hpcl100" + ProbeASRockRack = "asrockrack" ) // ScanAndConnect will scan the bmc trying to learn the device type and return a working connection. @@ -63,6 +64,7 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e: probe.m1000e, ProbeQuanta: probe.quanta, ProbeHpCl100: probe.hpCl100, + ProbeASRockRack: probe.asRockRack, } order := []string{ProbeHpIlo, @@ -74,6 +76,7 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e, ProbeQuanta, ProbeHpCl100, + ProbeASRockRack, } if opts.Hint != "" { diff --git a/discover/discover_test.go b/discover/discover_test.go index 0aa885d7..bf4806c1 100644 --- a/discover/discover_test.go +++ b/discover/discover_test.go @@ -113,6 +113,11 @@ func TestProbes(t *testing.T) { wantHint: ProbeHpIlo, wantType: (*ilo.Ilo)(nil), }, + { + name: "ASRockRack", + wantHint: ProbeASRockRack, + wantType: nil, + }, } for _, tt := range testt { diff --git a/discover/probe.go b/discover/probe.go index 050e09d9..81cce646 100644 --- a/discover/probe.go +++ b/discover/probe.go @@ -13,6 +13,7 @@ import ( "github.com/bmc-toolbox/bmclib/devices" "github.com/bmc-toolbox/bmclib/errors" + "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/dell/idrac8" "github.com/bmc-toolbox/bmclib/providers/dell/idrac9" "github.com/bmc-toolbox/bmclib/providers/dell/m1000e" @@ -332,6 +333,33 @@ func (p *Probe) quanta(ctx context.Context, log logr.Logger) (bmcConnection inte return bmcConnection, errors.ErrDeviceNotMatched } +func (p *Probe) asRockRack(ctx context.Context, log logr.Logger) (bmcConnection interface{}, err error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s", p.host), nil) + if err != nil { + return bmcConnection, err + } + resp, err := p.client.Do(req) + if err != nil { + return bmcConnection, err + } + + defer resp.Body.Close() + defer io.Copy(ioutil.Discard, resp.Body) // nolint + + payload, err := ioutil.ReadAll(resp.Body) + if err != nil { + return bmcConnection, err + } + + // ensure the response we got included a png + if resp.StatusCode == 200 && bytes.Contains(payload, []byte("ASRockRack")) { + log.V(1).Info("step", "ScanAndConnect", "host", p.host, "vendor", string(devices.ASRockRack), "msg", "it's a ASRockRack") + return asrockrack.New(ctx, p.host, p.username, p.password, log) + } + + return bmcConnection, errors.ErrDeviceNotMatched +} + func containsAnySubStr(data []byte, subStrs []string) bool { for _, subStr := range subStrs { if bytes.Contains(data, []byte(subStr)) { From 5c150f77dd5d753e56cea9951fc11e7bfe63ea4f Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Feb 2021 17:59:38 +0100 Subject: [PATCH 21/42] lint fixes --- go.sum | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/go.sum b/go.sum index 5b9c11a1..bcf361d3 100644 --- a/go.sum +++ b/go.sum @@ -137,13 +137,10 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -156,7 +153,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -164,14 +160,11 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -189,36 +182,26 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg= github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -228,16 +211,13 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -245,7 +225,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -260,7 +239,6 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -280,7 +258,6 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -308,16 +285,13 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -339,10 +313,8 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -368,15 +340,11 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -384,13 +352,10 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 01f89234ca0be632586a88238589b0ebffa8b162 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Thu, 11 Feb 2021 12:05:12 +0100 Subject: [PATCH 22/42] providers: implement stub Firmware interface methods --- devices/interfaces.go | 9 +++++++++ providers/dell/idrac8/idrac8.go | 15 +++++++++++++++ providers/dell/idrac9/idrac9.go | 15 +++++++++++++++ providers/dummy/ibmc/ibmc.go | 15 +++++++++++++++ providers/hp/ilo/ilo.go | 15 +++++++++++++++ providers/supermicro/supermicrox/supermicrox.go | 15 +++++++++++++++ providers/supermicro/supermicrox11/supermicrox.go | 15 +++++++++++++++ .../supermicro/supermicrox11/supermicrox_test.go | 1 + 8 files changed, 100 insertions(+) diff --git a/devices/interfaces.go b/devices/interfaces.go index 26ceb0a7..b628dd8c 100644 --- a/devices/interfaces.go +++ b/devices/interfaces.go @@ -15,6 +15,9 @@ type Bmc interface { // BmcCollection interface BmcCollection + // Firmware getter/updater interface + Firmware + CheckCredentials() error Close(context.Context) error PowerOn() (bool, error) // PowerSetter @@ -134,3 +137,9 @@ type Configure interface { GenerateCSR(*cfgresources.HTTPSCertAttributes) ([]byte, error) UploadHTTPSCert([]byte, string, []byte, string) (bool, error) } + +type Firmware interface { + GetBIOSVersion(context.Context) (version string, err error) + GetBMCVersion(context.Context) (version string, err error) + FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) +} diff --git a/providers/dell/idrac8/idrac8.go b/providers/dell/idrac8/idrac8.go index c894c530..04af8dec 100644 --- a/providers/dell/idrac8/idrac8.go +++ b/providers/dell/idrac8/idrac8.go @@ -882,3 +882,18 @@ func (i *IDrac8) UpdateCredentials(username string, password string) { i.username = username i.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *IDrac8) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *IDrac8) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *IDrac8) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/dell/idrac9/idrac9.go b/providers/dell/idrac9/idrac9.go index 80999cfa..fc3fc9a5 100644 --- a/providers/dell/idrac9/idrac9.go +++ b/providers/dell/idrac9/idrac9.go @@ -925,3 +925,18 @@ func (i *IDrac9) UpdateCredentials(username string, password string) { i.username = username i.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *IDrac9) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *IDrac9) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *IDrac9) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/dummy/ibmc/ibmc.go b/providers/dummy/ibmc/ibmc.go index 0fca762a..9225b033 100644 --- a/providers/dummy/ibmc/ibmc.go +++ b/providers/dummy/ibmc/ibmc.go @@ -187,3 +187,18 @@ func (i *Ibmc) UpdateFirmware(string, string) (b bool, e error) { func (i *Ibmc) IsOn() (status bool, err error) { return false, nil } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *Ibmc) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *Ibmc) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *Ibmc) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/hp/ilo/ilo.go b/providers/hp/ilo/ilo.go index b904041f..12e53a4a 100644 --- a/providers/hp/ilo/ilo.go +++ b/providers/hp/ilo/ilo.go @@ -843,3 +843,18 @@ func (i *Ilo) UpdateCredentials(username string, password string) { i.username = username i.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (i *Ilo) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (i *Ilo) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (i *Ilo) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/supermicro/supermicrox/supermicrox.go b/providers/supermicro/supermicrox/supermicrox.go index 2b871274..5194cb12 100644 --- a/providers/supermicro/supermicrox/supermicrox.go +++ b/providers/supermicro/supermicrox/supermicrox.go @@ -721,3 +721,18 @@ func (s *SupermicroX) UpdateCredentials(username string, password string) { s.username = username s.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (s *SupermicroX) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (s *SupermicroX) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (s *SupermicroX) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/supermicro/supermicrox11/supermicrox.go b/providers/supermicro/supermicrox11/supermicrox.go index dc44674d..0ecbe543 100644 --- a/providers/supermicro/supermicrox11/supermicrox.go +++ b/providers/supermicro/supermicrox11/supermicrox.go @@ -724,3 +724,18 @@ func (s *SupermicroX) UpdateCredentials(username string, password string) { s.username = username s.password = password } + +// BiosVersion returns the BIOS version from the BMC, implements the Firmware interface +func (s *SupermicroX) GetBIOSVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// BMCVersion returns the BMC version, implements the Firmware interface +func (s *SupermicroX) GetBMCVersion(ctx context.Context) (string, error) { + return "", errors.ErrNotImplemented +} + +// Updates the BMC firmware, implements the Firmware interface +func (s *SupermicroX) FirmwareUpdateBMC(ctx context.Context, filePath string) error { + return errors.ErrNotImplemented +} diff --git a/providers/supermicro/supermicrox11/supermicrox_test.go b/providers/supermicro/supermicrox11/supermicrox_test.go index eeb7094c..75d3b042 100644 --- a/providers/supermicro/supermicrox11/supermicrox_test.go +++ b/providers/supermicro/supermicrox11/supermicrox_test.go @@ -597,6 +597,7 @@ func TestIBmcInterface(t *testing.T) { } _ = devices.Bmc(bmc) _ = devices.Configure(bmc) + _ = devices.Firmware(bmc) tearDown() } From 2b52025101fc4fba5e062da846cbb195c18ce758 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Sun, 21 Feb 2021 19:55:35 +0100 Subject: [PATCH 23/42] providers/asrockrack: various linting fixes based on feedback in PR#196 --- providers/asrockrack/asrockrack_test.go | 11 ----------- providers/asrockrack/helpers.go | 24 +++++++++++------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/providers/asrockrack/asrockrack_test.go b/providers/asrockrack/asrockrack_test.go index 90096dca..72ed3be1 100644 --- a/providers/asrockrack/asrockrack_test.go +++ b/providers/asrockrack/asrockrack_test.go @@ -8,17 +8,6 @@ import ( "gopkg.in/go-playground/assert.v1" ) -//func TestBmcInterface(t *testing.T) { - -//c, err := New(context.TODO(), ip, username, password, logrusr.NewLogger(testLog)) -//if err != nil { -//return c, err -//} -//_ = devices.Bmc(c) -//_ = devices.Configure(c) -//_ = devices.Firmware(c) -//} - func Test_httpLogin(t *testing.T) { err := aClient.httpsLogin() diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 208b6d2c..77c5013d 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -14,7 +14,6 @@ import ( "path" "github.com/bmc-toolbox/bmclib/errors" - log "github.com/sirupsen/logrus" ) // API session setup response payload @@ -75,7 +74,7 @@ func (a *ASRockRack) setFlashMode() error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } a.resetRequired = true @@ -122,7 +121,7 @@ func (a *ASRockRack) uploadFirmware(endpoint string, filePath string) error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } return nil @@ -139,7 +138,7 @@ func (a *ASRockRack) verifyUploadedFirmware() error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } return nil @@ -165,7 +164,7 @@ func (a *ASRockRack) upgradeBMC() error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } return nil @@ -177,13 +176,13 @@ func (a *ASRockRack) reset() error { endpoint := "api/maintenance/reset" - _, statusCode, err := a.queryHTTPS(endpoint, "GET", nil, nil) + _, statusCode, err := a.queryHTTPS(endpoint, "POST", nil, nil) if err != nil { return err } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } return nil @@ -199,7 +198,7 @@ func (a *ASRockRack) flashProgress(endpoint string) (*upgradeProgress, error) { } if statusCode != 200 { - return nil, fmt.Errorf("Non 200 response: %d", statusCode) + return nil, fmt.Errorf("non 200 response: %d", statusCode) } p := &upgradeProgress{} @@ -223,7 +222,7 @@ func (a *ASRockRack) firmwareInfo() (*firmwareInfo, error) { } if statusCode != 200 { - return nil, fmt.Errorf("Non 200 response: %d", statusCode) + return nil, fmt.Errorf("non 200 response: %d", statusCode) } f := &firmwareInfo{} @@ -256,7 +255,7 @@ func (a *ASRockRack) biosUpgradeConfiguration() error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } f := &firmwareInfo{} @@ -288,7 +287,7 @@ func (a *ASRockRack) biosUpgrade() error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response: %d", statusCode) + return fmt.Errorf("non 200 response: %d", statusCode) } f := &firmwareInfo{} @@ -338,7 +337,6 @@ func (a *ASRockRack) httpsLogin() error { func (a *ASRockRack) httpsLogout() error { urlEndpoint := "api/session" - log.WithFields(log.Fields{"step": "bmc connection", "vendor": VendorID, "ip": a.ip}).Debug("logout from bmc") _, statusCode, err := a.queryHTTPS(urlEndpoint, "DELETE", nil, nil) if err != nil { @@ -350,7 +348,7 @@ func (a *ASRockRack) httpsLogout() error { } if statusCode != 200 { - return fmt.Errorf("Non 200 response at https logout: %d", statusCode) + return fmt.Errorf("non 200 response at https logout: %d", statusCode) } return nil From 39b616a7bef03aad1260ca668ae548937d061fc6 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Sun, 21 Feb 2021 19:58:08 +0100 Subject: [PATCH 24/42] providers/asrockrack: move test init into TestMain --- providers/asrockrack/{mock.go => mock_test.go} | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) rename providers/asrockrack/{mock.go => mock_test.go} (99%) diff --git a/providers/asrockrack/mock.go b/providers/asrockrack/mock_test.go similarity index 99% rename from providers/asrockrack/mock.go rename to providers/asrockrack/mock_test.go index c6a11ca1..dde46cec 100644 --- a/providers/asrockrack/mock.go +++ b/providers/asrockrack/mock_test.go @@ -10,8 +10,10 @@ import ( "net/http" "net/http/httptest" "net/url" + "os" "strconv" "strings" + "testing" "github.com/bombsimon/logrusr" "github.com/sirupsen/logrus" @@ -43,7 +45,7 @@ type testFwUpgradeState struct { // the bmc lib client var aClient *ASRockRack -func init() { +func TestMain(m *testing.M) { var err error // setup mock server @@ -61,6 +63,7 @@ func init() { // firmware update test state fwUpgradeState = &testFwUpgradeState{} + os.Exit(m.Run()) } /////////////// mock bmc service /////////////////////////// @@ -114,8 +117,6 @@ func bmcFirmwareUpgrade(w http.ResponseWriter, r *http.Request) { } fwUpgradeState.FirmwareVerified = true _, _ = w.Write(fwVerificationResponse) - case "/api/maintenance/reset": - w.WriteHeader(http.StatusOK) // 5. flash progress case "/api/maintenance/firmware/flash-progress": if !fwUpgradeState.UpgradeInitiated { @@ -178,6 +179,8 @@ func bmcFirmwareUpgrade(w http.ResponseWriter, r *http.Request) { } case "POST": switch r.RequestURI { + case "/api/maintenance/reset": + w.WriteHeader(http.StatusOK) // 2. upload firmware case "/api/maintenance/firmware": From 9070351076f4c7a1bfe9509ddc17ae9d8e1bdacc Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Sun, 21 Feb 2021 19:59:39 +0100 Subject: [PATCH 25/42] client: move asrockrack registry --- client.go | 3 +++ examples/v2/main.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index b29688b9..d5dec5ab 100644 --- a/client.go +++ b/client.go @@ -7,6 +7,7 @@ import ( "github.com/bmc-toolbox/bmclib/bmc" "github.com/bmc-toolbox/bmclib/logging" + "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/ipmitool" "github.com/go-logr/logr" "github.com/jacobweinstock/registrar" @@ -69,6 +70,8 @@ func (c *Client) registerProviders() { driverIpmitool := &ipmitool.Conn{Host: c.Auth.Host, Port: c.Auth.Port, User: c.Auth.User, Pass: c.Auth.Pass, Log: c.Logger} c.Registry.Register(ipmitool.ProviderName, ipmitool.ProviderProtocol, ipmitool.Features, nil, driverIpmitool) + asrockRack, _ := asrockrack.New(context.TODO(), c.Auth.Host, c.Auth.User, c.Auth.Pass, c.Logger) + c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, asrockRack) } // Open pass through to library function diff --git a/examples/v2/main.go b/examples/v2/main.go index 68294104..ac5c227e 100644 --- a/examples/v2/main.go +++ b/examples/v2/main.go @@ -42,7 +42,7 @@ func main() { // The driver interface being provided could implement methods for ProviderName, ProviderProtocol etc // that way we don't have to pass all of these in individually? - drivers.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, asrockRack) + regOptions := bmclib.WithRegistry(drivers) // bmclib client - setting the logger as a param doesn't work - its overwritten by the default logger From f099ec7c14d4d70f113fc1b8ef4dde56f9cdeddb Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 16 Feb 2021 20:13:46 +0100 Subject: [PATCH 26/42] providers/asrockrack: implement the registrar.Verifier interface --- providers/asrockrack/asrockrack.go | 25 +++++++++++++++++++++++-- providers/asrockrack/asrockrack_test.go | 7 +++++++ providers/asrockrack/mock_test.go | 8 ++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index 1064f609..579dbc76 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -1,6 +1,7 @@ package asrockrack import ( + "bytes" "context" "fmt" "net/http" @@ -67,7 +68,27 @@ func New(ctx context.Context, ip string, username string, password string, log l }, nil } -// Open a connection to a BMC +// Compatible implements the registrar.Verifier interface +// returns true if the BMC is identified to be an asrockrack +func (a *ASRockRack) Compatible() bool { + + resp, statusCode, err := a.queryHTTPS("/", "GET", nil, nil) + if err != nil { + return false + } + + if statusCode != 200 { + return false + } + + if bytes.Contains(resp, []byte(`ASRockRack`)) { + return true + } + + return false +} + +// Open a connection to a BMC, implements the Opener interface func (a *ASRockRack) Open(ctx context.Context) (err error) { err = a.httpsLogin() @@ -78,7 +99,7 @@ func (a *ASRockRack) Open(ctx context.Context) (err error) { return nil } -// Close a connection to a BMC +// Close a connection to a BMC, implements the Closer interface func (a *ASRockRack) Close(ctx context.Context) (err error) { if a.skipLogout { diff --git a/providers/asrockrack/asrockrack_test.go b/providers/asrockrack/asrockrack_test.go index 72ed3be1..60825cc6 100644 --- a/providers/asrockrack/asrockrack_test.go +++ b/providers/asrockrack/asrockrack_test.go @@ -8,6 +8,13 @@ import ( "gopkg.in/go-playground/assert.v1" ) +func Test_Compatible(t *testing.T) { + b := aClient.Compatible() + if !b { + t.Errorf("expected true, got false") + } +} + func Test_httpLogin(t *testing.T) { err := aClient.httpsLogin() diff --git a/providers/asrockrack/mock_test.go b/providers/asrockrack/mock_test.go index dde46cec..4fa02a59 100644 --- a/providers/asrockrack/mock_test.go +++ b/providers/asrockrack/mock_test.go @@ -69,6 +69,7 @@ func TestMain(m *testing.M) { /////////////// mock bmc service /////////////////////////// func mockASRockBMC() *httptest.Server { handler := http.NewServeMux() + handler.HandleFunc("/", index) handler.HandleFunc("/api/session", session) handler.HandleFunc("/api/asrr/fw-info", fwinfo) @@ -84,6 +85,13 @@ func mockASRockBMC() *httptest.Server { return httptest.NewTLSServer(handler) } +func index(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + _, _ = w.Write([]byte(`ASRockRack`)) + } +} + func biosFirmwareUpgrade(w http.ResponseWriter, r *http.Request) { fmt.Printf("%s -> %s\n", r.Method, r.RequestURI) switch r.Method { From a688310172f20bbb8b3a5f4ca4b9d9b5ca3f5373 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 16 Feb 2021 20:14:49 +0100 Subject: [PATCH 27/42] client: register asrockrack driver --- client.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index d5dec5ab..15ac69e2 100644 --- a/client.go +++ b/client.go @@ -70,8 +70,10 @@ func (c *Client) registerProviders() { driverIpmitool := &ipmitool.Conn{Host: c.Auth.Host, Port: c.Auth.Port, User: c.Auth.User, Pass: c.Auth.Pass, Log: c.Logger} c.Registry.Register(ipmitool.ProviderName, ipmitool.ProviderProtocol, ipmitool.Features, nil, driverIpmitool) - asrockRack, _ := asrockrack.New(context.TODO(), c.Auth.Host, c.Auth.User, c.Auth.Pass, c.Logger) - c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, asrockRack) + // register ASRR vendorapi provider + driverAsrockrack, _ := asrockrack.New(context.TODO(), c.Auth.Host, c.Auth.User, c.Auth.Pass, c.Logger) + c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, driverAsrockrack) + } // Open pass through to library function From a09e6614a858613ecfec22ac8c55a6f51c7fbd9f Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 16 Feb 2021 20:16:38 +0100 Subject: [PATCH 28/42] examples/v2: clean up since the provider driver is registered --- examples/v2/main.go | 59 +++++++++------------------------------------ 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/examples/v2/main.go b/examples/v2/main.go index ac5c227e..159969e6 100644 --- a/examples/v2/main.go +++ b/examples/v2/main.go @@ -7,76 +7,39 @@ package main import ( "context" "fmt" + "log" "time" "github.com/bmc-toolbox/bmclib" - "github.com/bmc-toolbox/bmclib/logging" - "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bombsimon/logrusr" - "github.com/jacobweinstock/registrar" "github.com/sirupsen/logrus" ) func main() { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Hour) + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - host := "" + host := "127.0.0.1" port := "" - user := "" - pass := "" + user := "foo" + pass := "bar" - log := logging.DefaultLogger() - - asrockRack, err := asrockrack.New(ctx, host, user, pass, log) - if err != nil { - log.Error(err, "failed to init asrockrack instance") - } - - // how do I get logr to log at trace/debug level + cl := bmclib.NewClient(host, port, user, pass) l := logrus.New() - l.Level = logrus.InfoLevel - logg := logrusr.NewLogger(l) - - // define and register driver - drivers := registrar.NewRegistry() - - // The driver interface being provided could implement methods for ProviderName, ProviderProtocol etc - // that way we don't have to pass all of these in individually? - - regOptions := bmclib.WithRegistry(drivers) - - // bmclib client - setting the logger as a param doesn't work - its overwritten by the default logger - cl := bmclib.NewClient(host, port, user, pass, regOptions) - cl.Registry.Logger = logg + l.Level = logrus.TraceLevel + cl.Logger = logrusr.NewLogger(l) - // open connection - err = cl.Open(ctx) + err := cl.Open(ctx) if err != nil { - log.Error(err, "bmc login failed") + log.Fatal(err, "bmc login failed") } defer cl.Close(ctx) v, err := cl.GetBMCVersion(ctx) if err != nil { - log.Error(err, "unable to retrieve BMC version") + log.Fatal(err, "unable to retrieve BMC version") } fmt.Println("BMC version: " + v) - // err = cl.UpdateBMCFirmware(ctx, "/tmp/E3C246D4I-NL_L0.03.00.ima") - // if err != nil { - // log.Error(err, "error updating BMC firmware") - // } - // v, err = cl.GetBIOSVersion(ctx) - // if err != nil { - // log.Error(err, "unable to retrieve BIOS version") - // } - // - // fmt.Println("BIOS version: " + v) - // - // err = cl.UpdateBIOSFirmware(ctx, "/tmp/E6D4INL2.07B") - // if err != nil { - // log.Error(err, "error updating BIOS firmware") - // } } From fa8e5f5772a314a2c18e6149962a2a33ddf20e1f Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 23 Feb 2021 08:16:10 +0100 Subject: [PATCH 29/42] client: point registry logger after opts are set --- client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.go b/client.go index 15ac69e2..c0e8d6f3 100644 --- a/client.go +++ b/client.go @@ -47,12 +47,12 @@ func NewClient(host, port, user, pass string, opts ...Option) *Client { Logger: logging.DefaultLogger(), Registry: registrar.NewRegistry(), } - defaultClient.Registry.Logger = defaultClient.Logger for _, opt := range opts { opt(defaultClient) } + defaultClient.Registry.Logger = defaultClient.Logger defaultClient.Auth.Host = host defaultClient.Auth.Port = port defaultClient.Auth.User = user From 7e81b0075d95fff4acc506867266ff9ef289dacb Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 23 Feb 2021 08:17:25 +0100 Subject: [PATCH 30/42] examples/v2: pass in logger to NewClient --- examples/v2/main.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/examples/v2/main.go b/examples/v2/main.go index 159969e6..4112dec9 100644 --- a/examples/v2/main.go +++ b/examples/v2/main.go @@ -18,17 +18,19 @@ import ( func main() { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - host := "127.0.0.1" + host := "" port := "" - user := "foo" - pass := "bar" + user := "" + pass := "" - cl := bmclib.NewClient(host, port, user, pass) l := logrus.New() - l.Level = logrus.TraceLevel - cl.Logger = logrusr.NewLogger(l) + l.Level = logrus.DebugLevel + logger := logrusr.NewLogger(l) - err := cl.Open(ctx) + var err error + + cl := bmclib.NewClient(host, port, user, pass, bmclib.WithLogger(logger)) + err = cl.Open(ctx) if err != nil { log.Fatal(err, "bmc login failed") } @@ -42,4 +44,16 @@ func main() { fmt.Println("BMC version: " + v) + // open file handle + fh, err := os.Open("/tmp/E3C246D4I-NL_L0.03.00.ima") + if err != nil { + log.Fatal(err) + } + defer fh.Close() + + err = cl.UpdateBMCFirmware(ctx, fh) + if err != nil { + log.Fatal(err) + } + } From f574d212e0200df79bf6229f27a73ee541f221da Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 23 Feb 2021 09:20:45 +0100 Subject: [PATCH 31/42] bmc: update firmware interface to accept an io.Reader --- bmc/firmware.go | 21 +++++++++++---------- bmc/firmware_test.go | 14 ++++++++------ client.go | 9 +++++---- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/bmc/firmware.go b/bmc/firmware.go index b7b198d9..ba906208 100644 --- a/bmc/firmware.go +++ b/bmc/firmware.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "io" "github.com/hashicorp/go-multierror" ) @@ -15,7 +16,7 @@ type BMCVersionGetter interface { // BMCFirmwareUpdater upgrades the BMC firmware type BMCFirmwareUpdater interface { - FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) + FirmwareUpdateBMC(ctx context.Context, fileReader io.Reader) (err error) } // BIOSVersionGetter retrieves the current BIOS firmware version information @@ -25,7 +26,7 @@ type BIOSVersionGetter interface { // BIOSFirmwareUpdater upgrades the BIOS firmware type BIOSFirmwareUpdater interface { - FirmwareUpdateBIOS(ctx context.Context, fileName string) (err error) + FirmwareUpdateBIOS(ctx context.Context, fileReader io.Reader) (err error) } // GetBMCVersion returns the BMC firmware version, trying all interface implementations passed in @@ -71,7 +72,7 @@ func GetBMCVersionFromInterfaces(ctx context.Context, generic []interface{}) (ve } // UpdateBMCFirmware upgrades the BMC firmware, trying all interface implementations passed ini -func UpdateBMCFirmware(ctx context.Context, updateFileName string, p []BMCFirmwareUpdater) (err error) { +func UpdateBMCFirmware(ctx context.Context, fileReader io.Reader, p []BMCFirmwareUpdater) (err error) { Loop: for _, elem := range p { select { @@ -80,7 +81,7 @@ Loop: break Loop default: if elem != nil { - uErr := elem.FirmwareUpdateBMC(ctx, updateFileName) + uErr := elem.FirmwareUpdateBMC(ctx, fileReader) if uErr != nil { err = multierror.Append(err, uErr) continue @@ -95,7 +96,7 @@ Loop: } // UpdateBMCFirmwareFromInterfaces pass through to library function -func UpdateBMCFirmwareFromInterfaces(ctx context.Context, updateFileName string, generic []interface{}) (err error) { +func UpdateBMCFirmwareFromInterfaces(ctx context.Context, fileReader io.Reader, generic []interface{}) (err error) { bmcFirmwareUpdater := make([]BMCFirmwareUpdater, 0) for _, elem := range generic { switch p := elem.(type) { @@ -110,7 +111,7 @@ func UpdateBMCFirmwareFromInterfaces(ctx context.Context, updateFileName string, return multierror.Append(err, errors.New("no BMCFirmwareUpdater implementations found")) } - return UpdateBMCFirmware(ctx, updateFileName, bmcFirmwareUpdater) + return UpdateBMCFirmware(ctx, fileReader, bmcFirmwareUpdater) } // GetBIOSVersion returns the BMC firmware version, trying all interface implementations passed in @@ -156,7 +157,7 @@ func GetBIOSVersionFromInterfaces(ctx context.Context, generic []interface{}) (v } // UpdateBIOSFirmware upgrades the BIOS firmware, trying all interface implementations passed ini -func UpdateBIOSFirmware(ctx context.Context, updateFileName string, p []BIOSFirmwareUpdater) (err error) { +func UpdateBIOSFirmware(ctx context.Context, fileReader io.Reader, p []BIOSFirmwareUpdater) (err error) { Loop: for _, elem := range p { select { @@ -165,7 +166,7 @@ Loop: break Loop default: if elem != nil { - uErr := elem.FirmwareUpdateBIOS(ctx, updateFileName) + uErr := elem.FirmwareUpdateBIOS(ctx, fileReader) if uErr != nil { err = multierror.Append(err, uErr) continue @@ -180,7 +181,7 @@ Loop: } // GetBMCVersionFromInterfaces pass through to library function -func UpdateBIOSFirmwareFromInterfaces(ctx context.Context, updateFileName string, generic []interface{}) (err error) { +func UpdateBIOSFirmwareFromInterfaces(ctx context.Context, fileReader io.Reader, generic []interface{}) (err error) { biosFirmwareUpdater := make([]BIOSFirmwareUpdater, 0) for _, elem := range generic { switch p := elem.(type) { @@ -195,5 +196,5 @@ func UpdateBIOSFirmwareFromInterfaces(ctx context.Context, updateFileName string return multierror.Append(err, errors.New("no BIOSFirmwareUpdater implementations found")) } - return UpdateBIOSFirmware(ctx, updateFileName, biosFirmwareUpdater) + return UpdateBIOSFirmware(ctx, fileReader, biosFirmwareUpdater) } diff --git a/bmc/firmware_test.go b/bmc/firmware_test.go index 54f2b579..b5459d16 100644 --- a/bmc/firmware_test.go +++ b/bmc/firmware_test.go @@ -1,8 +1,10 @@ package bmc import ( + "bytes" "context" "errors" + "io" "testing" "time" @@ -25,7 +27,7 @@ func (f *firmwareTester) GetBMCVersion(ctx context.Context) (version string, err return "1.33.7", nil } -func (f *firmwareTester) FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) { +func (f *firmwareTester) FirmwareUpdateBMC(ctx context.Context, fileReader io.Reader) (err error) { if f.MakeErrorOut { return errors.New("failed update") } @@ -33,7 +35,7 @@ func (f *firmwareTester) FirmwareUpdateBMC(ctx context.Context, fileName string) return nil } -func (f *firmwareTester) FirmwareUpdateBIOS(ctx context.Context, fileName string) (err error) { +func (f *firmwareTester) FirmwareUpdateBIOS(ctx context.Context, fileReader io.Reader) (err error) { if f.MakeErrorOut { return errors.New("failed update") } @@ -154,7 +156,7 @@ func TestUpdateBMCFirmware(t *testing.T) { } ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout) defer cancel() - err := UpdateBMCFirmware(ctx, "foo", []BMCFirmwareUpdater{&testImplementation}) + err := UpdateBMCFirmware(ctx, bytes.NewReader([]byte(`foo`)), []BMCFirmwareUpdater{&testImplementation}) if err != nil { diff := cmp.Diff(tc.err.Error(), err.Error()) if diff != "" { @@ -187,7 +189,7 @@ func TestUpdateBMCFirmwareFromInterfaces(t *testing.T) { testImplementation := firmwareTester{} generic = []interface{}{&testImplementation} } - err := UpdateBMCFirmwareFromInterfaces(context.Background(), "foo", generic) + err := UpdateBMCFirmwareFromInterfaces(context.Background(), bytes.NewReader([]byte(`foo`)), generic) if err != nil { diff := cmp.Diff(tc.err.Error(), err.Error()) if diff != "" { @@ -302,7 +304,7 @@ func TestUpdateBIOSFirmware(t *testing.T) { } ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout) defer cancel() - err := UpdateBIOSFirmware(ctx, "foo", []BIOSFirmwareUpdater{&testImplementation}) + err := UpdateBIOSFirmware(ctx, bytes.NewReader([]byte(`foo`)), []BIOSFirmwareUpdater{&testImplementation}) if err != nil { diff := cmp.Diff(tc.err.Error(), err.Error()) if diff != "" { @@ -335,7 +337,7 @@ func TestUpdateBIOSFirmwareFromInterfaces(t *testing.T) { testImplementation := firmwareTester{} generic = []interface{}{&testImplementation} } - err := UpdateBIOSFirmwareFromInterfaces(context.Background(), "foo", generic) + err := UpdateBIOSFirmwareFromInterfaces(context.Background(), bytes.NewReader([]byte(`foo`)), generic) if err != nil { diff := cmp.Diff(tc.err.Error(), err.Error()) if diff != "" { diff --git a/client.go b/client.go index c0e8d6f3..3f43a12f 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,7 @@ package bmclib import ( "context" + "io" "github.com/bmc-toolbox/bmclib/bmc" "github.com/bmc-toolbox/bmclib/logging" @@ -132,8 +133,8 @@ func (c *Client) GetBMCVersion(ctx context.Context) (version string, err error) } // UpdateBMCFirmware pass through library function -func (c *Client) UpdateBMCFirmware(ctx context.Context, fileName string) (err error) { - return bmc.UpdateBMCFirmwareFromInterfaces(ctx, fileName, c.Registry.GetDriverInterfaces()) +func (c *Client) UpdateBMCFirmware(ctx context.Context, fileReader io.Reader) (err error) { + return bmc.UpdateBMCFirmwareFromInterfaces(ctx, fileReader, c.Registry.GetDriverInterfaces()) } // GetBIOSVersion pass through library function @@ -142,6 +143,6 @@ func (c *Client) GetBIOSVersion(ctx context.Context) (version string, err error) } // UpdateBIOSFirmware pass through library function -func (c *Client) UpdateBIOSFirmware(ctx context.Context, fileName string) (err error) { - return bmc.UpdateBIOSFirmwareFromInterfaces(ctx, fileName, c.Registry.GetDriverInterfaces()) +func (c *Client) UpdateBIOSFirmware(ctx context.Context, fileReader io.Reader) (err error) { + return bmc.UpdateBIOSFirmwareFromInterfaces(ctx, fileReader, c.Registry.GetDriverInterfaces()) } From 2081cd9d856fb027f33f751730126cccf5f3d7d7 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 23 Feb 2021 09:21:31 +0100 Subject: [PATCH 32/42] providers/asrockrack: accept a io.Reader interface --- providers/asrockrack/asrockrack.go | 60 +++++++++++-------------- providers/asrockrack/asrockrack_test.go | 9 +++- providers/asrockrack/helpers.go | 16 ++----- 3 files changed, 36 insertions(+), 49 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index 579dbc76..b9b40f7c 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -4,8 +4,8 @@ import ( "bytes" "context" "fmt" + "io" "net/http" - "os" "time" "github.com/bmc-toolbox/bmclib/internal/httpclient" @@ -154,7 +154,7 @@ func (a *ASRockRack) GetBMCVersion(ctx context.Context) (string, error) { // nolint: gocyclo // BMC firmware update is a multi step process // this method initiates the upgrade process and waits in a loop until the device has been upgraded -func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) error { +func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, fileReader io.Reader) error { defer func() { // The device needs to be reset to be removed from flash mode, @@ -169,39 +169,35 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err } }() - // 0. validate the given filePath exists - _, err := os.Stat(filePath) - if os.IsNotExist(err) { - return err - } + var err error // 1. set the device to flash mode - prepares the flash - a.log.V(1).Info("info", "step", "1/5 - setting device into flash mode.. this takes a minute") + a.log.V(1).Info("info", "action", "set device to flash mode, takes a minute...", "step", "1/5") err = a.setFlashMode() if err != nil { - return fmt.Errorf("failed in step 1/5 - set device in flash mode: " + err.Error()) + return fmt.Errorf("failed in step 1/5 - set device to flash mode: " + err.Error()) } // 2. upload firmware image file - a.log.V(1).Info("info", "step", "2/5 uploading firmware image", "filePath", filePath) - err = a.uploadFirmware("api/maintenance/firmware", filePath) + a.log.V(1).Info("info", "action", "upload BMC firmware image", "step", "2/5") + err = a.uploadFirmware("api/maintenance/firmware", fileReader) if err != nil { - return fmt.Errorf("failed in step 2/5 - upload firmware image: " + err.Error()) + return fmt.Errorf("failed in step 2/5 - upload BMC firmware image: " + err.Error()) } // 3. BMC to verify the uploaded file err = a.verifyUploadedFirmware() - a.log.V(1).Info("info", "step", "3/5 - bmc to verify uploaded firmware") + a.log.V(1).Info("info", "action", "BMC verify uploaded firmware", "step", "3/5") if err != nil { - return fmt.Errorf("failed in step 3/5 - verify uploaded firmware: " + err.Error()) + return fmt.Errorf("failed in step 3/5 - BMC verify uploaded firmware: " + err.Error()) } startTS := time.Now() // 4. Run the upgrade - preserving current config - a.log.V(1).Info("info", "step 4/5", "run the upgrade, preserving current configuration") + a.log.V(1).Info("info", "action", "proceed with upgrade, preserve current configuration", "step", "4/5") err = a.upgradeBMC() if err != nil { - return fmt.Errorf("failed in step 4/5 - verify uploaded firmware: " + err.Error()) + return fmt.Errorf("failed in step 4/5 - proceed with upgrade: " + err.Error()) } // progress check interval @@ -224,11 +220,11 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err continue } - a.log.V(1).Info("info", "step", "5/5 - check flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Info("info", "action", p.Action, "step", "5/5", "progress", p.Progress, "elapsed time", time.Since(startTS).String()) // all done! if p.State == 2 { - a.log.V(1).Info("info", "step", "5/5 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Info("info", "action", "flash process complete", "step", "5/5", "progress", p.Progress, "elapsed time", time.Since(startTS).String()) // The BMC resets by itself after a successful flash a.resetRequired = false // HTTP sessions are terminated once the BMC resets after an upgrade @@ -241,7 +237,7 @@ func (a *ASRockRack) FirmwareUpdateBMC(ctx context.Context, filePath string) err } } -func (a *ASRockRack) FirmwareUpdateBIOS(ctx context.Context, filePath string) error { +func (a *ASRockRack) FirmwareUpdateBIOS(ctx context.Context, fileReader io.Reader) error { defer func() { if a.resetRequired { @@ -253,32 +249,28 @@ func (a *ASRockRack) FirmwareUpdateBIOS(ctx context.Context, filePath string) er } }() - // 0. validate the given filePath exists - _, err := os.Stat(filePath) - if os.IsNotExist(err) { - return err - } + var err error // 1. upload firmware image file - a.log.V(1).Info("info", "step", "1/4 uploading firmware image", "filePath", filePath) - err = a.uploadFirmware("api/asrr/maintenance/BIOS/firmware", filePath) + a.log.V(1).Info("info", "action", "upload BIOS firmware image", "step", "1/4") + err = a.uploadFirmware("api/asrr/maintenance/BIOS/firmware", fileReader) if err != nil { return fmt.Errorf("failed in step 1/4 - upload firmware image: " + err.Error()) } // 2. set update parameters to preserve configuratin - a.log.V(1).Info("info", "step", "2/4 set preserve configuration") + a.log.V(1).Info("info", "action", "set flash configuration", "step", "2/4") err = a.biosUpgradeConfiguration() if err != nil { - return fmt.Errorf("failed in step 2/4 - set preserve configuration: " + err.Error()) + return fmt.Errorf("failed in step 2/4 - set flash configuration: " + err.Error()) } startTS := time.Now() // 3. run upgrade - a.log.V(1).Info("info", "step", "3/4 run upgrade") + a.log.V(1).Info("info", "action", "proceed with upgrade", "step", "3/4") err = a.biosUpgrade() if err != nil { - return fmt.Errorf("failed in step 3/4 - run upgrade: " + err.Error()) + return fmt.Errorf("failed in step 3/4 - proceed with upgrade: " + err.Error()) } // progress check interval @@ -297,21 +289,21 @@ func (a *ASRockRack) FirmwareUpdateBIOS(ctx context.Context, filePath string) er p, err := a.flashProgress(endpoint) if err != nil { errorsCount++ - a.log.V(1).Error(err, "step", "4/4 - error checking flash progress", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Error(err, "action", "check flash progress", "step", "4/4", "error count", errorsCount, "max errors", maxErrors, "elapsed time", time.Since(startTS).String()) continue } - a.log.V(1).Info("info", "step", "4/4 - check flash progress..", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Info("info", "action", "check flash progress", "step", "4/4", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) // all done! if p.State == 2 { - a.log.V(1).Info("info", "step", "4/4 - firmware flash complete!", "progress", p.Progress, "action", p.Action, "elapsed time", time.Since(startTS).String()) + a.log.V(1).Info("info", "action", "flash process complete", "step", "4/4", "progress", p.Progress, "elapsed time", time.Since(startTS).String()) // Reset BMC after flash a.resetRequired = true return nil } case <-timeoutT: - return fmt.Errorf("timeout in step 5/5 - flash progress, error count: %d, elapsed time: %s", errorsCount, time.Since(startTS).String()) + return fmt.Errorf("timeout in step 4/4 - flash progress, error count: %d, elapsed time: %s", errorsCount, time.Since(startTS).String()) } } diff --git a/providers/asrockrack/asrockrack_test.go b/providers/asrockrack/asrockrack_test.go index 60825cc6..d363ba49 100644 --- a/providers/asrockrack/asrockrack_test.go +++ b/providers/asrockrack/asrockrack_test.go @@ -78,8 +78,13 @@ func Test_FirwmwareUpdateBMC(t *testing.T) { t.Errorf(err.Error()) } - defer os.Remove(upgradeFile) - err = aClient.FirmwareUpdateBMC(context.TODO(), upgradeFile) + fh, err := os.Open(upgradeFile) + if err != nil { + t.Errorf(err.Error()) + } + + defer fh.Close() + err = aClient.FirmwareUpdateBMC(context.TODO(), fh) if err != nil { t.Errorf(err.Error()) } diff --git a/providers/asrockrack/helpers.go b/providers/asrockrack/helpers.go index 77c5013d..98eaab49 100644 --- a/providers/asrockrack/helpers.go +++ b/providers/asrockrack/helpers.go @@ -1,7 +1,6 @@ package asrockrack import ( - "bufio" "bytes" "encoding/json" "fmt" @@ -10,8 +9,6 @@ import ( "mime/multipart" "net/http" "net/http/httputil" - "os" - "path" "github.com/bmc-toolbox/bmclib/errors" ) @@ -83,27 +80,20 @@ func (a *ASRockRack) setFlashMode() error { } // 2 Upload the firmware file -func (a *ASRockRack) uploadFirmware(endpoint string, filePath string) error { +func (a *ASRockRack) uploadFirmware(endpoint string, fwReader io.Reader) error { // setup a buffer for our multipart form var form bytes.Buffer w := multipart.NewWriter(&form) // create form data from update image - fwWriter, err := w.CreateFormFile("fwimage", path.Base(filePath)) - if err != nil { - return err - } - - // open file handle - fh, err := os.Open(filePath) + fwWriter, err := w.CreateFormFile("fwimage", "image") if err != nil { return err } // copy file contents into form payload - fReader := bufio.NewReader(fh) - _, err = io.Copy(fwWriter, fReader) + _, err = io.Copy(fwWriter, fwReader) if err != nil { return err } From bb6568fd6e7ebff1a7795e4f3050d84e944a1281 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 23 Feb 2021 09:23:22 +0100 Subject: [PATCH 33/42] purge asrockrack references from the older discover/probe methods --- discover/discover.go | 1 - discover/discover_test.go | 5 ----- discover/probe.go | 28 ---------------------------- 3 files changed, 34 deletions(-) diff --git a/discover/discover.go b/discover/discover.go index 73d8d9e8..c01a95d3 100644 --- a/discover/discover.go +++ b/discover/discover.go @@ -64,7 +64,6 @@ func ScanAndConnect(host string, username string, password string, options ...Op ProbeM1000e: probe.m1000e, ProbeQuanta: probe.quanta, ProbeHpCl100: probe.hpCl100, - ProbeASRockRack: probe.asRockRack, } order := []string{ProbeHpIlo, diff --git a/discover/discover_test.go b/discover/discover_test.go index bf4806c1..0aa885d7 100644 --- a/discover/discover_test.go +++ b/discover/discover_test.go @@ -113,11 +113,6 @@ func TestProbes(t *testing.T) { wantHint: ProbeHpIlo, wantType: (*ilo.Ilo)(nil), }, - { - name: "ASRockRack", - wantHint: ProbeASRockRack, - wantType: nil, - }, } for _, tt := range testt { diff --git a/discover/probe.go b/discover/probe.go index 81cce646..050e09d9 100644 --- a/discover/probe.go +++ b/discover/probe.go @@ -13,7 +13,6 @@ import ( "github.com/bmc-toolbox/bmclib/devices" "github.com/bmc-toolbox/bmclib/errors" - "github.com/bmc-toolbox/bmclib/providers/asrockrack" "github.com/bmc-toolbox/bmclib/providers/dell/idrac8" "github.com/bmc-toolbox/bmclib/providers/dell/idrac9" "github.com/bmc-toolbox/bmclib/providers/dell/m1000e" @@ -333,33 +332,6 @@ func (p *Probe) quanta(ctx context.Context, log logr.Logger) (bmcConnection inte return bmcConnection, errors.ErrDeviceNotMatched } -func (p *Probe) asRockRack(ctx context.Context, log logr.Logger) (bmcConnection interface{}, err error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s", p.host), nil) - if err != nil { - return bmcConnection, err - } - resp, err := p.client.Do(req) - if err != nil { - return bmcConnection, err - } - - defer resp.Body.Close() - defer io.Copy(ioutil.Discard, resp.Body) // nolint - - payload, err := ioutil.ReadAll(resp.Body) - if err != nil { - return bmcConnection, err - } - - // ensure the response we got included a png - if resp.StatusCode == 200 && bytes.Contains(payload, []byte("ASRockRack")) { - log.V(1).Info("step", "ScanAndConnect", "host", p.host, "vendor", string(devices.ASRockRack), "msg", "it's a ASRockRack") - return asrockrack.New(ctx, p.host, p.username, p.password, log) - } - - return bmcConnection, errors.ErrDeviceNotMatched -} - func containsAnySubStr(data []byte, subStrs []string) bool { for _, subStr := range subStrs { if bytes.Contains(data, []byte(subStr)) { From 3bb9a044c6025e7dd0e1321325dab4b9ef796711 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 23 Feb 2021 09:24:22 +0100 Subject: [PATCH 34/42] examples/v2: update to include the BMC FW flash example --- examples/v2/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/v2/main.go b/examples/v2/main.go index 4112dec9..1ab86c55 100644 --- a/examples/v2/main.go +++ b/examples/v2/main.go @@ -1,13 +1,14 @@ package main /* - This utilizes the 'v2' bmclib interface methods + This utilizes the 'v2' bmclib interface methods to flash a firmware image */ import ( "context" "fmt" "log" + "os" "time" "github.com/bmc-toolbox/bmclib" From 229dca961a06b88cda57bf0b24348474833172cb Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 8 Mar 2021 21:20:08 +0100 Subject: [PATCH 35/42] examples: fix example versions --- examples/pre.v1/main.go | 58 +++++++++++++++++++++++++++++++++++++++++ examples/v1/main.go | 52 ++++++++++++++++++------------------ 2 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 examples/pre.v1/main.go diff --git a/examples/pre.v1/main.go b/examples/pre.v1/main.go new file mode 100644 index 00000000..d5f024ff --- /dev/null +++ b/examples/pre.v1/main.go @@ -0,0 +1,58 @@ +package main + +// This snippet utilizes the older bmclib interface methods +// it connects to the bmc and retries its version + +import ( + "context" + "fmt" + "os" + + "github.com/bmc-toolbox/bmclib/devices" + "github.com/bmc-toolbox/bmclib/discover" + "github.com/bombsimon/logrusr" + "github.com/sirupsen/logrus" +) + +func main() { + //ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx := context.TODO() + //defer cancel() + host := "" + user := "" + pass := "" + + l := logrus.New() + l.Level = logrus.TraceLevel + logger := logrusr.NewLogger(l) + + c, err := discover.ScanAndConnect( + host, + user, + pass, + discover.WithContext(ctx), + discover.WithLogger(logger), + ) + + if err != nil { + logger.Error(err, "Error connecting to bmc") + } + + bmc := c.(devices.Bmc) + + err = bmc.CheckCredentials() + if err != nil { + logger.Error(err, "Failed to validate credentials") + os.Exit(1) + } + + defer bmc.Close(ctx) + + s, err := bmc.Serial() + if err != nil { + logger.Error(err, "Error getting bmc serial") + os.Exit(1) + } + fmt.Println(s) + +} diff --git a/examples/v1/main.go b/examples/v1/main.go index 1f129750..ee205a92 100644 --- a/examples/v1/main.go +++ b/examples/v1/main.go @@ -1,58 +1,60 @@ package main -// This snippet utilizes the 'v1' older bmclib interface methods -// it connects to the bmc and retries its version +/* + This utilizes what is to tbe the 'v1' bmclib interface methods to flash a firmware image +*/ import ( "context" "fmt" + "log" "os" + "time" - "github.com/bmc-toolbox/bmclib/devices" - "github.com/bmc-toolbox/bmclib/discover" + "github.com/bmc-toolbox/bmclib" "github.com/bombsimon/logrusr" "github.com/sirupsen/logrus" ) func main() { - //ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - ctx := context.TODO() - //defer cancel() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() host := "" + port := "" user := "" pass := "" l := logrus.New() - l.Level = logrus.TraceLevel + l.Level = logrus.DebugLevel logger := logrusr.NewLogger(l) - c, err := discover.ScanAndConnect( - host, - user, - pass, - discover.WithContext(ctx), - discover.WithLogger(logger), - ) + var err error + cl := bmclib.NewClient(host, port, user, pass, bmclib.WithLogger(logger)) + err = cl.Open(ctx) if err != nil { - logger.Error(err, "Error connecting to bmc") + log.Fatal(err, "bmc login failed") } - bmc := c.(devices.Bmc) + defer cl.Close(ctx) - err = bmc.CheckCredentials() + v, err := cl.GetBMCVersion(ctx) if err != nil { - logger.Error(err, "Failed to validate credentials") - os.Exit(1) + log.Fatal(err, "unable to retrieve BMC version") } - defer bmc.Close(ctx) + fmt.Println("BMC version: " + v) - s, err := bmc.Serial() + // open file handle + fh, err := os.Open("/tmp/E3C246D4I-NL_L0.03.00.ima") if err != nil { - logger.Error(err, "Error getting bmc serial") - os.Exit(1) + log.Fatal(err) + } + defer fh.Close() + + err = cl.UpdateBMCFirmware(ctx, fh) + if err != nil { + log.Fatal(err) } - fmt.Println(s) } From c0c4dfc295b720cfa16dab2de743c67fee9f2527 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 8 Mar 2021 21:28:59 +0100 Subject: [PATCH 36/42] providers/asrockrack: purge unused consts --- providers/asrockrack/asrockrack.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index b9b40f7c..c7760d8b 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -15,10 +15,6 @@ import ( ) const ( - // BmcType defines the bmc model that is supported by this package - BmcType = "asrockrack" - // VendorID represents the id of the vendor across all packages - VendorID = "ASRockRack" // ProviderName for the provider implementation ProviderName = "asrockrack" // ProviderProtocol for the provider implementation From 56ed33d5581548c72d8bbebb7700a315ca62d8aa Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 8 Mar 2021 21:30:39 +0100 Subject: [PATCH 37/42] go mod tidy --- go.mod | 1 - go.sum | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 8f35542c..78ae11e3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.15 require ( bou.ke/monkey v1.0.2 github.com/bombsimon/logrusr v1.0.0 - github.com/davecgh/go-spew v1.1.1 github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-logr/logr v0.4.0 github.com/go-logr/zapr v0.4.0 // indirect diff --git a/go.sum b/go.sum index bcf361d3..5b9c11a1 100644 --- a/go.sum +++ b/go.sum @@ -137,10 +137,13 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls= github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -153,6 +156,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -160,11 +164,14 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -182,26 +189,36 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg= github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -211,13 +228,16 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -225,6 +245,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -239,6 +260,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -258,6 +280,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -285,13 +308,16 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -313,8 +339,10 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -340,11 +368,15 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -352,10 +384,13 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From a514cb6e3cea2cbab3efb416faa57da7d65c306b Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 8 Mar 2021 21:37:34 +0100 Subject: [PATCH 38/42] client: fix misalligned comment --- client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.go b/client.go index 3f43a12f..5c86ba62 100644 --- a/client.go +++ b/client.go @@ -71,7 +71,7 @@ func (c *Client) registerProviders() { driverIpmitool := &ipmitool.Conn{Host: c.Auth.Host, Port: c.Auth.Port, User: c.Auth.User, Pass: c.Auth.Pass, Log: c.Logger} c.Registry.Register(ipmitool.ProviderName, ipmitool.ProviderProtocol, ipmitool.Features, nil, driverIpmitool) - // register ASRR vendorapi provider + // register ASRR vendorapi provider driverAsrockrack, _ := asrockrack.New(context.TODO(), c.Auth.Host, c.Auth.User, c.Auth.Pass, c.Logger) c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, driverAsrockrack) From bb18bfe4b7e4db2d0a60b6e57245f4abad3c54f4 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Mar 2021 08:25:58 +0100 Subject: [PATCH 39/42] providers/asrockrack: purge unused context from struct --- providers/asrockrack/asrockrack.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index c7760d8b..44195a00 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -41,7 +41,6 @@ type ASRockRack struct { fwInfo *firmwareInfo resetRequired bool // Indicates if the BMC requires a reset skipLogout bool // A Close() / httpsLogout() request is ignored if the BMC was just flashed - since the sessions are terminated either way - ctx context.Context log logr.Logger } @@ -57,7 +56,6 @@ func New(ctx context.Context, ip string, username string, password string, log l ip: ip, username: username, password: password, - ctx: ctx, log: log, loginSession: &loginSession{}, httpClient: client, From 09da9d44db2991b7b8f896f1ef063aa7b589394e Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 9 Mar 2021 08:27:47 +0100 Subject: [PATCH 40/42] devices/interfaces: purge older Firmware interface that crept back in after rebase --- devices/interfaces.go | 9 --------- providers/supermicro/supermicrox11/supermicrox_test.go | 1 - 2 files changed, 10 deletions(-) diff --git a/devices/interfaces.go b/devices/interfaces.go index b628dd8c..26ceb0a7 100644 --- a/devices/interfaces.go +++ b/devices/interfaces.go @@ -15,9 +15,6 @@ type Bmc interface { // BmcCollection interface BmcCollection - // Firmware getter/updater interface - Firmware - CheckCredentials() error Close(context.Context) error PowerOn() (bool, error) // PowerSetter @@ -137,9 +134,3 @@ type Configure interface { GenerateCSR(*cfgresources.HTTPSCertAttributes) ([]byte, error) UploadHTTPSCert([]byte, string, []byte, string) (bool, error) } - -type Firmware interface { - GetBIOSVersion(context.Context) (version string, err error) - GetBMCVersion(context.Context) (version string, err error) - FirmwareUpdateBMC(ctx context.Context, fileName string) (err error) -} diff --git a/providers/supermicro/supermicrox11/supermicrox_test.go b/providers/supermicro/supermicrox11/supermicrox_test.go index 75d3b042..eeb7094c 100644 --- a/providers/supermicro/supermicrox11/supermicrox_test.go +++ b/providers/supermicro/supermicrox11/supermicrox_test.go @@ -597,7 +597,6 @@ func TestIBmcInterface(t *testing.T) { } _ = devices.Bmc(bmc) _ = devices.Configure(bmc) - _ = devices.Firmware(bmc) tearDown() } From 3a22d5e10246e46c56bd0a1d383a50fb6a168131 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Sun, 21 Mar 2021 19:43:09 +0100 Subject: [PATCH 41/42] client, providers/asrockrack: purge unused context variable --- client.go | 2 +- providers/asrockrack/asrockrack.go | 2 +- providers/asrockrack/mock_test.go | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 5c86ba62..21fcf286 100644 --- a/client.go +++ b/client.go @@ -72,7 +72,7 @@ func (c *Client) registerProviders() { c.Registry.Register(ipmitool.ProviderName, ipmitool.ProviderProtocol, ipmitool.Features, nil, driverIpmitool) // register ASRR vendorapi provider - driverAsrockrack, _ := asrockrack.New(context.TODO(), c.Auth.Host, c.Auth.User, c.Auth.Pass, c.Logger) + driverAsrockrack, _ := asrockrack.New(c.Auth.Host, c.Auth.User, c.Auth.Pass, c.Logger) c.Registry.Register(asrockrack.ProviderName, asrockrack.ProviderProtocol, asrockrack.Features, nil, driverAsrockrack) } diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index 44195a00..bf2de6d8 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -45,7 +45,7 @@ type ASRockRack struct { } // New returns a new ASRockRack instance ready to be used -func New(ctx context.Context, ip string, username string, password string, log logr.Logger) (*ASRockRack, error) { +func New(ip string, username string, password string, log logr.Logger) (*ASRockRack, error) { client, err := httpclient.Build() if err != nil { diff --git a/providers/asrockrack/mock_test.go b/providers/asrockrack/mock_test.go index 4fa02a59..28a1d89b 100644 --- a/providers/asrockrack/mock_test.go +++ b/providers/asrockrack/mock_test.go @@ -2,7 +2,6 @@ package asrockrack import ( "bytes" - "context" "encoding/json" "fmt" "io/ioutil" @@ -56,7 +55,7 @@ func TestMain(m *testing.M) { l.Level = logrus.DebugLevel // setup bmc client tLog := logrusr.NewLogger(l) - aClient, err = New(context.TODO(), bmcURL.Host, "foo", "bar", tLog) + aClient, err = New(bmcURL.Host, "foo", "bar", tLog) if err != nil { log.Fatal(err.Error()) } From 8c2ffa991d54755328cf4b018a31f1024bcaec82 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Sun, 21 Mar 2021 19:43:54 +0100 Subject: [PATCH 42/42] providers/asrockrack: fix redundant error checks --- providers/asrockrack/asrockrack.go | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/providers/asrockrack/asrockrack.go b/providers/asrockrack/asrockrack.go index bf2de6d8..ad897dd3 100644 --- a/providers/asrockrack/asrockrack.go +++ b/providers/asrockrack/asrockrack.go @@ -75,22 +75,12 @@ func (a *ASRockRack) Compatible() bool { return false } - if bytes.Contains(resp, []byte(`ASRockRack`)) { - return true - } - - return false + return bytes.Contains(resp, []byte(`ASRockRack`)) } // Open a connection to a BMC, implements the Opener interface func (a *ASRockRack) Open(ctx context.Context) (err error) { - - err = a.httpsLogin() - if err != nil { - return err - } - - return nil + return a.httpsLogin() } // Close a connection to a BMC, implements the Closer interface @@ -100,21 +90,12 @@ func (a *ASRockRack) Close(ctx context.Context) (err error) { return nil } - err = a.httpsLogout() - if err != nil { - return err - } - - return nil + return a.httpsLogout() } // CheckCredentials verify whether the credentials are valid or not func (a *ASRockRack) CheckCredentials() (err error) { - err = a.httpsLogin() - if err != nil { - return err - } - return err + return a.httpsLogin() } // BiosVersion returns the BIOS version from the BMC