Drew Walters f3262bc015 Retrieve actual virtual media ID and types
The "GetVirtualID" method is stubbed for our Redifsh implementation and
always returns the same values. This change uses the Redfish client to
retrieve the correct virtual media ID and type.

Closes #141

Change-Id: I319b89c13349e7b2f5bf6eb8ced97c949e5f44b5
Signed-off-by: Drew Walters <andrew.walters@att.com>
2020-04-02 15:13:41 +00:00

174 lines
4.0 KiB
Go

package redfish
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/url"
redfishApi "opendev.org/airship/go-redfish/api"
redfishClient "opendev.org/airship/go-redfish/client"
alog "opendev.org/airship/airshipctl/pkg/log"
)
type RemoteDirect struct {
// Context
Context context.Context
// remote URL
RemoteURL url.URL
// ephemeral Host ID
EphemeralNodeID string
// ISO URL
IsoPath string
// Redfish Client implementation
RedfishAPI redfishApi.RedfishAPI
// optional Username Authentication
Username string
// optional Password
Password string
}
// Top level function to handle Redfish remote direct
func (cfg RemoteDirect) DoRemoteDirect() error {
alog.Debugf("Using Redfish Endpoint: '%s'", cfg.RemoteURL.String())
/* Get system details */
systemID := cfg.EphemeralNodeID
system, _, err := cfg.RedfishAPI.GetSystem(cfg.Context, systemID)
if err != nil {
return ErrRedfishClient{Message: fmt.Sprintf("Get System[%s] failed with err: %v", systemID, err)}
}
alog.Debugf("Ephemeral Node System ID: '%s'", systemID)
/* get manager for system */
managerID := GetResourceIDFromURL(system.Links.ManagedBy[0].OdataId)
alog.Debugf("Ephemeral node managerID: '%s'", managerID)
/* Get manager's Cd or DVD virtual media ID */
vMediaID, vMediaType, err := GetVirtualMediaID(cfg.Context, cfg.RedfishAPI, managerID)
if err != nil {
return err
}
alog.Debugf("Ephemeral Node Virtual Media Id: '%s'", vMediaID)
/* Load ISO in manager's virtual media */
err = SetVirtualMedia(cfg.Context, cfg.RedfishAPI, managerID, vMediaID, cfg.IsoPath)
if err != nil {
return err
}
alog.Debugf("Successfully loaded virtual media: '%s'", cfg.IsoPath)
/* Set system's bootsource to selected media */
err = SetSystemBootSourceForMediaType(cfg.Context, cfg.RedfishAPI, systemID, vMediaType)
if err != nil {
return err
}
/* Reboot system */
err = RebootSystem(cfg.Context, cfg.RedfishAPI, systemID)
if err != nil {
return err
}
alog.Debug("Restarted ephemeral host")
return nil
}
// NewRedfishRemoteDirectClient creates a new Redfish remote direct client.
func NewRedfishRemoteDirectClient(
remoteURL string,
ephNodeID string,
username string,
password string,
isoPath string,
insecure bool,
useproxy bool,
) (RemoteDirect, error) {
if remoteURL == "" {
return RemoteDirect{},
ErrRedfishMissingConfig{
What: "redfish remote url empty",
}
}
if ephNodeID == "" {
return RemoteDirect{},
ErrRedfishMissingConfig{
What: "redfish ephemeral node id empty",
}
}
var ctx context.Context
if username != "" && password != "" {
ctx = context.WithValue(
context.Background(),
redfishClient.ContextBasicAuth,
redfishClient.BasicAuth{UserName: username, Password: password},
)
} else {
ctx = context.Background()
}
if isoPath == "" {
return RemoteDirect{},
ErrRedfishMissingConfig{
What: "redfish ephemeral node iso Path empty",
}
}
cfg := &redfishClient.Configuration{
BasePath: remoteURL,
DefaultHeader: make(map[string]string),
UserAgent: "airshipctl/client",
}
// see https://github.com/golang/go/issues/26013
// We clone the default transport to ensure when we customize the transport
// that we are providing it sane timeouts and other defaults that we would
// normally get when not overriding the transport
defaultTransportCopy := (http.DefaultTransport.(*http.Transport))
transport := defaultTransportCopy.Clone()
if insecure {
transport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true, //nolint:gosec
}
}
if !useproxy {
transport.Proxy = nil
}
cfg.HTTPClient = &http.Client{
Transport: transport,
}
var api redfishApi.RedfishAPI = redfishClient.NewAPIClient(cfg).DefaultApi
parsedURL, err := url.Parse(remoteURL)
if err != nil {
return RemoteDirect{},
ErrRedfishMissingConfig{
What: fmt.Sprintf("invalid url format: %v", err),
}
}
client := RemoteDirect{
Context: ctx,
RemoteURL: *parsedURL,
EphemeralNodeID: ephNodeID,
IsoPath: isoPath,
RedfishAPI: api,
}
return client, nil
}