Implement RunAction method of the baremetal interface

Change-Id: I86b2cd7824c68ccd4fac875a5ad1d3ff9cd69072
Relates-To: #397
Relates-To: #362
Relates-To: #359
This commit is contained in:
Kostiantyn Kalynovskyi 2020-11-10 16:40:22 -06:00 committed by Kostyantyn Kalynovskyi
parent 991fcdcd9e
commit fa03b40f4a
4 changed files with 156 additions and 3 deletions

View File

@ -19,7 +19,6 @@ import (
"opendev.org/airship/airshipctl/pkg/config" "opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/document" "opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/errors"
"opendev.org/airship/airshipctl/pkg/inventory/ifc" "opendev.org/airship/airshipctl/pkg/inventory/ifc"
"opendev.org/airship/airshipctl/pkg/log" "opendev.org/airship/airshipctl/pkg/log"
remoteifc "opendev.org/airship/airshipctl/pkg/remote/ifc" remoteifc "opendev.org/airship/airshipctl/pkg/remote/ifc"
@ -89,7 +88,33 @@ func (i Inventory) RunOperation(
op ifc.BaremetalOperation, op ifc.BaremetalOperation,
selector ifc.BaremetalHostSelector, selector ifc.BaremetalHostSelector,
_ ifc.BaremetalBatchRunOptions) error { _ ifc.BaremetalBatchRunOptions) error {
return errors.ErrNotImplemented{What: "RunOperation of the baremetal inventory interface"} log.Debugf("Running operation '%s' against hosts selected by selector '%v'", op, selector)
hostAction, err := action(ctx, op)
if err != nil {
return err
}
hosts, err := i.Select(selector)
if err != nil {
return err
}
if len(hosts) == 0 {
log.Printf("Filtering using selector %v' didn't return any hosts to perform operation '%s'", selector, op)
return ErrNoBaremetalHostsFound{Selector: selector}
}
// TODO add concurent action execution
// TODO consider adding FailFast flag to BaremetalBatchRunOptions that would allow
// not fail on first error, but accumulate errors and return them at the end.
for _, host := range hosts {
if hostErr := hostAction(host); hostErr != nil {
return hostErr
}
}
return nil
} }
// Host implements baremetal host interface // Host implements baremetal host interface
@ -138,6 +163,29 @@ func (i Inventory) newHost(doc document.Document) (Host, error) {
return Host{Client: client}, nil return Host{Client: client}, nil
} }
func action(ctx context.Context, op ifc.BaremetalOperation) (func(remoteifc.Client) error, error) {
switch op {
case ifc.BaremetalOperationReboot:
return func(host remoteifc.Client) error {
return host.RebootSystem(ctx)
}, nil
case ifc.BaremetalOperationPowerOff:
return func(host remoteifc.Client) error {
return host.SystemPowerOff(ctx)
}, nil
case ifc.BaremetalOperationPowerOn:
return func(host remoteifc.Client) error {
return host.SystemPowerOn(ctx)
}, nil
case ifc.BaremetalOperationEjectVirtualMedia:
return func(host remoteifc.Client) error {
return host.EjectVirtualMedia(ctx)
}, nil
default:
return nil, ErrBaremetalOperationNotSupported{Operation: op}
}
}
func toDocumentSelector(selector ifc.BaremetalHostSelector) document.Selector { func toDocumentSelector(selector ifc.BaremetalHostSelector) document.Selector {
return document.NewSelector(). return document.NewSelector().
ByKind(document.BareMetalHostKind). ByKind(document.BareMetalHostKind).

View File

@ -15,6 +15,7 @@
package baremetal package baremetal
import ( import (
"context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -119,6 +120,101 @@ func TestSelectOne(t *testing.T) {
} }
} }
func TestRunAction(t *testing.T) {
tests := []struct {
name, remoteDriver, expectedErr string
operation ifc.BaremetalOperation
selector ifc.BaremetalHostSelector
}{
{
name: "success return one host",
remoteDriver: "redfish",
operation: ifc.BaremetalOperation("not supported"),
selector: (ifc.BaremetalHostSelector{}).ByName("master-0"),
expectedErr: "Baremetal operation not supported",
},
{
name: "success return one host",
remoteDriver: "redfish",
operation: ifc.BaremetalOperationPowerOn,
selector: (ifc.BaremetalHostSelector{}).ByName("does not exist"),
expectedErr: "No baremetal hosts matched selector",
},
{
name: "success return one host",
remoteDriver: "redfish",
operation: ifc.BaremetalOperationPowerOn,
selector: (ifc.BaremetalHostSelector{}).ByName("master-0"),
expectedErr: "HTTP request failed",
},
}
bundle := testBundle(t)
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
mgmCfg := config.ManagementConfiguration{Type: tt.remoteDriver}
inventory := NewInventory(mgmCfg, bundle)
err := inventory.RunOperation(
context.Background(),
tt.operation,
tt.selector,
ifc.BaremetalBatchRunOptions{})
if tt.expectedErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedErr)
} else {
assert.NoError(t, err)
}
})
}
}
func TestAction(t *testing.T) {
tests := []struct {
name string
action ifc.BaremetalOperation
expectErr bool
}{
{
name: "poweron",
action: ifc.BaremetalOperationPowerOn,
},
{
name: "poweroff",
action: ifc.BaremetalOperationPowerOff,
},
{
name: "ejectvirtualmedia",
action: ifc.BaremetalOperationEjectVirtualMedia,
},
{
name: "reboot",
action: ifc.BaremetalOperationReboot,
},
{
name: "reboot",
action: ifc.BaremetalOperation("not supported"),
expectErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
actionFunc, err := action(context.Background(), tt.action)
if tt.expectErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
// TODO inject fake host interface here to validate
// that correct actions were selected
assert.NotNil(t, actionFunc)
}
})
}
}
func testBundle(t *testing.T) document.Bundle { func testBundle(t *testing.T) document.Bundle {
t.Helper() t.Helper()
bundle, err := document.NewBundleByPath("testdata") bundle, err := document.NewBundleByPath("testdata")

View File

@ -40,3 +40,12 @@ type ErrNoBaremetalHostsFound struct {
func (e ErrNoBaremetalHostsFound) Error() string { func (e ErrNoBaremetalHostsFound) Error() string {
return fmt.Sprintf("No baremetal hosts matched selector %v", e.Selector) return fmt.Sprintf("No baremetal hosts matched selector %v", e.Selector)
} }
// ErrBaremetalOperationNotSupported is returned when baremetal operation is not supported
type ErrBaremetalOperationNotSupported struct {
Operation ifc.BaremetalOperation
}
func (e ErrBaremetalOperationNotSupported) Error() string {
return fmt.Sprintf("Baremetal operation not supported: '%s'", e.Operation)
}

View File

@ -9,7 +9,7 @@ spec:
online: true online: true
bootMACAddress: 00:3b:8b:0c:ec:8b bootMACAddress: 00:3b:8b:0c:ec:8b
bmc: bmc:
address: redfish+http://nolocalhost:8888/redfish/v1/Systems/ephemeral address: redfish+http://nolocalhost:32201/redfish/v1/Systems/ephemeral
credentialsName: master-0-bmc-secret credentialsName: master-0-bmc-secret
--- ---
apiVersion: v1 apiVersion: v1