From 57bec53d471a9791ba1ab14e4e1cac9a31258965 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Tue, 28 May 2024 09:26:39 -0400 Subject: [PATCH 01/16] FS-1123: Supermicro (SMC) BIOS config Get, Set and Reset support via SUM --- client.go | 24 +++++++++++++++++++ examples/bios/main.go | 37 ++++++++++++++++++++++++++++-- providers/providers.go | 3 +++ providers/redfish/redfish.go | 8 +++++++ providers/supermicro/firmware.go | 8 +++---- providers/supermicro/supermicro.go | 2 +- 6 files changed, 75 insertions(+), 7 deletions(-) diff --git a/client.go b/client.go index e9bd76ca..7ed7d5aa 100644 --- a/client.go +++ b/client.go @@ -23,6 +23,7 @@ import ( "github.com/bmc-toolbox/bmclib/v2/providers/openbmc" "github.com/bmc-toolbox/bmclib/v2/providers/redfish" "github.com/bmc-toolbox/bmclib/v2/providers/rpc" + "github.com/bmc-toolbox/bmclib/v2/providers/sum" "github.com/bmc-toolbox/bmclib/v2/providers/supermicro" "github.com/bmc-toolbox/common" "github.com/go-logr/logr" @@ -72,6 +73,7 @@ type providerConfig struct { supermicro supermicro.Config rpc rpc.Provider openbmc openbmc.Config + sum sum.Exec } // NewClient returns a new Client struct @@ -109,6 +111,7 @@ func NewClient(host, user, pass string, opts ...Option) *Client { openbmc: openbmc.Config{ Port: "443", }, + sum: sum.Exec{}, }, } @@ -262,6 +265,23 @@ func (c *Client) registerOpenBMCProvider() { c.Registry.Register(openbmc.ProviderName, openbmc.ProviderProtocol, openbmc.Features, nil, driver) } +// register sum provider +func (c *Client) registerSumProvider() error { + sumOpts := []sum.Option{ + sum.WithLogger(c.Logger), + sum.WithSumPath(c.providerConfig.sum.SumPath), + } + + driverSum, err := sum.New(c.Auth.Host, c.Auth.User, c.Auth.Pass, sumOpts...) + if err != nil { + return err + } + + c.Registry.Register(sum.ProviderName, sum.ProviderProtocol, sum.Features, nil, driverSum) + + return nil +} + func (c *Client) registerProviders() { // register the rpc provider // without the consumer URL there is no way to send RPC requests. @@ -279,6 +299,10 @@ func (c *Client) registerProviders() { c.Logger.Info("ipmitool provider not available", "error", err.Error()) } + if err := c.registerSumProvider(); err != nil { + c.Logger.Info("sum provider not available", "error", err.Error()) + } + c.registerASRRProvider() c.registerGofishProvider() c.registerIntelAMTProvider() diff --git a/examples/bios/main.go b/examples/bios/main.go index 16def4aa..3acd683b 100644 --- a/examples/bios/main.go +++ b/examples/bios/main.go @@ -32,14 +32,19 @@ func main() { // Logger configuration l := logrus.New() - l.Level = logrus.DebugLevel + // l.Level = logrus.TraceLevel logger := logrusr.New(l) + logger.V(9) // bmclib client abstraction clientOpts := []bmclib.Option{bmclib.WithLogger(logger)} client := bmclib.NewClient(*host, *user, *pass, clientOpts...) - client.Registry.Drivers = client.Registry.Supports(providers.FeatureGetBiosConfiguration, providers.FeatureSetBiosConfiguration, providers.FeatureResetBiosConfiguration) + client.Registry.Drivers = client.Registry.Supports( + providers.FeatureGetBiosConfiguration, + providers.FeatureSetBiosConfiguration, + providers.FeatureResetBiosConfiguration, + providers.FeatureSetBiosConfigurationFromFile) err := client.Open(ctx) if err != nil { @@ -82,6 +87,34 @@ func main() { 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 "setfile": + exampleConfig := make(map[string]string) + + 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) diff --git a/providers/providers.go b/providers/providers.go index 0699e7cb..2791c777 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -70,6 +70,9 @@ const ( // FeatureSetBiosConfiguration means an implementation that can set bios configuration from an input k/v map FeatureSetBiosConfiguration registrar.Feature = "setbiosconfig" + // FeatureSetBiosConfigurationFromFile means an implementation that can set bios configuration from a vendor specific text file + FeatureSetBiosConfigurationFromFile registrar.Feature = "setbiosconfigfile" + // FeatureGetBiosConfiguration means an implementation that can get bios configuration in a simple k/v map FeatureGetBiosConfiguration registrar.Feature = "getbiosconfig" ) diff --git a/providers/redfish/redfish.go b/providers/redfish/redfish.go index 1541feb2..89830272 100644 --- a/providers/redfish/redfish.go +++ b/providers/redfish/redfish.go @@ -36,6 +36,9 @@ var ( providers.FeatureInventoryRead, providers.FeatureBmcReset, providers.FeatureClearSystemEventLog, + providers.FeatureGetBiosConfiguration, + providers.FeatureSetBiosConfiguration, + providers.FeatureResetBiosConfiguration, } ) @@ -223,6 +226,11 @@ func (c *Conn) SetBiosConfiguration(ctx context.Context, biosConfig map[string]s return c.redfishwrapper.SetBiosConfiguration(ctx, biosConfig) } +// ResetBiosConfiguration set bios configuration +func (c *Conn) ResetBiosConfiguration(ctx context.Context) (err error) { + return c.redfishwrapper.ResetBiosConfiguration(ctx) +} + // SendNMI tells the BMC to issue an NMI to the device func (c *Conn) SendNMI(ctx context.Context) error { return c.redfishwrapper.SendNMI(ctx) diff --git a/providers/supermicro/firmware.go b/providers/supermicro/firmware.go index a13bda67..a7140c81 100644 --- a/providers/supermicro/firmware.go +++ b/providers/supermicro/firmware.go @@ -34,7 +34,7 @@ var ( // bmc client interface implementations methods func (c *Client) FirmwareInstallSteps(ctx context.Context, component string) ([]constants.FirmwareInstallStep, error) { - if err := c.serviceClient.supportsFirmwareInstall(ctx, c.bmc.deviceModel()); err != nil { + if err := c.serviceClient.supportsFirmwareInstall(c.bmc.deviceModel()); err != nil { return nil, err } @@ -42,7 +42,7 @@ func (c *Client) FirmwareInstallSteps(ctx context.Context, component string) ([] } func (c *Client) FirmwareUpload(ctx context.Context, component string, file *os.File) (taskID string, err error) { - if err := c.serviceClient.supportsFirmwareInstall(ctx, c.bmc.deviceModel()); err != nil { + if err := c.serviceClient.supportsFirmwareInstall(c.bmc.deviceModel()); err != nil { return "", err } @@ -56,7 +56,7 @@ func (c *Client) FirmwareUpload(ctx context.Context, component string, file *os. } func (c *Client) FirmwareInstallUploaded(ctx context.Context, component, uploadTaskID string) (installTaskID string, err error) { - if err := c.serviceClient.supportsFirmwareInstall(ctx, c.bmc.deviceModel()); err != nil { + if err := c.serviceClient.supportsFirmwareInstall(c.bmc.deviceModel()); err != nil { return "", err } @@ -70,7 +70,7 @@ func (c *Client) FirmwareInstallUploaded(ctx context.Context, component, uploadT // FirmwareTaskStatus returns the status of a firmware related task queued on the BMC. func (c *Client) FirmwareTaskStatus(ctx context.Context, kind constants.FirmwareInstallStep, component, taskID, installVersion string) (state constants.TaskState, status string, err error) { - if err := c.serviceClient.supportsFirmwareInstall(ctx, c.bmc.deviceModel()); err != nil { + if err := c.serviceClient.supportsFirmwareInstall(c.bmc.deviceModel()); err != nil { return "", "", errors.Wrap(bmclibErrs.ErrFirmwareInstallStatus, err.Error()) } diff --git a/providers/supermicro/supermicro.go b/providers/supermicro/supermicro.go index 2ba88d33..902aa94f 100644 --- a/providers/supermicro/supermicro.go +++ b/providers/supermicro/supermicro.go @@ -426,7 +426,7 @@ func (c *serviceClient) redfishSession(ctx context.Context) (err error) { return nil } -func (c *serviceClient) supportsFirmwareInstall(ctx context.Context, model string) error { +func (c *serviceClient) supportsFirmwareInstall(model string) error { if model == "" { return errors.Wrap(ErrModelUnknown, "unable to determine firmware install compatibility") } From 62dd780f61061a388180c359ed6b4433f572d55e Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Tue, 28 May 2024 09:31:03 -0400 Subject: [PATCH 02/16] FS-1123: Update devcontainer Dockerfile to use go 1.22 --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 11d9d578..94d0550e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/go:1-1.21-bullseye +FROM mcr.microsoft.com/devcontainers/go:1-1.22-bullseye RUN apt update RUN apt install ipmitool -y From 61c6387c5938b9860059c783ce87d81d660bca23 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 3 Jun 2024 16:15:38 -0400 Subject: [PATCH 03/16] FS-1123: Import latest bmc-toolbox/common --- go.mod | 9 +++++---- go.sum | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index fd656c19..a852e174 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( dario.cat/mergo v1.0.0 github.com/Jeffail/gabs/v2 v2.7.0 - github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116 + github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a github.com/bombsimon/logrusr/v2 v2.0.1 github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.4.1 @@ -22,9 +22,9 @@ require ( 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/crypto v0.23.0 golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 - golang.org/x/net v0.24.0 + golang.org/x/net v0.25.0 gopkg.in/go-playground/assert.v1 v1.2.1 ) @@ -37,7 +37,8 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect - golang.org/x/sys v0.19.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6468f053..398cd856 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,30 @@ github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 h1:a0MBqYm44o0N github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22/go.mod h1:/B7V22rcz4860iDqstGvia/2+IYWXf3/JdQCVd/1D2A= github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116 h1:gqWn/cMjryKoUfITx2vRHrRHTvd9fQ+zKPwWsmMIrK4= github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116/go.mod h1:SY//n1PJjZfbFbmAsB6GvEKbc7UXz3d30s3kWxfJQ/c= +github.com/bmc-toolbox/common v0.0.0-20240510143200-3db7cecbb5a6 h1:qJJDtxYKk/sMfF6F3hVAcM+KDpN1H58gNWpdtaQys0o= +github.com/bmc-toolbox/common v0.0.0-20240510143200-3db7cecbb5a6/go.mod h1:SY//n1PJjZfbFbmAsB6GvEKbc7UXz3d30s3kWxfJQ/c= +github.com/bmc-toolbox/common v0.0.0-20240603172842-eb6f410eb5de h1:NJBK0yIF7qSOpgY1OOrGxp3RZhHsC0cFk0gTKzXUc2k= +github.com/bmc-toolbox/common v0.0.0-20240603172842-eb6f410eb5de/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603184341-1e0bb3c83913 h1:7aoALwFulgTiQdqwYMjHupAtU3EHTH+WPvsGTJBLdjY= +github.com/bmc-toolbox/common v0.0.0-20240603184341-1e0bb3c83913/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603184929-3cf0da0cbfa3 h1:SfWGTN0bcwVlraIU1yxdkoqQ6v9jaJR/l+bxdSY73gE= +github.com/bmc-toolbox/common v0.0.0-20240603184929-3cf0da0cbfa3/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603185220-8b3e265f41a8 h1:rKzrj3Z8tOI3G61iU1DQ+WMO7jdZ33f30S5C/EHyM0Q= +github.com/bmc-toolbox/common v0.0.0-20240603185220-8b3e265f41a8/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603185344-8dba5823aba7 h1:7vND3B+FVFnPdgB8D6uHuZ5fP5b3VJrmBXEcnobz654= +github.com/bmc-toolbox/common v0.0.0-20240603185344-8dba5823aba7/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603185654-589b5b927f1a h1:mzv6kR+ESe8yc9+zdD9/9bnENbN72xV+em7w46itSYA= +github.com/bmc-toolbox/common v0.0.0-20240603185654-589b5b927f1a/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603191859-10f91c7f7069 h1:qCDEPX+KCst3vscXL3D2A2bkIMFM5m2UYwXxJBVOQp4= +github.com/bmc-toolbox/common v0.0.0-20240603191859-10f91c7f7069/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603195442-451b340c917f h1:Aany52L3NnVzLaatENRgcnFPkvmxlCwbJdCSoLnDUU8= +github.com/bmc-toolbox/common v0.0.0-20240603195442-451b340c917f/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603195647-7e4b15cdd4df h1:gE+MdFa70AZZt4JTGI6XmCnFi6LEmGLBU2pHIcUhPb0= +github.com/bmc-toolbox/common v0.0.0-20240603195647-7e4b15cdd4df/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603195926-3b5f49af547c h1:ZEBcAi/NGrJqrVCtmslL5s8qCuGs+RFLsFKG350VQqE= +github.com/bmc-toolbox/common v0.0.0-20240603195926-3b5f49af547c/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a h1:kyT7AEN1iav7MLqE4hspxlI6FT46RyUdQcij5EA1lbE= +github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a/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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -75,10 +99,13 @@ go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -87,7 +114,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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= From 45b9aef8b95533ad781d148a7b297bfe4f14496f Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 3 Jun 2024 16:15:57 -0400 Subject: [PATCH 04/16] FS-1123: Enhancements to examples/bios --- examples/bios/main.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/bios/main.go b/examples/bios/main.go index 3acd683b..5425e68f 100644 --- a/examples/bios/main.go +++ b/examples/bios/main.go @@ -32,6 +32,7 @@ func main() { // Logger configuration l := logrus.New() + l.Level = logrus.DebugLevel // l.Level = logrus.TraceLevel logger := logrusr.New(l) logger.V(9) @@ -62,7 +63,7 @@ func main() { l.Fatal(err) } - fmt.Printf("biosConfig: %+v\n", biosConfig) + fmt.Printf("biosConfig: %#v\n", biosConfig) case "set": exampleConfig := make(map[string]string) @@ -95,18 +96,17 @@ func main() { exampleConfig := make(map[string]string) if *dfile != "" { - jsonFile, err := os.Open(*dfile) + cfgFile, err := os.Open(*dfile) if err != nil { l.Fatal(err) } - defer jsonFile.Close() - - jsonData, _ := io.ReadAll(jsonFile) + defer cfgFile.Close() + jsonData, _ := io.ReadAll(cfgFile) err = json.Unmarshal(jsonData, &exampleConfig) if err != nil { - l.Fatal(err) + l.Error(err) } } else { exampleConfig["TpmSecurity"] = "Off" From d49516d3ff30a4545791e958e280bc7bf8e1b09e Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 5 Jun 2024 19:52:36 -0400 Subject: [PATCH 05/16] FS-1123: Supermicro Update Manager (SUM) provider --- providers/sum/sum.go | 280 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 providers/sum/sum.go diff --git a/providers/sum/sum.go b/providers/sum/sum.go new file mode 100644 index 00000000..330bebda --- /dev/null +++ b/providers/sum/sum.go @@ -0,0 +1,280 @@ +package sum + +import ( + "context" + "os" + "os/exec" + "strings" + + "github.com/bmc-toolbox/bmclib/v2/providers" + "github.com/bmc-toolbox/common" + "github.com/bmc-toolbox/common/config" + "github.com/go-logr/logr" + "github.com/jacobweinstock/registrar" +) + +const ( + // ProviderName for the provider implementation + ProviderName = "sum" + // ProviderProtocol for the provider implementation + ProviderProtocol = "sum" +) + +var ( + // Features implemented by SUM + Features = registrar.Features{ + providers.FeatureGetBiosConfiguration, + providers.FeatureSetBiosConfiguration, + providers.FeatureSetBiosConfigurationFromFile, + providers.FeatureResetBiosConfiguration, + } +) + +// Conn for Sum connection details +type Exec struct { + SumPath string + Log logr.Logger + Host string + Username string + Password string +} + +// Option for setting optional Client values +type Option func(*Exec) + +func WithSumPath(sumPath string) Option { + return func(c *Exec) { + c.SumPath = sumPath + } +} + +func WithLogger(log logr.Logger) Option { + return func(c *Exec) { + c.Log = log + } +} + +func New(host, user, pass string, opts ...Option) (*Exec, error) { + sum := &Exec{ + Host: host, + Username: user, + Password: pass, + Log: logr.Discard(), + } + + for _, opt := range opts { + opt(sum) + } + + var err error + + if sum.SumPath == "" { + sum.SumPath, err = exec.LookPath("sum") + if err != nil { + return nil, err + } + } else { + if _, err = os.Stat(sum.SumPath); err != nil { + return nil, err + } + } + + return sum, nil +} + +// Open a connection to a BMC +func (c *Exec) Open(ctx context.Context) (err error) { + return nil +} + +// Close a connection to a BMC +func (c *Exec) Close(ctx context.Context) (err error) { + return nil +} + +func (c *Exec) Name() string { + return ProviderName +} + +func (s *Exec) run(ctx context.Context, command string, additionalArgs ...string) (output string, err error) { + // TODO(splaspood) use a tmp file here (as sum supports) to read the password + sumArgs := []string{"-i", s.Host, "-u", s.Username, "-p", s.Password, "-c", command} + sumArgs = append(sumArgs, additionalArgs...) + + s.Log.V(9).WithValues( + "sumArgs", + sumArgs, + ).Info("Calling sum") + + cmd := exec.CommandContext(ctx, s.SumPath, sumArgs...) + b_out, err := cmd.CombinedOutput() + if err != nil || ctx.Err() != nil { + if err != nil { + return + } + + if ctx.Err() != nil { + return output, ctx.Err() + } + } + + return string(b_out), err +} + +func (s *Exec) GetCurrentBiosCfg(ctx context.Context) (output string, err error) { + return s.run(ctx, "GetCurrentBiosCfg") +} + +func (s *Exec) LoadDefaultBiosCfg(ctx context.Context) (err error) { + _, err = s.run(ctx, "LoadDefaultBiosCfg") + return +} + +func (s *Exec) ChangeBiosCfg(ctx context.Context, cfgFile string, reboot bool) (err error) { + args := []string{"--file", cfgFile} + + if reboot { + args = append(args, "--reboot") + } + + _, err = s.run(ctx, "ChangeBiosCfg", args...) + + return +} + +// GetBiosConfiguration return bios configuration +func (s *Exec) GetBiosConfiguration(ctx context.Context) (biosConfig map[string]string, err error) { + biosText, err := s.GetCurrentBiosCfg(ctx) + if err != nil { + return + } + + // We need to call vcm here to take the XML returned by SUM and convert it into a simple map + vcm, err := config.NewVendorConfigManager("xml", common.VendorSupermicro, map[string]string{}) + if err != nil { + return + } + + err = vcm.Unmarshal(biosText) + if err != nil { + return nil, err + } + + biosConfig, err = vcm.StandardConfig() + if err != nil { + return nil, err + } + + return biosConfig, nil +} + +// SetBiosConfiguration set bios configuration +func (s *Exec) SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error) { + vcm, err := config.NewVendorConfigManager("xml", common.VendorSupermicro, map[string]string{}) + if err != nil { + return + } + + for k, v := range biosConfig { + switch { + case k == "boot_mode": + if err = vcm.BootMode(v); err != nil { + return err + } + case k == "boot_order": + if err = vcm.BootOrder(v); err != nil { + return err + } + case k == "intel_sgx": + if err = vcm.IntelSGX(v); err != nil { + return err + } + case k == "secure_boot": + switch v { + case "Enabled": + if err = vcm.SecureBoot(true); err != nil { + return err + } + case "Disabled": + if err = vcm.SecureBoot(false); err != nil { + return err + } + } + case k == "tpm": + switch v { + case "Enabled": + if err = vcm.TPM(true); err != nil { + return err + } + case "Disabled": + if err = vcm.TPM(false); err != nil { + return err + } + } + case k == "smt": + switch v { + case "Enabled": + if err = vcm.SMT(true); err != nil { + return err + } + case "Disabled": + if err = vcm.SMT(false); err != nil { + return err + } + } + case k == "sr_iov": + switch v { + case "Enabled": + if err = vcm.SRIOV(true); err != nil { + return err + } + case "Disabled": + if err = vcm.SRIOV(false); err != nil { + return err + } + } + case strings.HasPrefix(k, "raw:"): + // k = raw:Menu1,SubMenu1,SubMenuMenu1,SettingName + pathStr := strings.TrimPrefix(k, "raw:") + path := strings.Split(pathStr, ",") + name := path[len(path)-1] + path = path[:len(path)-1] + + vcm.Raw(name, v, path) + } + } + + xmlData, err := vcm.Marshal() + if err != nil { + return + } + + return s.SetBIOSConfigurationFromFile(ctx, xmlData) +} + +func (s *Exec) SetBIOSConfigurationFromFile(ctx context.Context, cfg string) (err error) { + // Open tmp file to hold cfg + inputConfigTmpFile, err := os.CreateTemp("", "bmclib") + if err != nil { + return + } + + defer os.Remove(inputConfigTmpFile.Name()) + + _, err = inputConfigTmpFile.WriteString(cfg) + if err != nil { + return + } + + err = inputConfigTmpFile.Close() + if err != nil { + return + } + + return s.ChangeBiosCfg(ctx, inputConfigTmpFile.Name(), false) +} + +// ResetBiosConfiguration reset bios configuration +func (s *Exec) ResetBiosConfiguration(ctx context.Context) (err error) { + return s.LoadDefaultBiosCfg(ctx) +} From 57710dc7f413d96c6677ce96ce57da8bb5088272 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 5 Jun 2024 19:54:45 -0400 Subject: [PATCH 06/16] FS-1123: Pin to bmc-toolbox/common@cfd9f1a6c4ad3253e074a34bca4e2aa7f2463eab --- go.mod | 2 +- go.sum | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a852e174..df7bcc21 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( dario.cat/mergo v1.0.0 github.com/Jeffail/gabs/v2 v2.7.0 - github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a + github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad github.com/bombsimon/logrusr/v2 v2.0.1 github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.4.1 diff --git a/go.sum b/go.sum index 398cd856..1171e70b 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,12 @@ github.com/bmc-toolbox/common v0.0.0-20240603195926-3b5f49af547c h1:ZEBcAi/NGrJq github.com/bmc-toolbox/common v0.0.0-20240603195926-3b5f49af547c/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a h1:kyT7AEN1iav7MLqE4hspxlI6FT46RyUdQcij5EA1lbE= github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240605235353-a070a211ea91 h1:2fIuUXNjIIfs/+UyRdgi78BNw4nqJvOPzPgVvXgJDh8= +github.com/bmc-toolbox/common v0.0.0-20240605235353-a070a211ea91/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240605235604-dd3030c2f298 h1:2xs7qhthgZySFn7wwXCSMB20miuY4gN2oQ1lueAvWFU= +github.com/bmc-toolbox/common v0.0.0-20240605235604-dd3030c2f298/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad h1:lnIG+pB9t6EuX2I89gKdPj9rHbXA4cNRMMDO07ziX0E= +github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad/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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= From 200eec6dd93c692669bc7172fa2fcc4052ab67f4 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Tue, 23 Jul 2024 12:15:27 -0400 Subject: [PATCH 07/16] go.mod: Update bmc-toolbox/common version --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index df7bcc21..10b13773 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( dario.cat/mergo v1.0.0 github.com/Jeffail/gabs/v2 v2.7.0 - github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad + github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8 github.com/bombsimon/logrusr/v2 v2.0.1 github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.4.1 diff --git a/go.sum b/go.sum index 1171e70b..64504aad 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ github.com/bmc-toolbox/common v0.0.0-20240605235604-dd3030c2f298 h1:2xs7qhthgZyS github.com/bmc-toolbox/common v0.0.0-20240605235604-dd3030c2f298/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad h1:lnIG+pB9t6EuX2I89gKdPj9rHbXA4cNRMMDO07ziX0E= github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8 h1:KK812W5Tpk0n5qcS0vZ0IYqhoZNkV66NuCIon99OGQ8= +github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8/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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= From 9c572ad76ac7ad74c8461babcee917c69236d190 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Tue, 23 Jul 2024 12:16:35 -0400 Subject: [PATCH 08/16] internal/sum: Convert providers/sum into an internal package --- client.go | 24 ----------------- {providers => internal}/sum/sum.go | 27 ++----------------- providers/supermicro/supermicro.go | 42 ++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 49 deletions(-) rename {providers => internal}/sum/sum.go (88%) diff --git a/client.go b/client.go index 7ed7d5aa..e9bd76ca 100644 --- a/client.go +++ b/client.go @@ -23,7 +23,6 @@ import ( "github.com/bmc-toolbox/bmclib/v2/providers/openbmc" "github.com/bmc-toolbox/bmclib/v2/providers/redfish" "github.com/bmc-toolbox/bmclib/v2/providers/rpc" - "github.com/bmc-toolbox/bmclib/v2/providers/sum" "github.com/bmc-toolbox/bmclib/v2/providers/supermicro" "github.com/bmc-toolbox/common" "github.com/go-logr/logr" @@ -73,7 +72,6 @@ type providerConfig struct { supermicro supermicro.Config rpc rpc.Provider openbmc openbmc.Config - sum sum.Exec } // NewClient returns a new Client struct @@ -111,7 +109,6 @@ func NewClient(host, user, pass string, opts ...Option) *Client { openbmc: openbmc.Config{ Port: "443", }, - sum: sum.Exec{}, }, } @@ -265,23 +262,6 @@ func (c *Client) registerOpenBMCProvider() { c.Registry.Register(openbmc.ProviderName, openbmc.ProviderProtocol, openbmc.Features, nil, driver) } -// register sum provider -func (c *Client) registerSumProvider() error { - sumOpts := []sum.Option{ - sum.WithLogger(c.Logger), - sum.WithSumPath(c.providerConfig.sum.SumPath), - } - - driverSum, err := sum.New(c.Auth.Host, c.Auth.User, c.Auth.Pass, sumOpts...) - if err != nil { - return err - } - - c.Registry.Register(sum.ProviderName, sum.ProviderProtocol, sum.Features, nil, driverSum) - - return nil -} - func (c *Client) registerProviders() { // register the rpc provider // without the consumer URL there is no way to send RPC requests. @@ -299,10 +279,6 @@ func (c *Client) registerProviders() { c.Logger.Info("ipmitool provider not available", "error", err.Error()) } - if err := c.registerSumProvider(); err != nil { - c.Logger.Info("sum provider not available", "error", err.Error()) - } - c.registerASRRProvider() c.registerGofishProvider() c.registerIntelAMTProvider() diff --git a/providers/sum/sum.go b/internal/sum/sum.go similarity index 88% rename from providers/sum/sum.go rename to internal/sum/sum.go index 330bebda..5db01a31 100644 --- a/providers/sum/sum.go +++ b/internal/sum/sum.go @@ -6,28 +6,9 @@ import ( "os/exec" "strings" - "github.com/bmc-toolbox/bmclib/v2/providers" "github.com/bmc-toolbox/common" "github.com/bmc-toolbox/common/config" "github.com/go-logr/logr" - "github.com/jacobweinstock/registrar" -) - -const ( - // ProviderName for the provider implementation - ProviderName = "sum" - // ProviderProtocol for the provider implementation - ProviderProtocol = "sum" -) - -var ( - // Features implemented by SUM - Features = registrar.Features{ - providers.FeatureGetBiosConfiguration, - providers.FeatureSetBiosConfiguration, - providers.FeatureSetBiosConfigurationFromFile, - providers.FeatureResetBiosConfiguration, - } ) // Conn for Sum connection details @@ -92,10 +73,6 @@ func (c *Exec) Close(ctx context.Context) (err error) { return nil } -func (c *Exec) Name() string { - return ProviderName -} - func (s *Exec) run(ctx context.Context, command string, additionalArgs ...string) (output string, err error) { // TODO(splaspood) use a tmp file here (as sum supports) to read the password sumArgs := []string{"-i", s.Host, "-u", s.Username, "-p", s.Password, "-c", command} @@ -249,10 +226,10 @@ func (s *Exec) SetBiosConfiguration(ctx context.Context, biosConfig map[string]s return } - return s.SetBIOSConfigurationFromFile(ctx, xmlData) + return s.SetBiosConfigurationFromFile(ctx, xmlData) } -func (s *Exec) SetBIOSConfigurationFromFile(ctx context.Context, cfg string) (err error) { +func (s *Exec) SetBiosConfigurationFromFile(ctx context.Context, cfg string) (err error) { // Open tmp file to hold cfg inputConfigTmpFile, err := os.CreateTemp("", "bmclib") if err != nil { diff --git a/providers/supermicro/supermicro.go b/providers/supermicro/supermicro.go index 902aa94f..0f24f2b5 100644 --- a/providers/supermicro/supermicro.go +++ b/providers/supermicro/supermicro.go @@ -19,6 +19,7 @@ import ( "github.com/bmc-toolbox/bmclib/v2/constants" "github.com/bmc-toolbox/bmclib/v2/internal/httpclient" "github.com/bmc-toolbox/bmclib/v2/internal/redfishwrapper" + "github.com/bmc-toolbox/bmclib/v2/internal/sum" "github.com/bmc-toolbox/bmclib/v2/providers" "github.com/bmc-toolbox/common" @@ -51,6 +52,10 @@ var ( providers.FeaturePowerSet, providers.FeaturePowerState, providers.FeatureBmcReset, + providers.FeatureGetBiosConfiguration, + providers.FeatureSetBiosConfiguration, + providers.FeatureSetBiosConfigurationFromFile, + providers.FeatureResetBiosConfiguration, } ) @@ -235,6 +240,42 @@ func (c *Client) Inventory(ctx context.Context) (device *common.Device, err erro return c.serviceClient.redfish.Inventory(ctx, false) } +// GetBiosConfiguration return bios configuration +func (c *Client) GetBiosConfiguration(ctx context.Context) (biosConfig map[string]string, err error) { + if c.serviceClient == nil || c.serviceClient.sum == nil { + return nil, errors.Wrap(bmclibErrs.ErrLoginFailed, "client not initialized") + } + + return c.serviceClient.sum.GetBiosConfiguration(ctx) +} + +// SetBiosConfiguration set bios configuration +func (c *Client) SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error) { + if c.serviceClient == nil || c.serviceClient.sum == nil { + return errors.Wrap(bmclibErrs.ErrLoginFailed, "client not initialized") + } + + return c.serviceClient.sum.SetBiosConfiguration(ctx, biosConfig) +} + +// SetBiosConfigurationFromFile sets the bios configuration from a raw vendor config file +func (c *Client) SetBIOSConfigurationFromFile(ctx context.Context, cfg string) (err error) { + if c.serviceClient == nil || c.serviceClient.sum == nil { + return errors.Wrap(bmclibErrs.ErrLoginFailed, "client not initialized") + } + + return c.serviceClient.sum.SetBiosConfigurationFromFile(ctx, cfg) +} + +// ResetBiosConfiguration sets the bios configuration back to "factory" defaults +func (c *Client) ResetBiosConfiguration(ctx context.Context) (err error) { + if c.serviceClient == nil || c.serviceClient.sum == nil { + return errors.Wrap(bmclibErrs.ErrLoginFailed, "client not initialized") + } + + return c.serviceClient.sum.ResetBiosConfiguration(ctx) +} + func (c *Client) bmcQueryor(ctx context.Context) (bmcQueryor, error) { x11 := newX11Client(c.serviceClient, c.log) x12 := newX12Client(c.serviceClient, c.log) @@ -393,6 +434,7 @@ type serviceClient struct { csrfToken string client *http.Client redfish *redfishwrapper.Client + sum *sum.Exec } func newBmcServiceClient(host, port, user, pass string, client *http.Client) *serviceClient { From 246e00272aafa93c7578059870158118cf1d077b Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Tue, 23 Jul 2024 12:36:25 -0400 Subject: [PATCH 09/16] internal/sum/sum.go: Use explict returns --- internal/sum/sum.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/sum/sum.go b/internal/sum/sum.go index 5db01a31..9d16f85b 100644 --- a/internal/sum/sum.go +++ b/internal/sum/sum.go @@ -104,7 +104,7 @@ func (s *Exec) GetCurrentBiosCfg(ctx context.Context) (output string, err error) func (s *Exec) LoadDefaultBiosCfg(ctx context.Context) (err error) { _, err = s.run(ctx, "LoadDefaultBiosCfg") - return + return err } func (s *Exec) ChangeBiosCfg(ctx context.Context, cfgFile string, reboot bool) (err error) { @@ -116,20 +116,20 @@ func (s *Exec) ChangeBiosCfg(ctx context.Context, cfgFile string, reboot bool) ( _, err = s.run(ctx, "ChangeBiosCfg", args...) - return + return err } // GetBiosConfiguration return bios configuration func (s *Exec) GetBiosConfiguration(ctx context.Context) (biosConfig map[string]string, err error) { biosText, err := s.GetCurrentBiosCfg(ctx) if err != nil { - return + return nil, err } // We need to call vcm here to take the XML returned by SUM and convert it into a simple map vcm, err := config.NewVendorConfigManager("xml", common.VendorSupermicro, map[string]string{}) if err != nil { - return + return nil, err } err = vcm.Unmarshal(biosText) @@ -149,7 +149,7 @@ func (s *Exec) GetBiosConfiguration(ctx context.Context) (biosConfig map[string] func (s *Exec) SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error) { vcm, err := config.NewVendorConfigManager("xml", common.VendorSupermicro, map[string]string{}) if err != nil { - return + return err } for k, v := range biosConfig { @@ -223,7 +223,7 @@ func (s *Exec) SetBiosConfiguration(ctx context.Context, biosConfig map[string]s xmlData, err := vcm.Marshal() if err != nil { - return + return err } return s.SetBiosConfigurationFromFile(ctx, xmlData) @@ -233,19 +233,19 @@ func (s *Exec) SetBiosConfigurationFromFile(ctx context.Context, cfg string) (er // Open tmp file to hold cfg inputConfigTmpFile, err := os.CreateTemp("", "bmclib") if err != nil { - return + return err } defer os.Remove(inputConfigTmpFile.Name()) _, err = inputConfigTmpFile.WriteString(cfg) if err != nil { - return + return err } err = inputConfigTmpFile.Close() if err != nil { - return + return err } return s.ChangeBiosCfg(ctx, inputConfigTmpFile.Name(), false) From 678cddf6ab310d15050d23695a3726de2f824c45 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 24 Jul 2024 11:00:02 -0400 Subject: [PATCH 10/16] go.sum: go mod tidy --- go.sum | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/go.sum b/go.sum index 64504aad..791c98ad 100644 --- a/go.sum +++ b/go.sum @@ -6,38 +6,6 @@ github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 h1:t95Grn2 github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230/go.mod h1:t2EzW1qybnPDQ3LR/GgeF0GOzHUXT5IVMLP2gkW1cmc= github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 h1:a0MBqYm44o0NcthLKCljZHe1mxlN6oahCQHHThnSwB4= github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22/go.mod h1:/B7V22rcz4860iDqstGvia/2+IYWXf3/JdQCVd/1D2A= -github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116 h1:gqWn/cMjryKoUfITx2vRHrRHTvd9fQ+zKPwWsmMIrK4= -github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116/go.mod h1:SY//n1PJjZfbFbmAsB6GvEKbc7UXz3d30s3kWxfJQ/c= -github.com/bmc-toolbox/common v0.0.0-20240510143200-3db7cecbb5a6 h1:qJJDtxYKk/sMfF6F3hVAcM+KDpN1H58gNWpdtaQys0o= -github.com/bmc-toolbox/common v0.0.0-20240510143200-3db7cecbb5a6/go.mod h1:SY//n1PJjZfbFbmAsB6GvEKbc7UXz3d30s3kWxfJQ/c= -github.com/bmc-toolbox/common v0.0.0-20240603172842-eb6f410eb5de h1:NJBK0yIF7qSOpgY1OOrGxp3RZhHsC0cFk0gTKzXUc2k= -github.com/bmc-toolbox/common v0.0.0-20240603172842-eb6f410eb5de/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603184341-1e0bb3c83913 h1:7aoALwFulgTiQdqwYMjHupAtU3EHTH+WPvsGTJBLdjY= -github.com/bmc-toolbox/common v0.0.0-20240603184341-1e0bb3c83913/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603184929-3cf0da0cbfa3 h1:SfWGTN0bcwVlraIU1yxdkoqQ6v9jaJR/l+bxdSY73gE= -github.com/bmc-toolbox/common v0.0.0-20240603184929-3cf0da0cbfa3/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603185220-8b3e265f41a8 h1:rKzrj3Z8tOI3G61iU1DQ+WMO7jdZ33f30S5C/EHyM0Q= -github.com/bmc-toolbox/common v0.0.0-20240603185220-8b3e265f41a8/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603185344-8dba5823aba7 h1:7vND3B+FVFnPdgB8D6uHuZ5fP5b3VJrmBXEcnobz654= -github.com/bmc-toolbox/common v0.0.0-20240603185344-8dba5823aba7/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603185654-589b5b927f1a h1:mzv6kR+ESe8yc9+zdD9/9bnENbN72xV+em7w46itSYA= -github.com/bmc-toolbox/common v0.0.0-20240603185654-589b5b927f1a/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603191859-10f91c7f7069 h1:qCDEPX+KCst3vscXL3D2A2bkIMFM5m2UYwXxJBVOQp4= -github.com/bmc-toolbox/common v0.0.0-20240603191859-10f91c7f7069/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603195442-451b340c917f h1:Aany52L3NnVzLaatENRgcnFPkvmxlCwbJdCSoLnDUU8= -github.com/bmc-toolbox/common v0.0.0-20240603195442-451b340c917f/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603195647-7e4b15cdd4df h1:gE+MdFa70AZZt4JTGI6XmCnFi6LEmGLBU2pHIcUhPb0= -github.com/bmc-toolbox/common v0.0.0-20240603195647-7e4b15cdd4df/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603195926-3b5f49af547c h1:ZEBcAi/NGrJqrVCtmslL5s8qCuGs+RFLsFKG350VQqE= -github.com/bmc-toolbox/common v0.0.0-20240603195926-3b5f49af547c/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a h1:kyT7AEN1iav7MLqE4hspxlI6FT46RyUdQcij5EA1lbE= -github.com/bmc-toolbox/common v0.0.0-20240603200149-d7c52783cf3a/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240605235353-a070a211ea91 h1:2fIuUXNjIIfs/+UyRdgi78BNw4nqJvOPzPgVvXgJDh8= -github.com/bmc-toolbox/common v0.0.0-20240605235353-a070a211ea91/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240605235604-dd3030c2f298 h1:2xs7qhthgZySFn7wwXCSMB20miuY4gN2oQ1lueAvWFU= -github.com/bmc-toolbox/common v0.0.0-20240605235604-dd3030c2f298/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= -github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad h1:lnIG+pB9t6EuX2I89gKdPj9rHbXA4cNRMMDO07ziX0E= -github.com/bmc-toolbox/common v0.0.0-20240606000647-cfd9f1a6c4ad/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8 h1:KK812W5Tpk0n5qcS0vZ0IYqhoZNkV66NuCIon99OGQ8= github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= @@ -105,13 +73,10 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -120,12 +85,9 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 2cfd480681772d1c1e6ab3d5a4b189f29512a745 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 5 Aug 2024 09:31:25 -0400 Subject: [PATCH 11/16] Implement sum test cases and a mocked Executor model --- fixtures/internal/sum/ChangeBiosConfig | 11 + .../internal/sum/ChangeBiosConfig-Changed | 7 + .../sum/ChangeBiosConfig-Changed-Reboot | 16 + fixtures/internal/sum/GetBiosConfiguration | 3634 +++++++++++++++++ fixtures/internal/sum/SetBiosConfiguration | 16 + internal/executor/errors.go | 44 + internal/executor/executor.go | 168 + internal/executor/executor_test.go | 117 + internal/executor/fake_executor.go | 100 + internal/sum/sum.go | 78 +- internal/sum/sum_test.go | 104 + providers/supermicro/supermicro.go | 2 +- 12 files changed, 4268 insertions(+), 29 deletions(-) create mode 100644 fixtures/internal/sum/ChangeBiosConfig create mode 100644 fixtures/internal/sum/ChangeBiosConfig-Changed create mode 100644 fixtures/internal/sum/ChangeBiosConfig-Changed-Reboot create mode 100644 fixtures/internal/sum/GetBiosConfiguration create mode 100644 fixtures/internal/sum/SetBiosConfiguration create mode 100644 internal/executor/errors.go create mode 100644 internal/executor/executor.go create mode 100644 internal/executor/executor_test.go create mode 100644 internal/executor/fake_executor.go create mode 100644 internal/sum/sum_test.go diff --git a/fixtures/internal/sum/ChangeBiosConfig b/fixtures/internal/sum/ChangeBiosConfig new file mode 100644 index 00000000..99b91d0c --- /dev/null +++ b/fixtures/internal/sum/ChangeBiosConfig @@ -0,0 +1,11 @@ +Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64) +Copyright(C) 2013-2024 Super Micro Computer, Inc. All rights reserved. +................. + + +Note: No BIOS setting has been changed. + +Status: The BIOS configuration is updated for 10.145.129.168 + +Note: You have to reboot or power up the system for the changes to take effect. + diff --git a/fixtures/internal/sum/ChangeBiosConfig-Changed b/fixtures/internal/sum/ChangeBiosConfig-Changed new file mode 100644 index 00000000..9b49cf0b --- /dev/null +++ b/fixtures/internal/sum/ChangeBiosConfig-Changed @@ -0,0 +1,7 @@ +Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64) +Copyright(C) 2013-2024 Super Micro Computer, Inc. All rights reserved. +.................. +Status: The BIOS configuration is updated for 10.145.129.168 + +Note: You have to reboot or power up the system for the changes to take effect. + diff --git a/fixtures/internal/sum/ChangeBiosConfig-Changed-Reboot b/fixtures/internal/sum/ChangeBiosConfig-Changed-Reboot new file mode 100644 index 00000000..3aa242f8 --- /dev/null +++ b/fixtures/internal/sum/ChangeBiosConfig-Changed-Reboot @@ -0,0 +1,16 @@ +Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64) +Copyright(C) 2013-2024 Super Micro Computer, Inc. All rights reserved. +................. +Status: The managed system 10.145.129.168 is rebooting. + +.............................Done +.... +................. + + +Note: No BIOS setting has been changed. + +Status: The BIOS configuration is updated for 10.145.129.168 + +WARNING: Without option --post_complete, please manually confirm the managed system is POST complete before executing next action. + diff --git a/fixtures/internal/sum/GetBiosConfiguration b/fixtures/internal/sum/GetBiosConfiguration new file mode 100644 index 00000000..99d8f37e --- /dev/null +++ b/fixtures/internal/sum/GetBiosConfiguration @@ -0,0 +1,3634 @@ +Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64) +Copyright(C) 2013-2024 Super Micro Computer, Inc. All rights reserved. +....................... + + + + + + + + + Supermicro X11SCM-F + BIOS Version(1.9) + Build Date(09/16/2022) + CPLD Version(03.B3.05) + + Memory Information + Total Memory(32768 MB) + + + + + + + + + + + + + + Disabled + + + + + + + + Checked + + + + + + + + + + + On + + + + + + + + + + Force BIOS + + + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Disabled + + + + + + + + + + + Last State + + + + + + + + + + Instant Off + + + + + + + + + + Disabled + + + + + + 32767 + 1 + 1 + 100 + + + + + + + + + CPU Configuration + + Intel(R) Xeon(R) E-2278G CPU @ 3.40GHz() + CPU Signature(0x906ED) + Microcode Revision(F4) + CPU Speed(3400 MHz) + L1 Data Cache(32 KB x 8) + L1 Instruction Cache(32 KB x 8) + L2 Cache(256 KB x 8) + L3 Cache(16 MB) + L4 Cache(N/A) + VMX(Supported) + SMX/TXT(Supported) + + + + + + + + Disabled + + + + + + 63 + 0 + 0 + 20 + + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + + + + + + + All + + + + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + Enabled + + + + + + + + + + + Max Non-Turbo Performance + + + + + + + + + + Enabled + + + + + + + + + + Disabled + + + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + + + + C1 and C3 + + + + + + + + + + + + + C1 and C3 + + + + + + + + + + + Disabled + + + + + + + + + + + Disabled + + + + + + + + + + + Enabled + + + + + + + + + + + + + + + + + + + + Auto + + + + + + + + + + + Disabled + + + + + + + 4095875 + 0 + 125 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + Enabled + + + + + + + 4095875 + 0 + 125 + 0 + + + + + + + + + + Unchecked + + + + + + + + + + WARNING: Setting wrong values in below sections may cause + system to malfunction. + + + + + System Agent (SA) Configuration + + SA PCIe Code Version(7.0.88.80) + VT-d(Supported) + + + + + + Memory Configuration + + Memory RC Version(0.7.1.115) + Memory Frequency( 2667 MHz) + Memory Timings (tCL-tRCD-tRP-tRAS)(19-19-19-43) + + DIMMA1(Not Present) + DIMMA2(Populated & Enabled) + Size(16384 MB (DDR4)) + Number of Ranks(2) + Manufacturer(Micron Technology) + DIMMB1(Not Present) + DIMMB2(Populated & Enabled) + Size(16384 MB (DDR4)) + Number of Ranks(2) + Manufacturer(Micron Technology) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Auto + + + + + + + + + + + + + + + + + + + + Dynamic + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + DMI/OPI Configuration + + DMI(X4 Gen3) + + + + + + + + + + L1 + + + + + + + + + + Disabled + + + + + + + + + + -3.5 dB + + + + + + + + + PEG Port Configuration + + CPU Slot6 PCI-E 3.0 X16(x8 Gen3) + + + + + + + + Auto + + + + + + + + + + + + Auto + + + + + + + + + + + + + Auto + + + + + + + + + + + + + Auto + + + + + + + + + + + Both Root and Endpoint Ports + + + + + + + + + + + -3.5 dB + + + + + + 255 + 0 + 1 + 75 + + + + + + + + + + + + 1.0x + + + + + + 8191 + 0 + 1 + 1 + + + + + + + + + + + Auto + + + + + + + + + + + Disabled + + + + + + + + + + + + Enabled + + + + + + + + + + + Software Controlled + + + + + + + + + + + No Change in Owner EPOCHs + + + + + + + 18446744073709551615 + 0 + 1 + 6142344250440060711 + + + + + + + 18446744073709551615 + 0 + 1 + 15521488688214965697 + + + + + + + + + + + + Unlocked + + + + + + + 18446744073709551615 + 0 + 1 + 0 + + + + + + + 18446744073709551615 + 0 + 1 + 0 + + + + + + + 18446744073709551615 + 0 + 1 + 0 + + + + + + + 18446744073709551615 + 0 + 1 + 0 + + + + + + + + + + + INVALID PRMRR + + + + + + + + + + + Enabled + + + + + + + + + + Disabled + + + + + + + + + + PCH-IO Configuration + + + + + + PCI Express Configuration + + + + + + + + + + + Auto + + + + + + + + + + Disabled + + + + + + + + + + + + + + + + + Auto + + + + + + + + + + + L1.1 & L1.2 + + + + + + + + + + + + Auto + + + + + + + + + + + + + + + + + + Auto + + + + + + + + + + + L1.1 & L1.2 + + + + + + + + + + + + Auto + + + + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + Super IO Configuration + + Super IO Chip(AST2500) + + + + + Serial Port 1 Configuration + + + + + Checked + + + + Device Settings(IO=3F8h; IRQ=4;) + + + + + + + + + + + + Auto + + + + + + + + + + Serial Port 2 Configuration + + + + + Checked + + + + Device Settings(IO=2F8h; IRQ=3;) + + + + + + + + + + + + Auto + + + + + + + + + + + + COM1 + + + + Unchecked + + + + + + + + + COM1 + Console Redirection Settings + + + + + + + + + + VT100+ + + + + + + + + + + + + + 115200 + + + + + + + + + + 8 + + + + + + + + + + + + + None + + + + + + + + + + 1 + + + + + + + + + + None + + + + + + + Checked + + + + + + + Unchecked + + + + + + + Checked + + + + + + + + + + + + + + VT100 + + + + + + + SOL + + + + Checked + + + + + + + + + SOL + Console Redirection Settings + + + + + + + + + + VT100+ + + + + + + + + + + + + + 115200 + + + + + + + + + + 8 + + + + + + + + + + + + + None + + + + + + + + + + 1 + + + + + + + + + + None + + + + + + + Checked + + + + + + + Unchecked + + + + + + + Checked + + + + + + + + + + + + + + VT100 + + + + + + + Legacy Console Redirection + + + + + Legacy Console Redirection Settings + + + + + + + + COM1 + + + + + + + + + + 80x25 + + + + + + + + + + Always Enable + + + + + + Serial Port for Out-of-Band Management/ + Windows Emergency Management Services (EMS) + + + + Unchecked + + + + + + + + + + + + + + + COM1 + + + + + + + + + + + + VT-UTF8 + + + + + + + + + + + + + 115200 + + + + + + + + + + + + None + + + + + Data Bits(8) + + Parity(None) + + Stop Bits(1) + + + + + + + + SATA And RSTe Configuration + + + + + + + + Enabled + + + + + + + + + + AHCI + + + + + + + + + + + + MSI + + + + + + + + + + + Disabled + + + + + + + + + + + + Legacy + + + + + Serial ATA Port 0(Micron_5300_MT (480.1GB)) + + Software Preserve(SUPPORTED) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + Serial ATA Port 1(Micron_5300_MT (480.1GB)) + + Software Preserve(SUPPORTED) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + Serial ATA Port 2(Empty) + + Software Preserve(Unknown) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + Serial ATA Port 3(Empty) + + Software Preserve(Unknown) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + Serial ATA Port 4(Empty) + + Software Preserve(Unknown) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + Serial ATA Port 5(Empty) + + Software Preserve(Unknown) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + Serial ATA Port 6(Empty) + + Software Preserve(Unknown) + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Hard Disk Drive + + + + + + + + + + PCH-FW Configuration + Operational Firmware Version(5.1.4.700) + Backup Firmware Version(N/A) + Recovery Firmware Version(5.1.4.700) + ME Firmware Features(SiEn +NM +PECIProxy +ICC +MeStorageServices +BootGuard +PmBusProxy +HSIO +PCHDebug +PowerThermalUtility +PCHThermalSensorInit +DeepSx +DirectMeUpdate +TelemetryHub +) + ME Firmware Status #1(0x00000255) + ME Firmware Status #2(0x89118027) + Current State(Operational) + Error Code(No Error) + + + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + + Auto + + + + + + + + + + Disabled + + + + + + + + + USB Configuration + + USB Module Version(23) + + USB Controllers:() + 1 XHCI + USB Devices:() + 1 Keyboard, 1 Mouse, 1 Hub + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + Option ROM execution + + + + + + + Disabled + + + + + + + + + + Disabled + + + + + + + + + + Disabled + + + + + + + + + + Onboard + + + + + + + + + + + Legacy + + + + + + + + + + Vendor Defined Firmware + + + + + PCIe/PCI/PnP Configuration + + + + + + + + Legacy + + + + + + + + + + + Legacy + + + + + + + + + + + Legacy + + + + + + + + + + Legacy + + + + + + + + + + + PXE + + + + + + + + + + + Disabled + + + + + + + + + + + Enabled + + + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Enabled + + + + + + + + + + + Disabled + + + + + + + + + + + Disabled + + + + + + + 5 + 0 + 1 + 0 + + + + + + + 50 + 1 + 1 + 1 + + + + + + + + + + + + + + + + TPM20 Device Found + Firmware Version:(7.62) + Vendor:(IFX) + + + + + + + + Enable + + + + Active PCR banks(SHA-1,SHA256) + + Available PCR banks(SHA-1,SHA256) + + + + + + + + + Enabled + + + + + + + + + + + Enabled + + + + + + + + + + + + None + + + + + + + + + + + Enabled + + + + + + + + + + + Enabled + + + + + + + + + + + Enabled + + + + + + + + + + + TCG_2 + + + + + + + + + + + 1.3 + + + + + + + + + + + Enabled + + + + + + + + + + + Auto + + + + + + + + + + + Disabled + + + + + + + + + + Disabled + + + + + + + + + + HTTP BOOT Configuration + + + + + + + Disabled + + + + + + 0 + 75 + + + False + + + + + + 0 + 80 + + + False + + + + + + + + + + + to change the SMBIOS Event Log configuration.]]> + + Enabling/Disabling Options + + + + + + + Enabled + + + + + + + + + + Disabled + + + + + Erasing Settings + + + + + + + + No + + + + + + + + + + + Do Nothing + + + + + + SMBIOS Event Log Standard Settings + + + + + + + Disabled + + + + + + + 255 + 1 + 1 + 1 + + + + + + + 99 + 0 + 1 + 60 + + + + + + + + to view the SMBIOS Event Log records.]]> + + DATE TIME ERROR CODE SEVERITY + + + + + + + Password Description + + If the Administrator / User password is set, then this only limits access to Setup and is asked for when entering Setup. Please set Administrator password first in order for setting User password, if clear Administrator password, User password will be cleared as well. + The password length must be in the following range: + Minimum length(3) + Maximum length(20) + + + + + + + + Setup + + + + + + + + + + Disabled + + + + + + + + + Security Module Version(1.00) + HDD Name(Micron_5300_MTFDDAK480TDT) + HDD Serial Number(20422B887014) + Security Mode(SAT3 Supported) + Estimated Time(2 Minutes) + HDD User Pwd Status(NOT INSTALLED) + + + + + + + + + Disable + + + + + + 0 + 32 + + + False + + + + + HDD Name(Micron_5300_MTFDDAK480TDT) + HDD Serial Number(20422B8885C5) + Security Mode(SAT3 Supported) + Estimated Time(2 Minutes) + HDD User Pwd Status(NOT INSTALLED) + + + + + + + + + Disable + + + + + + 0 + 32 + + + False + + + + + + + + + + 3 + 20 + False + + + + + + + + + 3 + 20 + False + + + + + + + + + + + + + + + + + + Disabled + + + + + + + + + + + + Disabled + + + + System Mode(Setup) + Secure Boot(Not Active) + + + + + + + Setup + + + + + HDD Security Configuration: + + + + + HDD Password Description : + + Allows Access to Set, Modify and Clear + + HDD PASSWORD CONFIGURATION: + + Security Supported :(Yes) + Security Supported :(No) + Security Enabled :(No) + Security Locked :(Yes) + Security Locked :(No) + Security Frozen :(No) + HDD User Pwd Status:(INSTALLED) + HDD User Pwd Status:(NOT INSTALLED) + HDD Master Pwd Status :(NOT INSTALLED) + + + + + 0 + 32 + False + + + + + + + + + + + HDD Password Description : + + Allows Access to Set, Modify and Clear + + HDD PASSWORD CONFIGURATION: + + Security Supported :(No) + Security Enabled :(Yes) + Security Locked :(No) + Security Frozen :(Yes) + Security Frozen :(No) + HDD User Pwd Status:(NOT INSTALLED) + HDD Master Pwd Status :(INSTALLED) + HDD Master Pwd Status :(NOT INSTALLED) + + + + + 0 + 32 + False + + + + + + + + + + + + Boot Configuration + + + 65535 + 1 + 1 + 1 + + + + + + + + + + + + DUAL + + + + + FIXED BOOT ORDER Priorities + + + + + + + + + + + + + + + UEFI Hard Disk + + + + + + + + + + + + + + + + + + + UEFI CD/DVD + + + + + + + + + + + + + + + + + + + UEFI USB Hard Disk + + + + + + + + + + + + + + + + + + + UEFI USB CD/DVD + + + + + + + + + + + + + + + + + + + UEFI USB Key + + + + + + + + + + + + + + + + + + + UEFI USB Floppy + + + + + + + + + + + + + + + + + + + UEFI USB Lan + + + + + + + + + + + + + + + + + + + UEFI Network + + + + + + + + + + + + + + + + + + + UEFI AP:UEFI: Built-in EFI Shell + + + + + + + + + + + + + + + + + + Hard Disk: Micron_5300_MTFDDAK480TDT + + + + + + + + + + + + + + + + + + CD/DVD + + + + + + + + + + + + + + + + + + USB Hard Disk + + + + + + + + + + + + + + + + + + USB CD/DVD + + + + + + + + + + + + + + + + + + USB Key + + + + + + + + + + + + + + + + + + USB Floppy + + + + + + + + + + + + + + + + + + USB Lan + + + + + + + + + + + + + + + + + + Network:FlexBoot v3.5.901 (PCI 01:00.0) + + + + + + + + + + + + + + + + + + + + + + + + + + + Hard Disk: Micron_5300_MTFDDAK480TDT + + + + + + + + + + + + + + + + + + + + + + + + + + + CD/DVD + + + + + + + + + + + + + + + + + + + + + + + + + + + USB Hard Disk + + + + + + + + + + + + + + + + + + + + + + + + + + + USB CD/DVD + + + + + + + + + + + + + + + + + + + + + + + + + + + USB Key + + + + + + + + + + + + + + + + + + + + + + + + + + + USB Floppy + + + + + + + + + + + + + + + + + + + + + + + + + + + USB Lan + + + + + + + + + + + + + + + + + + + + + + + + + + + Network:FlexBoot v3.5.901 (PCI 01:00.0) + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI Hard Disk + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI CD/DVD + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI USB Hard Disk + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI USB CD/DVD + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI USB Key + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI USB Floppy + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI USB Lan + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI Network + + + + + + + + + + + + + + + + + + + + + + + + + + + UEFI AP:UEFI: Built-in EFI Shell + + + + + + + + + + + + + + + + + + + UEFI: Built-in EFI Shell + + + + + + + + + + + + + + + + + P0: Micron_5300_MTFDDAK480TDT(SATA,Port:0) + + + + + + + + + + + P1: Micron_5300_MTFDDAK480TDT(SATA,Port:1) + + + + + + + + + + + + + + + + + FlexBoot v3.5.901 (PCI 01:00.0) + + + + + + + + + + + FlexBoot v3.5.901 (PCI 01:00.1) + + + + + + + diff --git a/fixtures/internal/sum/SetBiosConfiguration b/fixtures/internal/sum/SetBiosConfiguration new file mode 100644 index 00000000..3aa242f8 --- /dev/null +++ b/fixtures/internal/sum/SetBiosConfiguration @@ -0,0 +1,16 @@ +Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64) +Copyright(C) 2013-2024 Super Micro Computer, Inc. All rights reserved. +................. +Status: The managed system 10.145.129.168 is rebooting. + +.............................Done +.... +................. + + +Note: No BIOS setting has been changed. + +Status: The BIOS configuration is updated for 10.145.129.168 + +WARNING: Without option --post_complete, please manually confirm the managed system is POST complete before executing next action. + diff --git a/internal/executor/errors.go b/internal/executor/errors.go new file mode 100644 index 00000000..d37b70c0 --- /dev/null +++ b/internal/executor/errors.go @@ -0,0 +1,44 @@ +package executor + +import ( + "errors" + "fmt" +) + +var ( + ErrNoCommandOutput = errors.New("command returned no output") + ErrVersionStrExpectedSemver = errors.New("expected version string to follow semver format") + ErrFakeExecutorInvalidArgs = errors.New("invalid number of args passed to fake executor") + ErrRepositoryBaseURL = errors.New("repository base URL undefined, ensure UpdateOptions.BaseURL OR UPDATE_BASE_URL env var is set") + ErrNoUpdatesApplicable = errors.New("no updates applicable") + ErrDmiDecodeRun = errors.New("error running dmidecode") + ErrComponentListExpected = errors.New("expected a list of components to apply updates") + ErrDeviceInventory = errors.New("failed to collect device inventory") + ErrUnsupportedDiskVendor = errors.New("unsupported disk vendor") + ErrNoUpdateHandlerForComponent = errors.New("component slug has no update handler declared") + ErrBinNotExecutable = errors.New("bin has no executable bit set") + ErrBinLstat = errors.New("failed to run lstat on bin") + ErrBinLookupPath = errors.New("failed to lookup bin path") +) + +// ExecError is returned when the command exits with an error or a non zero exit status +type ExecError struct { + Cmd string + Stderr string + Stdout string + ExitCode int +} + +// Error implements the error interface +func (u *ExecError) Error() string { + return fmt.Sprintf("cmd %s exited with error: %s\n\t exitCode: %d\n\t stdout: %s", u.Cmd, u.Stderr, u.ExitCode, u.Stdout) +} + +func newExecError(cmd string, r *Result) *ExecError { + return &ExecError{ + Cmd: cmd, + Stderr: string(r.Stderr), + Stdout: string(r.Stdout), + ExitCode: r.ExitCode, + } +} diff --git a/internal/executor/executor.go b/internal/executor/executor.go new file mode 100644 index 00000000..48e202ca --- /dev/null +++ b/internal/executor/executor.go @@ -0,0 +1,168 @@ +package executor + +import ( + "bytes" + "context" + "io" + "os" + "os/exec" + "strings" + + "github.com/pkg/errors" +) + +// Executor interface lets us implement dummy executors for tests +type Executor interface { + ExecWithContext(context.Context) (*Result, error) + SetArgs([]string) + SetEnv([]string) + SetQuiet() + SetVerbose() + GetCmd() string + DisableBinCheck() + SetStdin(io.Reader) + CmdPath() string + CheckExecutable() error + // for tests + SetStdout([]byte) + SetStderr([]byte) + SetExitCode(int) +} + +func NewExecutor(cmd string) Executor { + return &Execute{Cmd: cmd, CheckBin: true} +} + +// An execute instace +type Execute struct { + Cmd string + Args []string + Env []string + Stdin io.Reader + CheckBin bool + Quiet bool +} + +// The result of a command execution +type Result struct { + Stdout []byte + Stderr []byte + ExitCode int +} + +// GetCmd returns the command with args as a string +func (e *Execute) GetCmd() string { + cmd := []string{e.Cmd} + cmd = append(cmd, e.Args...) + + return strings.Join(cmd, " ") +} + +// CmdPath returns the absolute path to the executable +// this means the caller should not have disabled CheckBin. +func (e *Execute) CmdPath() string { + return e.Cmd +} + +// SetArgs sets the command args +func (e *Execute) SetArgs(a []string) { + e.Args = a +} + +// SetEnv sets the env variables +func (e *Execute) SetEnv(env []string) { + e.Env = env +} + +// SetQuiet lowers the verbosity +func (e *Execute) SetQuiet() { + e.Quiet = true +} + +// SetVerbose does whats it says +func (e *Execute) SetVerbose() { + e.Quiet = false +} + +// SetStdin sets the reader to the command stdin +func (e *Execute) SetStdin(r io.Reader) { + e.Stdin = r +} + +// DisableBinCheck disables validating the binary exists and is executable +func (e *Execute) DisableBinCheck() { + e.CheckBin = false +} + +// SetStdout doesn't do much, is around for tests +func (e *Execute) SetStdout(_ []byte) { +} + +// SetStderr doesn't do much, is around for tests +func (e *Execute) SetStderr(_ []byte) { +} + +// SetExitCode doesn't do much, is around for tests +func (e *Execute) SetExitCode(_ int) { +} + +// ExecWithContext executes the command and returns the Result object +func (e *Execute) ExecWithContext(ctx context.Context) (result *Result, err error) { + if e.CheckBin { + err = e.CheckExecutable() + if err != nil { + return nil, err + } + } + + cmd := exec.CommandContext(ctx, e.Cmd, e.Args...) + cmd.Env = append(cmd.Env, e.Env...) + cmd.Stdin = e.Stdin + + var stdoutBuf, stderrBuf bytes.Buffer + if !e.Quiet { + cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) + cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) + } else { + cmd.Stderr = &stderrBuf + cmd.Stdout = &stdoutBuf + } + + if err := cmd.Run(); err != nil { + result = &Result{stdoutBuf.Bytes(), stderrBuf.Bytes(), cmd.ProcessState.ExitCode()} + return result, newExecError(e.GetCmd(), result) + } + + result = &Result{stdoutBuf.Bytes(), stderrBuf.Bytes(), cmd.ProcessState.ExitCode()} + + return result, nil +} + +// CheckExecutable determines if the set Cmd value exists as a file and is an executable. +func (e *Execute) CheckExecutable() error { + var path string + + if strings.Contains(e.Cmd, "/") { + path = e.Cmd + } else { + var err error + path, err = exec.LookPath(e.Cmd) + if err != nil { + return errors.Wrap(ErrBinLookupPath, err.Error()) + } + + e.Cmd = path + } + + fileInfo, err := os.Lstat(path) + if err != nil { + return errors.Wrap(ErrBinLstat, err.Error()) + } + + // bit mask 0111 indicates atleast one of owner, group, others has an executable bit set + if fileInfo.Mode()&0o111 == 0 { + return ErrBinNotExecutable + } + + return nil +} diff --git a/internal/executor/executor_test.go b/internal/executor/executor_test.go new file mode 100644 index 00000000..fa1c6e93 --- /dev/null +++ b/internal/executor/executor_test.go @@ -0,0 +1,117 @@ +package executor + +import ( + "bytes" + "context" + "fmt" + "io/fs" + "os" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func Test_Stdin(t *testing.T) { + e := new(Execute) + e.Cmd = "grep" + e.Args = []string{"hello"} + e.Stdin = bytes.NewReader([]byte("hello")) + e.SetQuiet() + + result, err := e.ExecWithContext(context.Background()) + if err != nil { + fmt.Println(err.Error()) + } + + assert.Equal(t, []byte("hello\n"), result.Stdout) +} + +type checkBinTester struct { + createFile bool + filePath string + expectedErr error + fileMode uint + testName string +} + +func initCheckBinTests() []checkBinTester { + return []checkBinTester{ + { + false, + "f", + ErrBinLookupPath, + 0, + "bin path lookup err test", + }, + { + false, + "/tmp/f", + ErrBinLstat, + 0, + "bin exists err test", + }, + { + true, + "/tmp/f", + ErrBinNotExecutable, + 0o666, + "bin exists with no executable bit test", + }, + { + true, + "/tmp/j", + nil, + 0o667, + "bin with executable bit returns no error", + }, + { + true, + "/tmp/k", + nil, + 0o700, + "bin with owner executable bit returns no error", + }, + { + true, + "/tmp/l", + nil, + 0o070, + "bin with group executable bit returns no error", + }, + { + true, + "/tmp/m", + nil, + 0o007, + "bin with other executable bit returns no error", + }, + } +} + +func Test_CheckExecutable(t *testing.T) { + tests := initCheckBinTests() + for _, c := range tests { + if c.createFile { + f, err := os.Create(c.filePath) + if err != nil { + t.Error(err) + } + + // nolint:gocritic // test code + defer os.Remove(c.filePath) + + if c.fileMode != 0 { + err = f.Chmod(fs.FileMode(c.fileMode)) + if err != nil { + t.Error(err) + } + } + } + + e := new(Execute) + e.Cmd = c.filePath + err := e.CheckExecutable() + assert.Equal(t, c.expectedErr, errors.Cause(err), c.testName) + } +} diff --git a/internal/executor/fake_executor.go b/internal/executor/fake_executor.go new file mode 100644 index 00000000..888a9983 --- /dev/null +++ b/internal/executor/fake_executor.go @@ -0,0 +1,100 @@ +package executor + +import ( + "context" + "io" + "strings" +) + +// FakeExecute implements the utils.Executor interface +// to enable testing +type FakeExecute struct { + Cmd string + Args []string + Env []string + CheckBin bool + Stdin io.Reader + Stdout []byte // Set this for the dummy data to be returned + Stderr []byte // Set this for the dummy data to be returned + Quiet bool + ExitCode int +} + +func NewFakeExecutor(cmd string) Executor { + return &FakeExecute{Cmd: cmd, CheckBin: false} +} + +// nolint:gocyclo // TODO: break this method up and move into each $util_test.go +// FakeExecute method returns whatever you want it to return +// Set e.Stdout and e.Stderr to data to be returned +func (e *FakeExecute) ExecWithContext(_ context.Context) (*Result, error) { + // switch e.Cmd { + // case "ipmicfg": + // if e.Args[0] == "-summary" { + // buf := new(bytes.Buffer) + + // _, err := buf.ReadFrom(e.Stdin) + // if err != nil { + // return nil, err + // } + + // e.Stdout = buf.Bytes() + // } + // } + + return &Result{Stdout: e.Stdout, Stderr: e.Stderr, ExitCode: 0}, nil +} + +// CheckExecutable implements the Executor interface +func (e *FakeExecute) CheckExecutable() error { + return nil +} + +// CmdPath returns the absolute path to the executable +// this means the caller should not have disabled CheckBin. +func (e *FakeExecute) CmdPath() string { + return e.Cmd +} + +func (e *FakeExecute) SetArgs(a []string) { + e.Args = a +} + +func (e *FakeExecute) SetEnv(env []string) { + e.Env = env +} + +func (e *FakeExecute) SetQuiet() { + e.Quiet = true +} + +func (e *FakeExecute) SetVerbose() { + e.Quiet = false +} + +func (e *FakeExecute) SetStdout(b []byte) { + e.Stdout = b +} + +func (e *FakeExecute) SetStderr(b []byte) { + e.Stderr = b +} + +func (e *FakeExecute) SetStdin(r io.Reader) { + e.Stdin = r +} + +func (e *FakeExecute) DisableBinCheck() { + e.CheckBin = false +} + +func (e *FakeExecute) SetExitCode(i int) { + e.ExitCode = i +} + +func (e *FakeExecute) GetCmd() string { + cmd := []string{e.Cmd} + cmd = append(cmd, e.Args...) + + return strings.Join(cmd, " ") +} diff --git a/internal/sum/sum.go b/internal/sum/sum.go index 9d16f85b..50878cbc 100644 --- a/internal/sum/sum.go +++ b/internal/sum/sum.go @@ -1,18 +1,23 @@ package sum import ( + "bytes" "context" + "io" "os" "os/exec" "strings" + ex "github.com/bmc-toolbox/bmclib/v2/internal/executor" + "github.com/bmc-toolbox/common" "github.com/bmc-toolbox/common/config" "github.com/go-logr/logr" ) -// Conn for Sum connection details -type Exec struct { +// Mvcli is a mvcli command executor object +type Sum struct { + Executor ex.Executor SumPath string Log logr.Logger Host string @@ -21,22 +26,22 @@ type Exec struct { } // Option for setting optional Client values -type Option func(*Exec) +type Option func(*Sum) func WithSumPath(sumPath string) Option { - return func(c *Exec) { + return func(c *Sum) { c.SumPath = sumPath } } func WithLogger(log logr.Logger) Option { - return func(c *Exec) { + return func(c *Sum) { c.Log = log } } -func New(host, user, pass string, opts ...Option) (*Exec, error) { - sum := &Exec{ +func New(host, user, pass string, opts ...Option) (*Sum, error) { + sum := &Sum{ Host: host, Username: user, Password: pass, @@ -60,20 +65,42 @@ func New(host, user, pass string, opts ...Option) (*Exec, error) { } } + e := ex.NewExecutor(sum.SumPath) + e.SetEnv([]string{"LC_ALL=C.UTF-8"}) + // e.SetQuiet() + sum.Executor = e + return sum, nil } +// Return a Fake mvcli executor for tests +func NewFakeSum(r io.Reader) (*Sum, error) { + e := ex.NewFakeExecutor("sum") + b := bytes.Buffer{} + + _, err := b.ReadFrom(r) + if err != nil { + return nil, err + } + + e.SetStdout(b.Bytes()) + + return &Sum{ + Executor: e, + }, nil +} + // Open a connection to a BMC -func (c *Exec) Open(ctx context.Context) (err error) { +func (c *Sum) Open(ctx context.Context) (err error) { return nil } // Close a connection to a BMC -func (c *Exec) Close(ctx context.Context) (err error) { +func (c *Sum) Close(ctx context.Context) (err error) { return nil } -func (s *Exec) run(ctx context.Context, command string, additionalArgs ...string) (output string, err error) { +func (s *Sum) run(ctx context.Context, command string, additionalArgs ...string) (output string, err error) { // TODO(splaspood) use a tmp file here (as sum supports) to read the password sumArgs := []string{"-i", s.Host, "-u", s.Username, "-p", s.Password, "-c", command} sumArgs = append(sumArgs, additionalArgs...) @@ -83,31 +110,26 @@ func (s *Exec) run(ctx context.Context, command string, additionalArgs ...string sumArgs, ).Info("Calling sum") - cmd := exec.CommandContext(ctx, s.SumPath, sumArgs...) - b_out, err := cmd.CombinedOutput() - if err != nil || ctx.Err() != nil { - if err != nil { - return - } + s.Executor.SetArgs(sumArgs) - if ctx.Err() != nil { - return output, ctx.Err() - } + result, err := s.Executor.ExecWithContext(ctx) + if err != nil { + return string(result.Stderr), err } - return string(b_out), err + return string(result.Stdout), err } -func (s *Exec) GetCurrentBiosCfg(ctx context.Context) (output string, err error) { +func (s *Sum) GetCurrentBiosCfg(ctx context.Context) (output string, err error) { return s.run(ctx, "GetCurrentBiosCfg") } -func (s *Exec) LoadDefaultBiosCfg(ctx context.Context) (err error) { +func (s *Sum) LoadDefaultBiosCfg(ctx context.Context) (err error) { _, err = s.run(ctx, "LoadDefaultBiosCfg") return err } -func (s *Exec) ChangeBiosCfg(ctx context.Context, cfgFile string, reboot bool) (err error) { +func (s *Sum) ChangeBiosCfg(ctx context.Context, cfgFile string, reboot bool) (err error) { args := []string{"--file", cfgFile} if reboot { @@ -120,7 +142,7 @@ func (s *Exec) ChangeBiosCfg(ctx context.Context, cfgFile string, reboot bool) ( } // GetBiosConfiguration return bios configuration -func (s *Exec) GetBiosConfiguration(ctx context.Context) (biosConfig map[string]string, err error) { +func (s *Sum) GetBiosConfiguration(ctx context.Context) (biosConfig map[string]string, err error) { biosText, err := s.GetCurrentBiosCfg(ctx) if err != nil { return nil, err @@ -146,7 +168,7 @@ func (s *Exec) GetBiosConfiguration(ctx context.Context) (biosConfig map[string] } // SetBiosConfiguration set bios configuration -func (s *Exec) SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error) { +func (s *Sum) SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error) { vcm, err := config.NewVendorConfigManager("xml", common.VendorSupermicro, map[string]string{}) if err != nil { return err @@ -229,7 +251,7 @@ func (s *Exec) SetBiosConfiguration(ctx context.Context, biosConfig map[string]s return s.SetBiosConfigurationFromFile(ctx, xmlData) } -func (s *Exec) SetBiosConfigurationFromFile(ctx context.Context, cfg string) (err error) { +func (s *Sum) SetBiosConfigurationFromFile(ctx context.Context, cfg string) (err error) { // Open tmp file to hold cfg inputConfigTmpFile, err := os.CreateTemp("", "bmclib") if err != nil { @@ -248,10 +270,10 @@ func (s *Exec) SetBiosConfigurationFromFile(ctx context.Context, cfg string) (er return err } - return s.ChangeBiosCfg(ctx, inputConfigTmpFile.Name(), false) + return s.ChangeBiosCfg(ctx, inputConfigTmpFile.Name(), true) } // ResetBiosConfiguration reset bios configuration -func (s *Exec) ResetBiosConfiguration(ctx context.Context) (err error) { +func (s *Sum) ResetBiosConfiguration(ctx context.Context) (err error) { return s.LoadDefaultBiosCfg(ctx) } diff --git a/internal/sum/sum_test.go b/internal/sum/sum_test.go new file mode 100644 index 00000000..760d0e6a --- /dev/null +++ b/internal/sum/sum_test.go @@ -0,0 +1,104 @@ +package sum + +import ( + "context" + "os" + "testing" + + ex "github.com/bmc-toolbox/bmclib/v2/internal/executor" +) + +func newFakeSum(t *testing.T, fixtureName string) *Sum { + e := &Sum{ + Executor: ex.NewFakeExecutor("sum"), + } + + b, err := os.ReadFile("../../fixtures/internal/sum/" + fixtureName) + if err != nil { + t.Error(err) + } + + e.Executor.SetStdout(b) + + return e +} + +func TestExec_Run(t *testing.T) { + // Create a new instance of Exec + exec := &Sum{ + Host: "example.com", + Username: "user", + Password: "password", + SumPath: "/path/to/sum", + } + + // Create a new context + ctx := context.Background() + + // Define the command and additional arguments + command := "some-command" + additionalArgs := []string{"arg1", "arg2"} + + // Call the run function + output, err := exec.run(ctx, command, additionalArgs...) + + // Check the output and error + if err != nil { + t.Errorf("Expected no error, got: %v", err) + } + + expectedOutput := "some output" + if output != expectedOutput { + t.Errorf("Expected output: %s, got: %s", expectedOutput, output) + } +} + +func TestExec_SetBiosConfiguration(t *testing.T) { + // Create a new context + ctx := context.Background() + + // Define the BIOS configuration + biosConfig := map[string]string{ + "boot_mode": "UEFI", + "boot_order": "UEFI", + "intel_sgx": "Enabled", + "secure_boot": "Enabled", + "tpm": "Enabled", + "smt": "Disabled", + "sr_iov": "Enabled", + "raw:Menu1,SubMenu1,SubMenuMenu1,SettingName": "Value", + } + + exec := newFakeSum(t, "SetBiosConfiguration") + + // Call the SetBiosConfiguration function + err := exec.SetBiosConfiguration(ctx, biosConfig) + + // Check for any errors + if err != nil { + t.Errorf("Expected no error, got: %v", err) + } + + // Additional assertions can be added to verify the behavior of the function +} + +func TestExec_GetBiosConfiguration(t *testing.T) { + // Create a new context + ctx := context.Background() + + exec := newFakeSum(t, "GetBiosConfiguration") + + // Call the SetBiosConfiguration function + biosConfig, err := exec.GetBiosConfiguration(ctx) + + // Check for any errors + if err != nil { + t.Errorf("Expected no error, got: %v", err) + } + + // Confirm boot_mode exists + _, ok := biosConfig["boot_mode"] + if !ok { + t.Fail() + } +} diff --git a/providers/supermicro/supermicro.go b/providers/supermicro/supermicro.go index 0f24f2b5..e40f4a66 100644 --- a/providers/supermicro/supermicro.go +++ b/providers/supermicro/supermicro.go @@ -434,7 +434,7 @@ type serviceClient struct { csrfToken string client *http.Client redfish *redfishwrapper.Client - sum *sum.Exec + sum *sum.Sum } func newBmcServiceClient(host, port, user, pass string, client *http.Client) *serviceClient { From 5da51530567068b8a035d7611a36cfd5ccdf347c Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 5 Aug 2024 11:39:54 -0400 Subject: [PATCH 12/16] internal/sum/sum.go: s/Mvcli/Sum/g --- internal/sum/sum.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/sum/sum.go b/internal/sum/sum.go index 50878cbc..3c08e922 100644 --- a/internal/sum/sum.go +++ b/internal/sum/sum.go @@ -15,7 +15,7 @@ import ( "github.com/go-logr/logr" ) -// Mvcli is a mvcli command executor object +// Sum is a sum command executor object type Sum struct { Executor ex.Executor SumPath string @@ -73,7 +73,7 @@ func New(host, user, pass string, opts ...Option) (*Sum, error) { return sum, nil } -// Return a Fake mvcli executor for tests +// Return a Fake sum executor for tests func NewFakeSum(r io.Reader) (*Sum, error) { e := ex.NewFakeExecutor("sum") b := bytes.Buffer{} From 1796b4f61ba8ed50150cb0a5c9f7a195f435e746 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 5 Aug 2024 12:47:23 -0400 Subject: [PATCH 13/16] internal/sum/sum.go: Remove unused NewFakeSum func --- internal/sum/sum.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/internal/sum/sum.go b/internal/sum/sum.go index 3c08e922..a7d8f5aa 100644 --- a/internal/sum/sum.go +++ b/internal/sum/sum.go @@ -1,9 +1,7 @@ package sum import ( - "bytes" "context" - "io" "os" "os/exec" "strings" @@ -73,23 +71,6 @@ func New(host, user, pass string, opts ...Option) (*Sum, error) { return sum, nil } -// Return a Fake sum executor for tests -func NewFakeSum(r io.Reader) (*Sum, error) { - e := ex.NewFakeExecutor("sum") - b := bytes.Buffer{} - - _, err := b.ReadFrom(r) - if err != nil { - return nil, err - } - - e.SetStdout(b.Bytes()) - - return &Sum{ - Executor: e, - }, nil -} - // Open a connection to a BMC func (c *Sum) Open(ctx context.Context) (err error) { return nil From fe3202b903f525f026f05fcc831220a11716b23b Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 5 Aug 2024 12:48:27 -0400 Subject: [PATCH 14/16] internal/sum/sum.go: Provide a link and description re supermicro update mananger(sum) --- internal/sum/sum.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/sum/sum.go b/internal/sum/sum.go index a7d8f5aa..0eb28179 100644 --- a/internal/sum/sum.go +++ b/internal/sum/sum.go @@ -1,5 +1,8 @@ package sum +// SUM is Supermicro Update Manager +// https://www.supermicro.com/en/solutions/management-software/supermicro-update-manager + import ( "context" "os" From 9e1f09044ff5d21789fe15b16d8ae27b0c1426ca Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 5 Aug 2024 16:08:44 -0400 Subject: [PATCH 15/16] internal/sum/sum_test.go: Fix test for Sum.Run(); Upgrade bmc-toolbox/common version --- go.mod | 2 +- go.sum | 2 ++ internal/sum/sum_test.go | 20 +++----------------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 10b13773..ee13905b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( dario.cat/mergo v1.0.0 github.com/Jeffail/gabs/v2 v2.7.0 - github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8 + github.com/bmc-toolbox/common v0.0.0-20240805193945-ce25765471a7 github.com/bombsimon/logrusr/v2 v2.0.1 github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.4.1 diff --git a/go.sum b/go.sum index 791c98ad..293092a1 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 h1:a0MBqYm44o0N github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22/go.mod h1:/B7V22rcz4860iDqstGvia/2+IYWXf3/JdQCVd/1D2A= github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8 h1:KK812W5Tpk0n5qcS0vZ0IYqhoZNkV66NuCIon99OGQ8= github.com/bmc-toolbox/common v0.0.0-20240723135842-8256ba794af8/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= +github.com/bmc-toolbox/common v0.0.0-20240805193945-ce25765471a7 h1:+NcnInwZxn25daBCb3d1y3x9QF23uob1ghdiimj2Dwo= +github.com/bmc-toolbox/common v0.0.0-20240805193945-ce25765471a7/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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= diff --git a/internal/sum/sum_test.go b/internal/sum/sum_test.go index 760d0e6a..c7bee90e 100644 --- a/internal/sum/sum_test.go +++ b/internal/sum/sum_test.go @@ -24,33 +24,19 @@ func newFakeSum(t *testing.T, fixtureName string) *Sum { } func TestExec_Run(t *testing.T) { - // Create a new instance of Exec - exec := &Sum{ - Host: "example.com", - Username: "user", - Password: "password", - SumPath: "/path/to/sum", - } + // Create a new instance of Sum + exec := newFakeSum(t, "GetBIOSInfo") // Create a new context ctx := context.Background() - // Define the command and additional arguments - command := "some-command" - additionalArgs := []string{"arg1", "arg2"} - // Call the run function - output, err := exec.run(ctx, command, additionalArgs...) + _, err := exec.run(ctx, "GetBIOSInfo") // Check the output and error if err != nil { t.Errorf("Expected no error, got: %v", err) } - - expectedOutput := "some output" - if output != expectedOutput { - t.Errorf("Expected output: %s, got: %s", expectedOutput, output) - } } func TestExec_SetBiosConfiguration(t *testing.T) { From 00ac9db9291f4aa0692dce71b9a4df26c9af999b Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 7 Aug 2024 10:22:09 -0400 Subject: [PATCH 16/16] fixtures/internal/sum/GetBIOSInfo: Add mock data for GetBIOSInfo command --- fixtures/internal/sum/GetBIOSInfo | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 fixtures/internal/sum/GetBIOSInfo diff --git a/fixtures/internal/sum/GetBIOSInfo b/fixtures/internal/sum/GetBIOSInfo new file mode 100644 index 00000000..f3b58f0c --- /dev/null +++ b/fixtures/internal/sum/GetBIOSInfo @@ -0,0 +1,7 @@ +Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64) +Copyright(C) 2013-2024 Super Micro Computer, Inc. All rights reserved. +.... +Managed system..........................10.145.129.168 + Board ID............................1B0F + BIOS build date.....................2022/09/16 + BIOS version........................1.9