Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dell #72

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
More progress
majst01 committed Nov 20, 2024
commit 9fa30f187938564cdd70855e3b211cbf0ca1cd37
5 changes: 4 additions & 1 deletion cli/board.go
Original file line number Diff line number Diff line change
@@ -13,7 +13,10 @@ var boardCmd = &cli.Command{
if err != nil {
return err
}
board := c.Board()
board, err := c.Board()
if err != nil {
return err
}
log.Infow("board", "bandtype", bandtype, "host", host, "result", board.String(), "redfish version", board.RedfishVersion, "bios", board.BiosVersion, "powermetric", board.PowerMetric, "powersupplies", board.PowerSupplies, "ledstate", board.IndicatorLED)
bmc, err := outBandBMCConnection.BMC()
if err != nil {
15 changes: 12 additions & 3 deletions cli/led.go
Original file line number Diff line number Diff line change
@@ -14,7 +14,10 @@ var ledCmd = &cli.Command{
if err != nil {
return err
}
board := c.Board()
board, err := c.Board()
if err != nil {
return err
}
log.Infow("lead", "state", board.IndicatorLED)
return nil
},
@@ -33,7 +36,10 @@ var ledCmd = &cli.Command{
return err
}
log.Infow("led state set to on")
board := c.Board()
board, err := c.Board()
if err != nil {
return err
}
log.Infow("lead", "state", board.IndicatorLED)
return nil
},
@@ -52,7 +58,10 @@ var ledCmd = &cli.Command{
return err
}
log.Infow("led state set to off")
board := c.Board()
board, err := c.Board()
if err != nil {
return err
}
log.Infow("lead", "state", board.IndicatorLED)
return nil
},
8 changes: 6 additions & 2 deletions cli/main.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import (
"fmt"
"log/slog"
"os"

"github.com/metal-stack/go-hal"
@@ -19,6 +20,7 @@
password string
host string
port int
debug bool

Check failure on line 23 in cli/main.go

GitHub Actions / build

var `debug` is unused (unused)

bandtypeFlag = &cli.StringFlag{
Name: "bandtype",
@@ -61,8 +63,7 @@
)

func main() {
log = logger.New()

log = logger.NewSlog(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})))
app := &cli.App{
Name: "hal",
Usage: "try bmc commands",
@@ -72,8 +73,11 @@
ledCmd,
powerCmd,
},
Flags: flags,
}

log.Infow("go hal cli", "host", host, "port", port, "password", password, "bandtype", bandtype)

if err := app.Run(os.Args); err != nil {
panic(err)
}
10 changes: 7 additions & 3 deletions connect/connect.go
Original file line number Diff line number Diff line change
@@ -47,13 +47,17 @@ func OutBand(ip string, ipmiPort int, user, password string, log logger.Logger)
if err != nil {
return nil, fmt.Errorf("unable to establish redfish connection for ip:%s user:%s error:%w", ip, user, err)
}
b, err := r.BoardInfo()
vendor, vendorString, modelString, err := r.VendorAndModel()
if err != nil {
return nil, fmt.Errorf("unable to get board info via redfish for ip:%s user:%s error:%w", ip, user, err)
}
b.Vendor = api.GuessVendor(b.VendorString)
b := &api.Board{
VendorString: vendorString,
Vendor: vendor,
Model: modelString,
}
log.Debugw("connect", "board", b)
switch b.Vendor {
switch vendor {
case api.VendorLenovo:
return lenovo.OutBand(r, b), nil
case api.VendorSupermicro, api.VendorNovarion:
6 changes: 3 additions & 3 deletions hal.go
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ func GuessPowerState(powerState string) PowerState {

type Hal interface {
// Board return board information of the current connection
Board() *api.Board
Board() (*api.Board, error)

// UUID get the machine UUID
// current usage in metal-hammer
@@ -127,7 +127,7 @@ type Hal interface {
// InBand get and set settings from the server via the inband interface.
type InBand interface {
// Board return board information of the current connection
Board() *api.Board
Board() (*api.Board, error)

// UUID get the machine UUID
// current usage in metal-hammer
@@ -178,7 +178,7 @@ type InBand interface {
// OutBand get and set settings from the server via the out of band interface.
type OutBand interface {
// Board return board information of the current connection
Board() *api.Board
Board() (*api.Board, error)
// UUID get the machine uuid
// current usage in ipmi-catcher
UUID() (*uuid.UUID, error)
4 changes: 2 additions & 2 deletions internal/inband/inband.go
Original file line number Diff line number Diff line change
@@ -41,8 +41,8 @@ func New(board *api.Board, inspectBMC bool, log logger.Logger) (*InBand, error)
}, nil
}

func (ib *InBand) Board() *api.Board {
return ib.board
func (ib *InBand) Board() (*api.Board, error) {
return ib.board, nil
}

func (ib *InBand) UUID() (*uuid.UUID, error) {
5 changes: 2 additions & 3 deletions internal/outband/outband.go
Original file line number Diff line number Diff line change
@@ -29,7 +29,6 @@ func New(r *redfish.APIClient, ipmiTool ipmi.IpmiTool, board *api.Board, ip stri
return &OutBand{
Redfish: r,
IpmiTool: ipmiTool,
board: board,
Ip: ip,
ipmiPort: ipmiPort,
user: user,
@@ -48,8 +47,8 @@ func ViaGoipmi(board *api.Board, ip string, ipmiPort int, user, password string)
}
}

func (ob *OutBand) Board() *api.Board {
return ob.board
func (ob *OutBand) Board() (*api.Board, error) {
return ob.Redfish.BoardInfo()
}

func (ob *OutBand) IPMIConnection() (string, int, string, string) {
32 changes: 32 additions & 0 deletions internal/redfish/redfish.go
Original file line number Diff line number Diff line change
@@ -55,6 +55,38 @@
}, nil
}

func (c *APIClient) VendorAndModel() (api.Vendor, string, string, error) {
manufacturer := ""
model := ""
vendor := api.VendorUnknown
// Query the chassis data using the session token
if c.Gofish.Service == nil {
return vendor, manufacturer, model, fmt.Errorf("gofish service root is not available most likely due to missing username")
}

systems, err := c.Gofish.Service.Systems()
if err != nil {
c.log.Warnw("ignore system query", "error", err.Error())
}
for _, system := range systems {
if system.Manufacturer != "" {
manufacturer = system.Manufacturer
}
if system.Model != "" {
model = system.Model
}
if manufacturer != "" && model != "" {
break
}
}
if manufacturer == "" || model == "" {
return vendor, manufacturer, model, fmt.Errorf("unable to detect vendor and model")
}

vendor = api.GuessVendor(manufacturer)
return vendor, manufacturer, model, nil
}

func (c *APIClient) BoardInfo() (*api.Board, error) {
// Query the chassis data using the session token
if c.Gofish.Service == nil {
@@ -380,7 +412,7 @@
case hal.IdentifyLEDStateUnknown:
return fmt.Errorf("unknown LED state:%s", state)
}
resp, err := c.Gofish.Patch("/redfish/v1/Chassis/System.Embedded.1", payload)

Check failure on line 415 in internal/redfish/redfish.go

GitHub Actions / build

response body must be closed (bodyclose)
if err != nil {
c.log.Errorw("unable to set led", "error", err)
}
@@ -391,14 +423,14 @@

func (c *APIClient) GetIdentifyLED() (hal.IdentifyLEDState, error) {

resp, err := c.Gofish.Get("/redfish/v1/Chassis/System.Embedded.1")

Check failure on line 426 in internal/redfish/redfish.go

GitHub Actions / build

response body must be closed (bodyclose)
if err != nil {
c.log.Errorw("unable to get led", "error", err)
return hal.IdentifyLEDStateUnknown, err
}
c.log.Infow("set led", "response", resp.Body)
var ledstate map[string]string
err = json.NewDecoder(resp.Body).Decode(ledstate)

Check failure on line 433 in internal/redfish/redfish.go

GitHub Actions / build

unmarshal: call of Decode passes non-pointer (govet)
if err != nil {
c.log.Errorw("unable to parse led state", "error", err)
return hal.IdentifyLEDStateUnknown, err
6 changes: 5 additions & 1 deletion internal/vendors/lenovo/lenovo.go
Original file line number Diff line number Diff line change
@@ -144,7 +144,11 @@ func (c *bmcConnection) Present() bool {
}

func (c *bmcConnection) CreateUserAndPassword(user api.BMCUser, privilege api.IpmiPrivilege) (string, error) {
return c.IpmiTool.CreateUser(user, privilege, "", c.Board().Vendor.PasswordConstraints(), ipmi.LowLevel)
board, err := c.Board()
if err != nil {
return "", err
}
return c.IpmiTool.CreateUser(user, privilege, "", board.Vendor.PasswordConstraints(), ipmi.LowLevel)
}

func (c *bmcConnection) CreateUser(user api.BMCUser, privilege api.IpmiPrivilege, password string) error {
6 changes: 5 additions & 1 deletion internal/vendors/supermicro/supermicro.go
Original file line number Diff line number Diff line change
@@ -165,7 +165,11 @@ func (c *bmcConnection) Present() bool {
}

func (c *bmcConnection) CreateUserAndPassword(user api.BMCUser, privilege api.IpmiPrivilege) (string, error) {
return c.IpmiTool.CreateUser(user, privilege, "", c.Board().Vendor.PasswordConstraints(), ipmi.HighLevel)
board, err := c.Board()
if err != nil {
return "", err
}
return c.IpmiTool.CreateUser(user, privilege, "", board.Vendor.PasswordConstraints(), ipmi.HighLevel)
}

func (c *bmcConnection) CreateUser(user api.BMCUser, privilege api.IpmiPrivilege, password string) error {
2 changes: 1 addition & 1 deletion pkg/logger/logger.go
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ func New() Logger {
return halslog.New(log)
}

// NewSlog returns an zap instance of logger
// NewSlog returns an slog instance of logger
func NewSlog(logger *slog.Logger) Logger {
return halslog.New(logger)
}

Unchanged files with check annotations Beta

if err != nil {
return err
}
retry.Do(func() error {

Check failure on line 41 in cli/power.go

GitHub Actions / build

Error return value of `retry.Do` is not checked (errcheck)
state, err := c.PowerState()
if err != nil {
return err
if err != nil {
return err
}
retry.Do(func() error {

Check failure on line 73 in cli/power.go

GitHub Actions / build

Error return value of `retry.Do` is not checked (errcheck)
state, err := c.PowerState()
if err != nil {
return err
}
func (c *Client) SetChassisIdentifyLEDState(state hal.IdentifyLEDState) error {
switch state {

Check failure on line 64 in internal/ipmi/goipmi.go

GitHub Actions / build

missing cases in switch of type hal.IdentifyLEDState: hal.IdentifyLEDStateBlinking (exhaustive)
case hal.IdentifyLEDStateOff:
return c.SetChassisIdentifyLEDOff()
case hal.IdentifyLEDStateOn:
// SetChassisIdentifyLEDState sets the chassis identify LED to given state
func (i *Ipmitool) SetChassisIdentifyLEDState(state hal.IdentifyLEDState) error {
switch state {

Check failure on line 490 in internal/ipmi/ipmitool.go

GitHub Actions / build

missing cases in switch of type hal.IdentifyLEDState: hal.IdentifyLEDStateBlinking (exhaustive)
case hal.IdentifyLEDStateOn:
return i.SetChassisIdentifyLEDOn()
case hal.IdentifyLEDStateOff: