diff --git a/cli/board.go b/cli/board.go index 304f2ee..825f95e 100644 --- a/cli/board.go +++ b/cli/board.go @@ -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 { diff --git a/cli/led.go b/cli/led.go index 0ee4960..6e89642 100644 --- a/cli/led.go +++ b/cli/led.go @@ -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 }, diff --git a/cli/main.go b/cli/main.go index f492208..bff5eda 100644 --- a/cli/main.go +++ b/cli/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log/slog" "os" "github.com/metal-stack/go-hal" @@ -19,6 +20,7 @@ var ( password string host string port int + debug bool bandtypeFlag = &cli.StringFlag{ Name: "bandtype", @@ -61,8 +63,7 @@ var ( ) 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 @@ func main() { 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) } diff --git a/connect/connect.go b/connect/connect.go index 98d1e1a..9703504 100644 --- a/connect/connect.go +++ b/connect/connect.go @@ -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: diff --git a/hal.go b/hal.go index ca85c64..1cc27d9 100644 --- a/hal.go +++ b/hal.go @@ -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) diff --git a/internal/inband/inband.go b/internal/inband/inband.go index 63eaf07..3c0804e 100644 --- a/internal/inband/inband.go +++ b/internal/inband/inband.go @@ -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) { diff --git a/internal/outband/outband.go b/internal/outband/outband.go index 991c38a..0870a7d 100644 --- a/internal/outband/outband.go +++ b/internal/outband/outband.go @@ -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) { diff --git a/internal/redfish/redfish.go b/internal/redfish/redfish.go index 94dea1e..ea5e0d9 100644 --- a/internal/redfish/redfish.go +++ b/internal/redfish/redfish.go @@ -55,6 +55,38 @@ func New(url, user, password string, insecure bool, log logger.Logger) (*APIClie }, 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 { diff --git a/internal/vendors/lenovo/lenovo.go b/internal/vendors/lenovo/lenovo.go index 969f872..a6be1c1 100644 --- a/internal/vendors/lenovo/lenovo.go +++ b/internal/vendors/lenovo/lenovo.go @@ -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 { diff --git a/internal/vendors/supermicro/supermicro.go b/internal/vendors/supermicro/supermicro.go index 67ad35b..178c7e5 100644 --- a/internal/vendors/supermicro/supermicro.go +++ b/internal/vendors/supermicro/supermicro.go @@ -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 { diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 064fd77..dd853d0 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -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) }