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

FS-1729 #8

Merged
merged 2 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/metal-toolbox/bioscfg
go 1.22.1

require (
github.com/bmc-toolbox/bmclib/v2 v2.2.4
github.com/bmc-toolbox/bmclib/v2 v2.3.1
github.com/bombsimon/logrusr/v2 v2.0.1
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/equinix-labs/otel-init-go v0.0.9
Expand All @@ -12,7 +12,7 @@ require (
github.com/jeremywohl/flatten v1.0.1
github.com/metal-toolbox/ctrl v0.2.9
github.com/metal-toolbox/fleetdb v1.19.5
github.com/metal-toolbox/rivets v1.3.8
github.com/metal-toolbox/rivets v1.3.10
github.com/mitchellh/copystructure v1.2.0
github.com/mitchellh/mapstructure v1.5.0
github.com/pkg/errors v0.9.1
Expand All @@ -36,7 +36,7 @@ require (
github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 // indirect
github.com/banzaicloud/logrus-runtime-formatter v0.0.0-20190729070250-5ae5475bae5e // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmc-toolbox/common v0.0.0-20240723142833-87832458b53b // indirect
github.com/bmc-toolbox/common v0.0.0-20240806132831-ba8adc6a35e3 // indirect
github.com/bytedance/sonic v1.12.1 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
Expand Down Expand Up @@ -112,7 +112,7 @@ require (
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stmcginnis/gofish v0.15.1-0.20231121142100-22a60a77be91 // indirect
github.com/stmcginnis/gofish v0.19.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
Expand Down Expand Up @@ -144,6 +144,7 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
18 changes: 10 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bmc-toolbox/bmclib/v2 v2.2.4 h1:agAQuDLI/NNpKkxU+c+NfPZAu8ENBDE+kcTfz7WTCrw=
github.com/bmc-toolbox/bmclib/v2 v2.2.4/go.mod h1:V2XVg0Scpm16+0gE7WnI+5bU/M0c/o/nPZKHKzyVjAo=
github.com/bmc-toolbox/common v0.0.0-20240723142833-87832458b53b h1:0LHjikaGWlqEMczrCEZ6w1N/ZqcYlx6WRHkhabRUQEk=
github.com/bmc-toolbox/common v0.0.0-20240723142833-87832458b53b/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I=
github.com/bmc-toolbox/bmclib/v2 v2.3.1 h1:cXUfQFlQpDeUHruwXBYOdEkWXmW/nKdXpOIqbH8fz/M=
github.com/bmc-toolbox/bmclib/v2 v2.3.1/go.mod h1:t8If/0fHQTRIK/yKDk2H3SgthDNNj+7z2aeftDFRFrU=
github.com/bmc-toolbox/common v0.0.0-20240806132831-ba8adc6a35e3 h1:/BjZSX/sphptIdxpYo4wxAQkgMLyMMgfdl48J9DKNeE=
github.com/bmc-toolbox/common v0.0.0-20240806132831-ba8adc6a35e3/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I=
github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM=
github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio=
github.com/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24=
Expand Down Expand Up @@ -556,8 +556,8 @@ github.com/metal-toolbox/ctrl v0.2.9 h1:Q1Hqpqyb71/gg2PcX/qrfoDE8FlydJt4rPQb7/Z8
github.com/metal-toolbox/ctrl v0.2.9/go.mod h1:QVATUIWFx3dbjOoEX0EnJHtRvypRlXZ9HUGaPLRyTG8=
github.com/metal-toolbox/fleetdb v1.19.5 h1:ERgdFAUtWnT/AeVhCGclsENmwPhU88JUcgOZAdxWKYI=
github.com/metal-toolbox/fleetdb v1.19.5/go.mod h1:k9MZXQsJX4NfBoANst6g1468papSs0tzsSyzN3gGWuQ=
github.com/metal-toolbox/rivets v1.3.8 h1:BxzBPBYPMGBwJurIe+8Xji2YL7vHZUHbOmMpszWfPYw=
github.com/metal-toolbox/rivets v1.3.8/go.mod h1:8irU6eXgOa3QkjdcGi/aY4vqoMqCkbwVz7iVTYYPCX8=
github.com/metal-toolbox/rivets v1.3.10 h1:UgYQSx/QJF6Yuzf+YSRF/t9soL6QjMY8sLugf/aMmII=
github.com/metal-toolbox/rivets v1.3.10/go.mod h1:HkF9k8yw3MZqrIkxsi7w7EkTP3h2/t08WBpm+WK/Dsk=
github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
Expand Down Expand Up @@ -701,8 +701,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stmcginnis/gofish v0.15.1-0.20231121142100-22a60a77be91 h1:WmABtU8y6kTgzoVUn3FWCQGAfyodve3uz3xno28BrRs=
github.com/stmcginnis/gofish v0.15.1-0.20231121142100-22a60a77be91/go.mod h1:BLDSFTp8pDlf/xDbLZa+F7f7eW0E/CHCboggsu8CznI=
github.com/stmcginnis/gofish v0.19.0 h1:fmxdRZ5WHfs+4ExArMYoeRfoh+SAxLELKtmoVplBkU4=
github.com/stmcginnis/gofish v0.19.0/go.mod h1:lq2jHj2t8Krg0Gx02ABk8MbK7Dz9jvWpO/TGnVksn00=
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/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
Expand Down Expand Up @@ -1349,6 +1349,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs=
gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI=
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/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
Expand Down
105 changes: 105 additions & 0 deletions internal/bioscfg/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package bioscfg

import (
"context"
"io"
"net/http"

"github.com/metal-toolbox/bioscfg/internal/model"
rctypes "github.com/metal-toolbox/rivets/condition"
)

// handleAction completes the condition task based on the condition action
func (th *TaskHandler) handleAction(ctx context.Context) error {
switch th.task.Parameters.Action {
case rctypes.ResetConfig:
return th.resetBiosConfig(ctx)
case rctypes.SetConfig:
return th.setBiosConfig(ctx)
default:
return th.failedWithError(ctx, string(th.task.Parameters.Action), errUnsupportedAction)
}
}

// resetBiosConfig resets the bios of the server
func (th *TaskHandler) resetBiosConfig(ctx context.Context) error {
// Get Power State
state, err := th.bmcClient.GetPowerState(ctx)
if err != nil {
return th.failedWithError(ctx, "error getting power state", err)
}

err = th.publishActivef(ctx, "current power state: %s", state)
if err != nil {
return err
}

// Reset Bios
err = th.bmcClient.ResetBiosConfig(ctx)
if err != nil {
return th.failedWithError(ctx, "error reseting bios", err)
}

err = th.publishActive(ctx, "BIOS settings reset")
if err != nil {
return err
}

// Reboot (if ON)
if state == model.PowerStateOn {
err = th.bmcClient.SetPowerState(ctx, model.PowerStateReset)
if err != nil {
return th.failedWithError(ctx, "failed to reboot server", err)
}

return th.successful(ctx, "rebooting server")
}

return th.successful(ctx, "skipping server reboot, not on")
}

// setBiosConfig sets BIOS Config
func (th *TaskHandler) setBiosConfig(ctx context.Context) error {
var configURL = ""
if th.task.Parameters.BiosConfigURL != nil {
configURL = th.task.Parameters.BiosConfigURL.String()
}

if configURL == "" {
return th.failed(ctx, "no Bios Configu URL was found")
}

req, err := http.NewRequest(http.MethodGet, configURL, http.NoBody)
if err != nil {
return th.failedWithError(ctx, "failed to create http request", err)
}
req = req.WithContext(ctx)

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
return th.failedWithError(ctx, "failed to get bios config from url", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return th.failed(ctx, resp.Status)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return th.failedWithError(ctx, "failed to read file from response body", err)
}

err = th.publishActive(ctx, "got bios config from url")
if err != nil {
return err
}

err = th.bmcClient.SetBiosConfigFromFile(ctx, string(body))
if err != nil {
return th.failedWithError(ctx, "failed to set bios config through the bmc", err)
}

return th.successful(ctx, "bios set")
}
50 changes: 4 additions & 46 deletions internal/bioscfg/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (th *TaskHandler) HandleTask(ctx context.Context, genTask *rctypes.Task[any
th.publisher = publisher

// Ungeneric the task
th.task, err = NewTask(genTask)
th.task, err = newTask(genTask)
if err != nil {
th.logger.WithFields(logrus.Fields{
"conditionID": genTask.ID,
Expand Down Expand Up @@ -91,10 +91,10 @@ func (th *TaskHandler) HandleTask(ctx context.Context, genTask *rctypes.Task[any
}
}()

return th.Run(ctx)
return th.run(ctx)
}

func (th *TaskHandler) Run(ctx context.Context) error {
func (th *TaskHandler) run(ctx context.Context) error {
ctx, span := otel.Tracer(pkgName).Start(
ctx,
"TaskHandler.Run",
Expand All @@ -108,47 +108,5 @@ func (th *TaskHandler) Run(ctx context.Context) error {
return err
}

switch th.task.Parameters.Action {
case rctypes.ResetSettings:
return th.ResetBios(ctx)
default:
return th.failedWithError(ctx, string(th.task.Parameters.Action), errUnsupportedAction)
}
}

// ResetBios reset the bios of the server
func (th *TaskHandler) ResetBios(ctx context.Context) error {
// Get Power State
state, err := th.bmcClient.GetPowerState(ctx)
if err != nil {
return th.failedWithError(ctx, "error getting power state", err)
}

err = th.publishActivef(ctx, "current power state: %s", state)
if err != nil {
return err
}

// Reset Bios
err = th.bmcClient.ResetBios(ctx)
if err != nil {
return th.failedWithError(ctx, "error reseting bios", err)
}

err = th.publishActive(ctx, "BIOS settings reset")
if err != nil {
return err
}

// Reboot (if ON)
if state == model.PowerStateOn {
err = th.bmcClient.SetPowerState(ctx, model.PowerStateReset)
if err != nil {
return th.failedWithError(ctx, "failed to reboot server", err)
}

return th.successful(ctx, "rebooting server")
}

return th.successful(ctx, "skipping server reboot, not on")
return th.handleAction(ctx)
}
2 changes: 1 addition & 1 deletion internal/bioscfg/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func (th *TaskHandler) publish(ctx context.Context, status string, state rctypes
th.task.State = state
th.task.Status.Append(status)

genTask, err := th.task.ToGeneric()
genTask, err := th.task.toGeneric()
if err != nil {
th.logger.WithError(errTaskConv).Error()
return err
Expand Down
6 changes: 4 additions & 2 deletions internal/bioscfg/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (

type Task rctypes.Task[*rctypes.BiosControlTaskParameters, json.RawMessage]

func NewTask(task *rctypes.Task[any, any]) (*Task, error) {
// newTask converts a Generic Condition Task to a BiosControl Task
func newTask(task *rctypes.Task[any, any]) (*Task, error) {
paramsJSON, ok := task.Parameters.(json.RawMessage)
if !ok {
return nil, errInvalidConditionParams
Expand Down Expand Up @@ -52,7 +53,8 @@ func NewTask(task *rctypes.Task[any, any]) (*Task, error) {
}, nil
}

func (task *Task) ToGeneric() (*rctypes.Task[any, any], error) {
// toGeneric converts a BiosControl Task to a Generic Condition Task
func (task *Task) toGeneric() (*rctypes.Task[any, any], error) {
paramsJSON, err := task.Parameters.Marshal()
if err != nil {
return nil, errors.Wrap(errTaskConv, err.Error()+": Task.Parameters")
Expand Down
11 changes: 10 additions & 1 deletion internal/store/bmc/bmc.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func (b *Client) Close(traceCtx context.Context) error {
// GetPowerState returns the device power status
func (b *Client) GetPowerState(ctx context.Context) (string, error) {
defer b.tracelog()

return b.client.GetPowerState(ctx)
}

Expand Down Expand Up @@ -148,11 +149,16 @@ func (b *Client) HostBooted(ctx context.Context) (bool, error) {
return status == constants.POSTStateOS, nil
}

func (b *Client) ResetBios(ctx context.Context) error {
func (b *Client) ResetBiosConfig(ctx context.Context) error {
defer b.tracelog()
return b.client.ResetBiosConfiguration(ctx)
}

func (b *Client) SetBiosConfigFromFile(ctx context.Context, cfg string) error {
defer b.tracelog()
return b.client.SetBiosConfigurationFromFile(ctx, cfg)
}

func (b *Client) tracelog() {
pc, _, _, _ := runtime.Caller(1)
funcName := path.Base(runtime.FuncForPC(pc).Name())
Expand Down Expand Up @@ -240,6 +246,9 @@ func newBmclibClient(asset *model.Asset, l *logrus.Entry) *bmclib.Client {
providers.FeatureBootDeviceSet,
providers.FeaturePowerSet,
providers.FeaturePowerState,
providers.FeatureResetBiosConfiguration,
providers.FeatureSetBiosConfiguration,
providers.FeatureSetBiosConfigurationFromFile,
)

// NOTE: remove the .Using("redfish") before this ends up in prod
Expand Down
6 changes: 5 additions & 1 deletion internal/store/bmc/dryRun.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (b *DryRunBMCClient) HostBooted(_ context.Context) (bool, error) {
return true, nil
}

func (b *DryRunBMCClient) ResetBios(ctx context.Context) error {
func (b *DryRunBMCClient) ResetBiosConfig(ctx context.Context) error {
_, ok := serverStates[b.id]
if !ok {
return errBmcCantFindServer
Expand All @@ -130,6 +130,10 @@ func (b *DryRunBMCClient) ResetBios(ctx context.Context) error {
return b.SetPowerState(ctx, "cycle")
}

func (b *DryRunBMCClient) SetBiosConfigFromFile(_ context.Context, _ string) error {
return nil
}

// getServer gets a simulateed server state, and update power status and boot device if required
func (b *DryRunBMCClient) getServer() (*server, error) {
state, ok := serverStates[b.id]
Expand Down
3 changes: 2 additions & 1 deletion internal/store/bmc/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ type BMC interface {
GetBootDevice(ctx context.Context) (device string, persistent, efiBoot bool, err error)
PowerCycleBMC(ctx context.Context) error
HostBooted(ctx context.Context) (bool, error)
ResetBios(ctx context.Context) error
ResetBiosConfig(ctx context.Context) error
SetBiosConfigFromFile(ctx context.Context, cfg string) error
}
Loading