-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #336 from bmc-toolbox/firmwaresmc
Supermicro X11 BIOS, BMC firmware install support
- Loading branch information
Showing
12 changed files
with
1,780 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,58 @@ | ||
/* | ||
install-firmware is an example commmand that utilizes the 'v1' bmclib interface | ||
install-firmware is an example command that utilizes the 'v1' bmclib interface | ||
methods to flash a firmware image to a BMC. | ||
$ go run ./examples/v1/install-firmware/main.go -h | ||
Usage of /tmp/go-build2950657412/b001/exe/main: | ||
-cert-pool string | ||
Path to an file containing x509 CAs. An empty string uses the system CAs. Only takes effect when --secure-tls=true | ||
-firmware string | ||
The local path of the firmware to install | ||
-host string | ||
BMC hostname to connect to | ||
-password string | ||
Username to login with | ||
-port int | ||
BMC port to connect to (default 443) | ||
-secure-tls | ||
Enable secure TLS | ||
-user string | ||
Username to login with | ||
-version string | ||
The firmware version being installed | ||
Note: The example installs the firmware and polls until the status until the install is complete, | ||
and if required by the install process - power cycles the host. | ||
$ go run ./examples/v1/install-firmware/main.go -h | ||
Usage of /tmp/go-build2950657412/b001/exe/main: | ||
-cert-pool string | ||
Path to an file containing x509 CAs. An empty string uses the system CAs. Only takes effect when -secure-tls=true | ||
-firmware string | ||
The local path of the firmware to install | ||
-host string | ||
BMC hostname to connect to | ||
-password string | ||
Username to login with | ||
-port int | ||
BMC port to connect to (default 443) | ||
-secure-tls | ||
Enable secure TLS | ||
-user string | ||
Username to login with | ||
-version string | ||
The firmware version being installed | ||
# install bios firmware on a supermicro X11 | ||
# | ||
$ go run . -host 192.168.1.1 -user ADMIN -password hunter2 -component bios -firmware BIOS_X11DPH-0981_20220208_3.6_STD.bin | ||
INFO[0007] set firmware install mode component=BIOS ip="https://192.168.1.1" model=X11DPH-T | ||
INFO[0011] uploading firmware component=BIOS ip="https://192.168.1.1" model=X11DPH-T | ||
INFO[0091] verifying uploaded firmware component=BIOS ip="https://192.168.1.1" model=X11DPH-T | ||
INFO[0105] initiating firmware install component=BIOS ip="https://192.168.1.1" model=X11DPH-T | ||
INFO[0115] firmware install running component=bios state=running | ||
INFO[0132] firmware install running component=bios state=running | ||
... | ||
... | ||
INFO[0628] firmware install running component=bios state=running | ||
INFO[0635] host powercycle required component=bios state=powercycle-host | ||
INFO[0637] host power cycled, all done! component=bios state=powercycle-host | ||
# install bmc firmware on a supermicro X11 | ||
# | ||
$ go run . -host 192.168.1.1 -user ADMIN -password hunter2 -component bmc -firmware BMC_X11AST2500-4101MS_20220225_01.74.02_STD.bin | ||
INFO[0007] setting device to firmware install mode component=BMC ip="https://192.168.1.1" | ||
INFO[0009] uploading firmware ip="https://192.168.1.1" | ||
INFO[0045] verifying uploaded firmware ip="https://192.168.1.1" | ||
INFO[0047] initiating firmware install ip="https://192.168.1.1" | ||
INFO[0079] firmware install running component=bmc state=running | ||
INFO[0085] firmware install running component=bmc state=running | ||
... | ||
... | ||
INFO[0233] firmware install running component=bmc state=running | ||
INFO[0238] firmware install completed component=bmc state=complete | ||
*/ | ||
package main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package supermicro | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
var ( | ||
ErrQueryFRUInfo = errors.New("FRU information query returned error") | ||
) | ||
|
||
type UnexpectedResponseError struct { | ||
payload string | ||
response string | ||
statusCode string | ||
} | ||
|
||
func (e *UnexpectedResponseError) Error() string { | ||
return fmt.Sprintf( | ||
"unexpected response - statusCode: %s, payload: %s, response: %s", | ||
e.statusCode, | ||
e.payload, | ||
e.response, | ||
) | ||
} | ||
|
||
func unexpectedResponseErr(payload, response []byte, statusCode int) error { | ||
return &UnexpectedResponseError{ | ||
string(payload), | ||
string(response), | ||
strconv.Itoa(statusCode), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package supermicro | ||
|
||
import ( | ||
"context" | ||
"io" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors" | ||
"github.com/bmc-toolbox/common" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// FirmwareInstall uploads and initiates firmware update for the component | ||
func (c *Client) FirmwareInstall(ctx context.Context, component, applyAt string, forceInstall bool, reader io.Reader) (jobID string, err error) { | ||
if err := c.deviceSupported(ctx); err != nil { | ||
return "", errors.Wrap(bmclibErrs.ErrFirmwareInstall, err.Error()) | ||
} | ||
|
||
var size int64 | ||
if file, ok := reader.(*os.File); ok { | ||
finfo, err := file.Stat() | ||
if err != nil { | ||
c.log.V(2).Error(err, "unable to determine file size") | ||
} | ||
|
||
size = finfo.Size() | ||
} | ||
|
||
// expect atleast 30 minutes left in the deadline to proceed with the update | ||
d, _ := ctx.Deadline() | ||
if time.Until(d) < 30*time.Minute { | ||
return "", errors.New("remaining context deadline insufficient to perform update: " + time.Until(d).String()) | ||
} | ||
|
||
component = strings.ToUpper(component) | ||
|
||
switch component { | ||
case common.SlugBIOS: | ||
err = c.firmwareInstallBIOS(ctx, reader, size) | ||
case common.SlugBMC: | ||
err = c.firmwareInstallBMC(ctx, reader, size) | ||
default: | ||
return "", errors.Wrap(bmclibErrs.ErrFirmwareInstall, "component unsupported: "+component) | ||
} | ||
|
||
if err != nil { | ||
err = errors.Wrap(bmclibErrs.ErrFirmwareInstall, err.Error()) | ||
} | ||
|
||
return jobID, err | ||
} | ||
|
||
// FirmwareInstallStatus returns the status of the firmware install process | ||
func (c *Client) FirmwareInstallStatus(ctx context.Context, installVersion, component, taskID string) (string, error) { | ||
component = strings.ToUpper(component) | ||
|
||
switch component { | ||
case common.SlugBMC: | ||
return c.statusBMCFirmwareInstall(ctx) | ||
case common.SlugBIOS: | ||
return c.statusBIOSFirmwareInstall(ctx) | ||
default: | ||
return "", errors.Wrap(bmclibErrs.ErrFirmwareInstallStatus, "component unsupported: "+component) | ||
} | ||
} | ||
|
||
func (c *Client) deviceSupported(ctx context.Context) error { | ||
errBoardPartNumUnknown := errors.New("baseboard part number unknown") | ||
errBoardUnsupported := errors.New("feature not supported/implemented for device") | ||
|
||
// Its likely this works on all X11's | ||
// for now, we list only the ones its been tested on. | ||
// | ||
// board part numbers | ||
// | ||
supported := []string{ | ||
"X11SCM-F", | ||
"X11DPH-T", | ||
} | ||
|
||
data, err := c.fruInfo(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if data.Board == nil || strings.TrimSpace(data.Board.PartNum) == "" { | ||
return errors.Wrap(errBoardPartNumUnknown, "baseboard part number empty") | ||
} | ||
|
||
c.model = strings.TrimSpace(data.Board.PartNum) | ||
|
||
for _, b := range supported { | ||
if strings.EqualFold(b, strings.TrimSpace(data.Board.PartNum)) { | ||
return nil | ||
} | ||
} | ||
|
||
return errors.Wrap(errBoardUnsupported, data.Board.PartNum) | ||
} |
Oops, something went wrong.