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

SetBiosConfiguration(ctx, biosConfig) & ResetBiosConfiguration(ctx) for dell #385

Merged
merged 11 commits into from
Apr 16, 2024
136 changes: 131 additions & 5 deletions bmc/bios.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,26 @@
BiosConfigurationGetter
}

type BiosConfigurationSetter interface {
SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error)
}

type biosConfigurationSetterProvider struct {
name string
BiosConfigurationSetter
}

type BiosConfigurationResetter interface {
ResetBiosConfiguration(ctx context.Context) (err error)
}

type biosConfigurationResetterProvider struct {
name string
BiosConfigurationResetter
}

func biosConfiguration(ctx context.Context, generic []biosConfigurationGetterProvider) (biosConfig map[string]string, metadata Metadata, err error) {
var metadataLocal Metadata
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationGetter == nil {
Expand All @@ -27,23 +45,79 @@
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())

Check failure on line 48 in bmc/bios.go

View workflow job for this annotation

GitHub Actions / lint

undefined: multierror (typecheck)

Check failure on line 48 in bmc/bios.go

View workflow job for this annotation

GitHub Actions / lint

undefined: multierror (typecheck)
break Loop
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
biosConfig, vErr := elem.GetBiosConfiguration(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))

Check failure on line 54 in bmc/bios.go

View workflow job for this annotation

GitHub Actions / lint

undefined: multierror (typecheck)

Check failure on line 54 in bmc/bios.go

View workflow job for this annotation

GitHub Actions / lint

undefined: multierror (typecheck)
err = multierror.Append(err, vErr)

Check failure on line 55 in bmc/bios.go

View workflow job for this annotation

GitHub Actions / lint

undefined: multierror (typecheck)

Check failure on line 55 in bmc/bios.go

View workflow job for this annotation

GitHub Actions / lint

undefined: multierror (typecheck)
continue

}
metadataLocal.SuccessfulProvider = elem.name
return biosConfig, metadataLocal, nil
metadata.SuccessfulProvider = elem.name
return biosConfig, metadata, nil
}
}

return biosConfig, metadata, multierror.Append(err, errors.New("failure to get bios configuration"))
}

func setBiosConfiguration(ctx context.Context, generic []biosConfigurationSetterProvider, biosConfig map[string]string) (metadata Metadata, err error) {
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationSetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
vErr := elem.SetBiosConfiguration(ctx, biosConfig)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue

}
metadata.SuccessfulProvider = elem.name
return metadata, nil
}
}

return metadata, multierror.Append(err, errors.New("failure to set bios configuration"))
}

func resetBiosConfiguration(ctx context.Context, generic []biosConfigurationResetterProvider) (metadata Metadata, err error) {
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationResetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
vErr := elem.ResetBiosConfiguration(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue

}
metadata.SuccessfulProvider = elem.name
return metadata, nil
}
}

return biosConfig, metadataLocal, multierror.Append(err, errors.New("failure to get bios configuration"))
return metadata, multierror.Append(err, errors.New("failure to reset bios configuration"))
}

func GetBiosConfigurationInterfaces(ctx context.Context, generic []interface{}) (biosConfig map[string]string, metadata Metadata, err error) {
Expand Down Expand Up @@ -71,3 +145,55 @@

return biosConfiguration(ctx, implementations)
}

func SetBiosConfigurationInterfaces(ctx context.Context, generic []interface{}, biosConfig map[string]string) (metadata Metadata, err error) {
implementations := make([]biosConfigurationSetterProvider, 0)
for _, elem := range generic {
temp := biosConfigurationSetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case BiosConfigurationSetter:
temp.BiosConfigurationSetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a BiosConfigurationSetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no BiosConfigurationSetter implementations found"),
),
)
}

return setBiosConfiguration(ctx, implementations, biosConfig)
}

func ResetBiosConfigurationInterfaces(ctx context.Context, generic []interface{}) (metadata Metadata, err error) {
implementations := make([]biosConfigurationResetterProvider, 0)
for _, elem := range generic {
temp := biosConfigurationResetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case BiosConfigurationResetter:
temp.BiosConfigurationResetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a BiosConfigurationResetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no BiosConfigurationResetter implementations found"),
),
)
}

return resetBiosConfiguration(ctx, implementations)
}
25 changes: 23 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/go-logr/logr"
"github.com/jacobweinstock/registrar"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
oteltrace "go.opentelemetry.io/otel/trace"
tracenoop "go.opentelemetry.io/otel/trace/noop"
)
Expand Down Expand Up @@ -319,7 +318,7 @@ func (c *Client) registry() *registrar.Registry {
return c.Registry
}

func (c *Client) RegisterSpanAttributes(m bmc.Metadata, span trace.Span) {
func (c *Client) RegisterSpanAttributes(m bmc.Metadata, span oteltrace.Span) {
span.SetAttributes(attribute.String("host", c.Auth.Host))

span.SetAttributes(attribute.String("successful-provider", m.SuccessfulProvider))
Expand Down Expand Up @@ -556,6 +555,28 @@ func (c *Client) GetBiosConfiguration(ctx context.Context) (biosConfig map[strin
return biosConfig, err
}

func (c *Client) SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error) {
coffeefreak101 marked this conversation as resolved.
Show resolved Hide resolved
ctx, span := c.traceprovider.Tracer(pkgName).Start(ctx, "SetBiosConfiguration")
defer span.End()

metadata, err := bmc.SetBiosConfigurationInterfaces(ctx, c.registry().GetDriverInterfaces(), biosConfig)
c.setMetadata(metadata)
metadata.RegisterSpanAttributes(c.Auth.Host, span)

return err
}

func (c *Client) ResetBiosConfiguration(ctx context.Context) (err error) {
ctx, span := c.traceprovider.Tracer(pkgName).Start(ctx, "ResetBiosConfiguration")
defer span.End()

metadata, err := bmc.ResetBiosConfigurationInterfaces(ctx, c.registry().GetDriverInterfaces())
c.setMetadata(metadata)
metadata.RegisterSpanAttributes(c.Auth.Host, span)

return err
}

// FirmwareInstall pass through library function to upload firmware and install firmware
func (c *Client) FirmwareInstall(ctx context.Context, component string, operationApplyTime string, forceInstall bool, reader io.Reader) (taskID string, err error) {
ctx, span := c.traceprovider.Tracer(pkgName).Start(ctx, "FirmwareInstall")
Expand Down
85 changes: 70 additions & 15 deletions examples/bios/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,97 @@ package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"os"
"strings"
"time"

bmclib "github.com/bmc-toolbox/bmclib/v2"
"github.com/bmc-toolbox/bmclib/v2/providers"
logrusr "github.com/bombsimon/logrusr/v2"

"github.com/sirupsen/logrus"
)

func main() {
// setup logger
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()

// Command line option flag parsing
user := flag.String("user", "", "Username to login with")
pass := flag.String("password", "", "Username to login with")
host := flag.String("host", "", "BMC hostname to connect to")
mode := flag.String("mode", "get", "Mode [get,set,reset]")
dfile := flag.String("file", "", "Read data from file")

flag.Parse()

// Logger configuration
l := logrus.New()
l.Level = logrus.TraceLevel
l.Level = logrus.DebugLevel
logger := logrusr.New(l)

// bmclib client abstraction
clientOpts := []bmclib.Option{bmclib.WithLogger(logger)}

host := os.Getenv("BMC_HOST")
bmcPass := os.Getenv("BMC_PASSWORD")
bmcUser := os.Getenv("BMC_USERNAME")
// init client
client := bmclib.NewClient(host, bmcUser, bmcPass, clientOpts...)
client := bmclib.NewClient(*host, *user, *pass, clientOpts...)
client.Registry.Drivers = client.Registry.Supports(providers.FeatureGetBiosConfiguration, providers.FeatureSetBiosConfiguration, providers.FeatureResetBiosConfiguration)

ctx := context.TODO()
// open BMC session
err := client.Open(ctx)
if err != nil {
l.Fatal(err, "bmc login failed")
}

defer client.Close(ctx)

// retrieve bios configuration
biosConfig, err := client.GetBiosConfiguration(ctx)
if err != nil {
l.Error(err)
}
// Operating mode selection
switch strings.ToLower(*mode) {
case "get":
// retrieve bios configuration
biosConfig, err := client.GetBiosConfiguration(ctx)
if err != nil {
l.Fatal(err)
}

fmt.Printf("biosConfig: %+v\n", biosConfig)
case "set":
exampleConfig := make(map[string]string)

fmt.Println(biosConfig)
if *dfile != "" {
jsonFile, err := os.Open(*dfile)
if err != nil {
l.Fatal(err)
}

defer jsonFile.Close()

jsonData, _ := io.ReadAll(jsonFile)

err = json.Unmarshal(jsonData, &exampleConfig)
if err != nil {
l.Fatal(err)
}
} else {
exampleConfig["TpmSecurity"] = "Off"
}

fmt.Println("Attempting to set BIOS configuration:")
fmt.Printf("exampleConfig: %+v\n", exampleConfig)

err := client.SetBiosConfiguration(ctx, exampleConfig)
if err != nil {
l.Error(err)
}
case "reset":
err := client.ResetBiosConfiguration(ctx)
if err != nil {
l.Error(err)
}
default:
l.Fatal("Unknown mode: " + *mode)

}
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/stmcginnis/gofish v0.15.1-0.20231121142100-22a60a77be91
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/otel v1.25.0
go.opentelemetry.io/otel/trace v1.25.0
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
go.uber.org/goleak v1.2.1
golang.org/x/crypto v0.22.0
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8
Expand Down
Loading
Loading