From afbd09b784d68b1dfae1a5f3dce983d6f1a64a24 Mon Sep 17 00:00:00 2001 From: Kirsten Laskoski Date: Fri, 31 Jan 2025 16:05:12 -0500 Subject: [PATCH] bmc: add WaitForSystemPowerState function When performing a reset action (power on, power off, reset, etc.), it is useful to verify the action actually took place. WaitForSystemPowerState allows one to poll the BMC until the desired power state occurs, similar to functions already used in cnf/ran in eco-gotests. --- pkg/bmc/bmc.go | 21 +++++++++++++++++++++ pkg/bmc/bmc_test.go | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/pkg/bmc/bmc.go b/pkg/bmc/bmc.go index 813160d8b..d30cfbfb7 100644 --- a/pkg/bmc/bmc.go +++ b/pkg/bmc/bmc.go @@ -586,6 +586,27 @@ func (bmc *BMC) SystemPowerState() (string, error) { return string(system.PowerState), nil } +// WaitForSystemPowerState waits up to timeout until the BMC returns the provided system power state. +func (bmc *BMC) WaitForSystemPowerState(powerState redfish.PowerState, timeout time.Duration) error { + if valid, err := bmc.validateRedfish(); !valid { + return err + } + + glog.V(100).Infof("Waiting up to %s until BMC returns power state %s", timeout, powerState) + + return wait.PollUntilContextTimeout( + context.TODO(), 10*time.Second, timeout, true, func(ctx context.Context) (bool, error) { + systemPowerState, err := bmc.SystemPowerState() + if err != nil { + glog.V(100).Infof("Failed to get system power state from BMC: %v", err) + + return false, nil + } + + return systemPowerState == string(powerState), nil + }) +} + // PowerUsage returns the current power usage of the chassis in watts using the Redfish API. This method uses the first // chassis with a power link and the power control index for the BMC client. func (bmc *BMC) PowerUsage() (float32, error) { diff --git a/pkg/bmc/bmc_test.go b/pkg/bmc/bmc_test.go index decda0991..8ab632a0c 100644 --- a/pkg/bmc/bmc_test.go +++ b/pkg/bmc/bmc_test.go @@ -1,6 +1,7 @@ package bmc import ( + "context" _ "embed" "encoding/json" "fmt" @@ -594,6 +595,22 @@ func TestBMCSystemPowerState(t *testing.T) { assert.Equal(t, expectedPowerState, powerState) } +func TestBMCWaitForSystemPowerState(t *testing.T) { + // Create fake redfish endpoint. + redfishServer := createFakeRedfishLocalServer(false, redfishAPIResponseCallbacks{}) + defer redfishServer.Close() + + host := strings.Split(redfishServer.URL, "//")[1] + bmc := New(host).WithRedfishUser(defaultUsername, defaultPassword) + + // The fake endpoint should be On, so will succeed when waiting till On and time out waiting for Off. + err := bmc.WaitForSystemPowerState(redfish.OnPowerState, time.Second) + assert.NoError(t, err) + + err = bmc.WaitForSystemPowerState(redfish.OffPowerState, time.Second) + assert.Equal(t, context.DeadlineExceeded, err) +} + func TestBMCPowerUsage(t *testing.T) { // Create a fake redfish api endpoint with secureBoot "disabled" redfishServer := createFakeRedfishLocalServer(false, redfishAPIResponseCallbacks{})