airshipctl/pkg/remote/remote_direct.go

128 lines
3.0 KiB
Go

package remote
import (
"context"
"fmt"
"net/url"
"strings"
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/environment"
alog "opendev.org/airship/airshipctl/pkg/log"
"opendev.org/airship/airshipctl/pkg/remote/redfish"
)
const (
AirshipRemoteTypeRedfish string = "redfish"
AirshipHostKind string = "BareMetalHost"
)
// Interface to be implemented by remoteDirect implementation
type Client interface {
DoRemoteDirect() error
}
// Get remotedirect client based on config
func getRemoteDirectClient(remoteConfig *config.RemoteDirect, remoteURL string) (Client, error) {
var client Client
switch remoteConfig.RemoteType {
case AirshipRemoteTypeRedfish:
alog.Debug("Remote type redfish")
rfURL, err := url.Parse(remoteURL)
if err != nil {
return nil, err
}
baseURL := fmt.Sprintf("%s://%s", rfURL.Scheme, rfURL.Host)
schemeSplit := strings.Split(rfURL.Scheme, redfish.RedfishURLSchemeSeparator)
if len(schemeSplit) > 1 {
baseURL = fmt.Sprintf("%s://%s", schemeSplit[len(schemeSplit)-1], rfURL.Host)
}
urlPath := strings.Split(rfURL.Path, "/")
nodeID := urlPath[len(urlPath)-1]
client, err = redfish.NewRedfishRemoteDirectClient(
context.Background(),
baseURL,
nodeID,
remoteConfig.IsoURL)
if err != nil {
alog.Debugf("redfish remotedirect client creation failed")
return nil, err
}
default:
return nil, NewRemoteDirectErrorf("invalid remote type")
}
return client, nil
}
func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (*config.RemoteDirect, string, error) {
cfg := settings.Config()
bootstrapSettings, err := cfg.CurrentContextBootstrapInfo()
if err != nil {
return nil, "", err
}
remoteConfig := bootstrapSettings.RemoteDirect
if remoteConfig == nil {
return nil, "", config.ErrMissingConfig{What: "RemoteDirect options not defined in bootstrap config"}
}
root, err := cfg.CurrentContextEntryPoint(config.Ephemeral, "")
if err != nil {
return nil, "", err
}
docBundle, err := document.NewBundleByPath(root)
if err != nil {
return nil, "", err
}
selector := document.NewEphemeralBMHSelector()
docs, err := docBundle.Select(selector)
if err != nil {
return nil, "", err
}
if len(docs) == 0 {
return nil, "", document.ErrDocNotFound{
Selector: selector,
}
}
// NOTE If filter returned more than one document chose first
remoteURL, err := docs[0].GetString("spec.bmc.address")
if err != nil {
return nil, "", err
}
return remoteConfig, remoteURL, nil
}
// Top level function to execute remote direct based on remote type
func DoRemoteDirect(settings *environment.AirshipCTLSettings) error {
remoteConfig, remoteURL, err := getRemoteDirectConfig(settings)
if err != nil {
return err
}
client, err := getRemoteDirectClient(remoteConfig, remoteURL)
if err != nil {
return err
}
err = client.DoRemoteDirect()
if err != nil {
alog.Debugf("remote direct failed: %s", err)
return err
}
alog.Print("Remote direct successfully completed")
return nil
}