From 4c70079261dba0b857acf5c968ca5962e20a8894 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 11 Sep 2023 10:21:34 +0200 Subject: [PATCH 1/6] redfishwrapper: add method to return list of virtual media currently inserted --- internal/redfishwrapper/virtual_media.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/internal/redfishwrapper/virtual_media.go b/internal/redfishwrapper/virtual_media.go index 4954eb3f..562cd8fa 100644 --- a/internal/redfishwrapper/virtual_media.go +++ b/internal/redfishwrapper/virtual_media.go @@ -74,3 +74,27 @@ func (c *Client) SetVirtualMedia(ctx context.Context, kind string, mediaURL stri return true, nil } + +func (c *Client) InsertedVirtualMedia(ctx context.Context) ([]string, error) { + managers, err := c.Managers(ctx) + if err != nil { + return nil, err + } + + var inserted []string + + for _, manager := range managers { + virtualMedia, err := manager.VirtualMedia() + if err != nil { + return nil, err + } + + for _, media := range virtualMedia { + if media.Inserted { + inserted = append(inserted, media.ID) + } + } + } + + return inserted, nil +} From 8e867844161b1d72e341e07944c5c1344a126ff3 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 11 Sep 2023 10:23:49 +0200 Subject: [PATCH 2/6] supermicro: Add methods to upload and unmount a floppy image --- providers/supermicro/floppy.go | 154 +++++++++++++++++++++++++++++ providers/supermicro/supermicro.go | 37 ++++++- 2 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 providers/supermicro/floppy.go diff --git a/providers/supermicro/floppy.go b/providers/supermicro/floppy.go new file mode 100644 index 00000000..72ee8434 --- /dev/null +++ b/providers/supermicro/floppy.go @@ -0,0 +1,154 @@ +package supermicro + +import ( + "bytes" + "context" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/textproto" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +var ( + errFloppyImageMounted = errors.New("floppy image is currently mounted") +) + +func (c *Client) floppyImageMounted(ctx context.Context) (bool, error) { + if err := c.openRedfish(ctx); err != nil { + return false, err + } + + inserted, err := c.redfish.InsertedVirtualMedia(ctx) + if err != nil { + return false, err + } + + for _, media := range inserted { + if strings.Contains(strings.ToLower(media), "floppy") { + return true, nil + } + } + + return false, nil +} + +func (c *Client) UploadFloppyImage(ctx context.Context, image io.Reader) error { + mounted, err := c.floppyImageMounted(ctx) + if err != nil { + return err + } + + if mounted { + return errFloppyImageMounted + } + + var payloadBuffer bytes.Buffer + + formParts := []struct { + name string + data io.Reader + }{ + { + name: "img_file", + data: image, + }, + { + name: "csrf-token", + data: bytes.NewBufferString(c.csrfToken), + }, + } + + payloadWriter := multipart.NewWriter(&payloadBuffer) + + for _, part := range formParts { + var partWriter io.Writer + + switch part.name { + case "img_file": + file, ok := part.data.(*os.File) + if !ok { + return errors.Wrap(ErrMultipartForm, "expected io.Reader for a floppy image file") + } + + if partWriter, err = payloadWriter.CreateFormFile(part.name, filepath.Base(file.Name())); err != nil { + return errors.Wrap(ErrMultipartForm, err.Error()) + } + + case "csrf-token": + // Add csrf token field + h := make(textproto.MIMEHeader) + // BMCs with newer firmware (>=1.74.09) accept the form with this name value + // h.Set("Content-Disposition", `form-data; name="CSRF-TOKEN"`) + // + // the BMCs running older firmware (<=1.23.06) versions expects the name value in this format + // and the newer firmware (>=1.74.09) seem to be backwards compatible with this name value format. + h.Set("Content-Disposition", `form-data; name="CSRF_TOKEN"`) + + if partWriter, err = payloadWriter.CreatePart(h); err != nil { + return errors.Wrap(ErrMultipartForm, err.Error()) + } + default: + return errors.Wrap(ErrMultipartForm, "unexpected form part: "+part.name) + } + + if _, err = io.Copy(partWriter, part.data); err != nil { + return err + } + } + payloadWriter.Close() + + resp, statusCode, err := c.query( + ctx, + "cgi/uimapin.cgi", + http.MethodPost, + bytes.NewReader(payloadBuffer.Bytes()), + map[string]string{"Content-Type": payloadWriter.FormDataContentType()}, + 0, + ) + + if err != nil { + return errors.Wrap(ErrMultipartForm, err.Error()) + } + + if statusCode != http.StatusOK { + return fmt.Errorf("non 200 response: %d %s", statusCode, resp) + } + + return nil +} + +func (c *Client) UnmountFloppyImage(ctx context.Context) error { + mounted, err := c.floppyImageMounted(ctx) + if err != nil { + return err + } + + if !mounted { + return nil + } + + resp, statusCode, err := c.query( + ctx, + "cgi/uimapout.cgi", + http.MethodPost, + nil, + nil, + 0, + ) + + if err != nil { + return err + } + + if statusCode != http.StatusOK { + return fmt.Errorf("non 200 response: %d %s", statusCode, resp) + } + + return nil +} diff --git a/providers/supermicro/supermicro.go b/providers/supermicro/supermicro.go index 3efb30af..ca03fc86 100644 --- a/providers/supermicro/supermicro.go +++ b/providers/supermicro/supermicro.go @@ -18,6 +18,7 @@ import ( "time" "github.com/bmc-toolbox/bmclib/v2/internal/httpclient" + "github.com/bmc-toolbox/bmclib/v2/internal/redfishwrapper" "github.com/bmc-toolbox/bmclib/v2/providers" "github.com/go-logr/logr" "github.com/jacobweinstock/registrar" @@ -40,6 +41,8 @@ var ( providers.FeatureScreenshot, providers.FeatureFirmwareInstall, providers.FeatureFirmwareInstallStatus, + providers.FeatureUploadFloppyImage, + providers.FeatureUnmountFloppyImage, } ) @@ -49,12 +52,15 @@ var ( // - screen capture // - bios firmware install // - bmc firmware install -// product: SYS-510T-MR, baseboard part number: X12STH-SYS +// +// product: SYS-510T-MR, baseboard part number: X12STH-SYS, X12SPO-NTF // - screen capture +// - floppy image mount // product: 6029P-E1CR12L, baseboard part number: X11DPH-T // . - screen capture // - bios firmware install // - bmc firmware install +// - floppy image mount type Config struct { HttpClient *http.Client @@ -93,7 +99,9 @@ type Client struct { port string csrfToken string model string + redfish *redfishwrapper.Client log logr.Logger + _ [32]byte } // New returns connection with a Supermicro client initialized @@ -163,6 +171,30 @@ func (c *Client) Open(ctx context.Context) (err error) { return nil } +func (c *Client) openRedfish(ctx context.Context) error { + if c.redfish != nil && c.redfish.SessionActive() == nil { + return nil + } + + rfclient := redfishwrapper.NewClient(c.host, "", c.user, c.pass) + if err := rfclient.Open(ctx); err != nil { + return err + } + + c.redfish = rfclient + + return nil +} + +func (c *Client) closeRedfish(ctx context.Context) { + if c.redfish != nil { + // error not checked on purpose + _ = c.redfish.Close(ctx) + + c.redfish = nil + } +} + func parseToken(body []byte) string { var key string if bytes.Contains(body, []byte(`CSRF-TOKEN`)) { @@ -205,6 +237,8 @@ func (c *Client) Close(ctx context.Context) error { return errors.Wrap(bmclibErrs.ErrLogoutFailed, strconv.Itoa(status)) } + c.closeRedfish(ctx) + return nil } @@ -383,6 +417,7 @@ func (c *Client) query(ctx context.Context, endpoint, method string, payload io. if cookie.Name == "SID" && cookie.Value != "" { req.AddCookie(cookie) } + } var reqDump []byte From 1930922981cb48aa35703a8918f9a517178fa16a Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 11 Sep 2023 10:24:51 +0200 Subject: [PATCH 3/6] Add methods to upload and unmount a floppy image --- bmc/floppy.go | 136 +++++++++++++++++++++++++++++++++++++++++ client.go | 15 +++++ providers/providers.go | 6 ++ 3 files changed, 157 insertions(+) create mode 100644 bmc/floppy.go diff --git a/bmc/floppy.go b/bmc/floppy.go new file mode 100644 index 00000000..0965de37 --- /dev/null +++ b/bmc/floppy.go @@ -0,0 +1,136 @@ +package bmc + +import ( + "context" + "fmt" + "io" + + "github.com/hashicorp/go-multierror" + "github.com/pkg/errors" +) + +// FloppyImageUploader defines methods to upload a floppy image +type FloppyImageUploader interface { + UploadFloppyImage(ctx context.Context, image io.Reader) (err error) +} + +// floppyImageUploaderProvider is an internal struct to correlate an implementation/provider and its name +type floppyImageUploaderProvider struct { + name string + impl FloppyImageUploader +} + +// uploadFloppyImage is a wrapper method to invoke methods for the FloppyImageUploader interface +func uploadFloppyImage(ctx context.Context, image io.Reader, p []floppyImageUploaderProvider) (metadata Metadata, err error) { + var metadataLocal Metadata + + for _, elem := range p { + if elem.impl == nil { + continue + } + + select { + case <-ctx.Done(): + err = multierror.Append(err, ctx.Err()) + + return metadata, err + default: + metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name) + uploadErr := elem.impl.UploadFloppyImage(ctx, image) + if uploadErr != nil { + err = multierror.Append(err, errors.WithMessagef(uploadErr, "provider: %v", elem.name)) + continue + } + + metadataLocal.SuccessfulProvider = elem.name + return metadataLocal, nil + } + } + + return metadataLocal, multierror.Append(err, errors.New("failed to upload floppy image")) +} + +// UploadFloppyImageFromInterfaces identifies implementations of the FloppyImageUploader interface and passes the found implementations to the uploadFloppyImage() wrapper +func UploadFloppyImageFromInterfaces(ctx context.Context, image io.Reader, p []interface{}) (metadata Metadata, err error) { + providers := make([]floppyImageUploaderProvider, 0) + for _, elem := range p { + temp := floppyImageUploaderProvider{name: getProviderName(elem)} + switch p := elem.(type) { + case FloppyImageUploader: + temp.impl = p + providers = append(providers, temp) + default: + e := fmt.Sprintf("not a FloppyImageUploader implementation: %T", p) + err = multierror.Append(err, errors.New(e)) + } + } + + if len(providers) == 0 { + return metadata, multierror.Append(err, errors.New("no FloppyImageUploader implementations found")) + } + + return uploadFloppyImage(ctx, image, providers) +} + +// FloppyImageUploader defines methods to unmount a floppy image +type FloppyImageUnmounter interface { + UnmountFloppyImage(ctx context.Context) (err error) +} + +// floppyImageUnmounterProvider is an internal struct to correlate an implementation/provider and its name +type floppyImageUnmounterProvider struct { + name string + impl FloppyImageUnmounter +} + +// unmountFloppyImage is a wrapper method to invoke methods for the FloppyImageUnmounter interface +func unmountFloppyImage(ctx context.Context, p []floppyImageUnmounterProvider) (metadata Metadata, err error) { + var metadataLocal Metadata + + for _, elem := range p { + if elem.impl == nil { + continue + } + + select { + case <-ctx.Done(): + err = multierror.Append(err, ctx.Err()) + + return metadata, err + default: + metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name) + uploadErr := elem.impl.UnmountFloppyImage(ctx) + if uploadErr != nil { + err = multierror.Append(err, errors.WithMessagef(uploadErr, "provider: %v", elem.name)) + continue + } + + metadataLocal.SuccessfulProvider = elem.name + return metadataLocal, nil + } + } + + return metadataLocal, multierror.Append(err, errors.New("failed to unmount floppy image")) +} + +// UploadFloppyImageFromInterfaces identifies implementations of the FloppyImageUnmounter interface and passes the found implementations to the unmountFloppyImage() wrapper +func UnmountFloppyImageFromInterfaces(ctx context.Context, p []interface{}) (metadata Metadata, err error) { + providers := make([]floppyImageUnmounterProvider, 0) + for _, elem := range p { + temp := floppyImageUnmounterProvider{name: getProviderName(elem)} + switch p := elem.(type) { + case FloppyImageUnmounter: + temp.impl = p + providers = append(providers, temp) + default: + e := fmt.Sprintf("not a FloppyImageUnmounter implementation: %T", p) + err = multierror.Append(err, errors.New(e)) + } + } + + if len(providers) == 0 { + return metadata, multierror.Append(err, errors.New("no FloppyImageUnmounter implementations found")) + } + + return unmountFloppyImage(ctx, providers) +} diff --git a/client.go b/client.go index c305fce2..e0c9e5a0 100644 --- a/client.go +++ b/client.go @@ -450,5 +450,20 @@ func (c *Client) Screenshot(ctx context.Context) (image []byte, fileType string, func (c *Client) ClearSystemEventLog(ctx context.Context) (err error) { metadata, err := bmc.ClearSystemEventLogFromInterfaces(ctx, c.perProviderTimeout(ctx), c.registry().GetDriverInterfaces()) c.setMetadata(metadata) + + return err +} + +func (c *Client) UploadFloppyImage(ctx context.Context, image io.Reader) (err error) { + metadata, err := bmc.UploadFloppyImageFromInterfaces(ctx, image, c.registry().GetDriverInterfaces()) + c.setMetadata(metadata) + + return err +} + +func (c *Client) UnmountFloppyImage(ctx context.Context) (err error) { + metadata, err := bmc.UnmountFloppyImageFromInterfaces(ctx, c.registry().GetDriverInterfaces()) + c.setMetadata(metadata) + return err } diff --git a/providers/providers.go b/providers/providers.go index 28ffd83a..fd558b63 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -23,6 +23,12 @@ const ( FeatureBootDeviceSet registrar.Feature = "bootdeviceset" // FeaturesVirtualMedia means an implementation can manage virtual media devices FeatureVirtualMedia registrar.Feature = "virtualmedia" + // FeatureUploadFloppyImage means an implementation uploads a floppy image for mounting as virtual media. + // + // note: This is differs from FeatureVirtualMedia which is limited to accepting a URL to download the image from. + FeatureUploadFloppyImage registrar.Feature = "uploadFloppyImage" + // FeatureUnmountFloppyImage means an implementation removes a floppy image that was previously uploaded. + FeatureUnmountFloppyImage registrar.Feature = "unmountFloppyImage" // FeatureFirmwareInstall means an implementation that initiates the firmware install process FeatureFirmwareInstall registrar.Feature = "firmwareinstall" // FeatureFirmwareInstallSatus means an implementation that returns the firmware install status From c282e1577be8f268783b06534b2d04adbfb54c98 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 11 Sep 2023 10:35:45 +0200 Subject: [PATCH 4/6] examples: Add example to upload and unmount a floppy image --- examples/floppy-image/doc.go | 19 +++++++++ examples/floppy-image/main.go | 79 +++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 examples/floppy-image/doc.go create mode 100644 examples/floppy-image/main.go diff --git a/examples/floppy-image/doc.go b/examples/floppy-image/doc.go new file mode 100644 index 00000000..c89443f9 --- /dev/null +++ b/examples/floppy-image/doc.go @@ -0,0 +1,19 @@ +/* +inventory is an example commmand that utilizes the 'v1' bmclib interface +methods to upload and mount, unmount a floppy image. + + # mount image + $ go run examples/floppy-image/main.go \ + -host 10.1.2.3 \ + -user ADMIN \ + -password hunter2 \ + -image /tmp/floppy.img + + # un-mount image + $ go run examples/floppy-image/main.go \ + -host 10.1.2.3 \ + -user ADMIN \ + -password hunter2 \ + -unmount +*/ +package main diff --git a/examples/floppy-image/main.go b/examples/floppy-image/main.go new file mode 100644 index 00000000..d7a25374 --- /dev/null +++ b/examples/floppy-image/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "context" + "crypto/x509" + "flag" + "log" + "os" + "time" + + bmclib "github.com/bmc-toolbox/bmclib/v2" + "github.com/bombsimon/logrusr/v2" + "github.com/sirupsen/logrus" +) + +func main() { + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + user := flag.String("user", "", "Username to login with") + pass := flag.String("password", "", "Username to login with") + host := flag.String("host", "", "BMC hostname to connect to") + imagePath := flag.String("image", "", "The .img file to be uploaded") + unmountImage := flag.Bool("unmount", false, "Unmount floppy image") + + withSecureTLS := flag.Bool("secure-tls", false, "Enable secure TLS") + certPoolFile := flag.String("cert-pool", "", "Path to an file containing x509 CAs. An empty string uses the system CAs. Only takes effect when --secure-tls=true") + flag.Parse() + + l := logrus.New() + l.Level = logrus.DebugLevel + logger := logrusr.New(l) + + clientOpts := []bmclib.Option{bmclib.WithLogger(logger)} + + if *withSecureTLS { + var pool *x509.CertPool + if *certPoolFile != "" { + pool = x509.NewCertPool() + data, err := os.ReadFile(*certPoolFile) + if err != nil { + l.Fatal(err) + } + pool.AppendCertsFromPEM(data) + } + // a nil pool uses the system certs + clientOpts = append(clientOpts, bmclib.WithSecureTLS(pool)) + } + + cl := bmclib.NewClient(*host, *user, *pass, clientOpts...) + err := cl.Open(ctx) + if err != nil { + log.Fatal(err, "bmc login failed") + } + + defer cl.Close(ctx) + + if *unmountImage { + if err := cl.UnmountFloppyImage(ctx); err != nil { + log.Fatal(err) + } + + return + } + + // open file handle + fh, err := os.Open(*imagePath) + if err != nil { + l.Fatal(err) + } + defer fh.Close() + + err = cl.UploadFloppyImage(ctx, fh) + if err != nil { + l.Fatal(err) + } + + l.WithField("img", *imagePath).Info("image mounted successfully") +} From 35b0e0f8a6c74c23e09ebe88a5fd49552e1f84f8 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Fri, 20 Oct 2023 07:34:11 +0200 Subject: [PATCH 5/6] bmc/floppy: fixes returned error and adds test cases --- bmc/floppy.go | 18 ++++++- bmc/floppy_test.go | 114 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 bmc/floppy_test.go diff --git a/bmc/floppy.go b/bmc/floppy.go index 0965de37..2cbb4e69 100644 --- a/bmc/floppy.go +++ b/bmc/floppy.go @@ -5,6 +5,7 @@ import ( "fmt" "io" + bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors" "github.com/hashicorp/go-multierror" "github.com/pkg/errors" ) @@ -66,7 +67,14 @@ func UploadFloppyImageFromInterfaces(ctx context.Context, image io.Reader, p []i } if len(providers) == 0 { - return metadata, multierror.Append(err, errors.New("no FloppyImageUploader implementations found")) + return metadata, multierror.Append( + err, + errors.Wrap( + bmclibErrs.ErrProviderImplementation, + "no FloppyImageUploader implementations found", + ), + ) + } return uploadFloppyImage(ctx, image, providers) @@ -129,7 +137,13 @@ func UnmountFloppyImageFromInterfaces(ctx context.Context, p []interface{}) (met } if len(providers) == 0 { - return metadata, multierror.Append(err, errors.New("no FloppyImageUnmounter implementations found")) + return metadata, multierror.Append( + err, + errors.Wrap( + bmclibErrs.ErrProviderImplementation, + "no FloppyImageUnmounter implementations found", + ), + ) } return unmountFloppyImage(ctx, providers) diff --git a/bmc/floppy_test.go b/bmc/floppy_test.go new file mode 100644 index 00000000..bbb413e2 --- /dev/null +++ b/bmc/floppy_test.go @@ -0,0 +1,114 @@ +package bmc + +import ( + "context" + "io" + "testing" + "time" + + bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors" + "github.com/stretchr/testify/assert" +) + +type uploadFloppyImageTester struct { + returnError error +} + +func (p *uploadFloppyImageTester) UploadFloppyImage(ctx context.Context, reader io.Reader) (err error) { + return p.returnError +} + +func (p *uploadFloppyImageTester) Name() string { + return "foo" +} + +func TestUploadFloppyFromInterfaces(t *testing.T) { + testCases := []struct { + testName string + image io.Reader + returnError error + ctxTimeout time.Duration + providerName string + providersAttempted int + badImplementation bool + }{ + {"success with metadata", nil, nil, 5 * time.Second, "foo", 1, false}, + {"failure with bad implementation", nil, bmclibErrs.ErrProviderImplementation, 1 * time.Nanosecond, "foo", 1, true}, + } + + for _, tc := range testCases { + t.Run(tc.testName, func(t *testing.T) { + var generic []interface{} + if tc.badImplementation { + badImplementation := struct{}{} + generic = []interface{}{&badImplementation} + } else { + testImplementation := &uploadFloppyImageTester{returnError: tc.returnError} + generic = []interface{}{testImplementation} + } + metadata, err := UploadFloppyImageFromInterfaces(context.Background(), tc.image, generic) + if tc.returnError != nil { + assert.ErrorContains(t, err, tc.returnError.Error()) + return + } + + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, tc.returnError, err) + assert.Equal(t, tc.providerName, metadata.SuccessfulProvider) + }) + } +} + +type unmountFloppyImageTester struct { + returnError error +} + +func (p *unmountFloppyImageTester) UnmountFloppyImage(ctx context.Context) (err error) { + return p.returnError +} + +func (p *unmountFloppyImageTester) Name() string { + return "foo" +} + +func TestUnmountFloppyFromInterfaces(t *testing.T) { + testCases := []struct { + testName string + returnError error + ctxTimeout time.Duration + providerName string + providersAttempted int + badImplementation bool + }{ + {"success with metadata", nil, 5 * time.Second, "foo", 1, false}, + {"failure with bad implementation", bmclibErrs.ErrProviderImplementation, 1 * time.Nanosecond, "foo", 1, true}, + } + + for _, tc := range testCases { + t.Run(tc.testName, func(t *testing.T) { + var generic []interface{} + if tc.badImplementation { + badImplementation := struct{}{} + generic = []interface{}{&badImplementation} + } else { + testImplementation := &unmountFloppyImageTester{returnError: tc.returnError} + generic = []interface{}{testImplementation} + } + metadata, err := UnmountFloppyImageFromInterfaces(context.Background(), generic) + if tc.returnError != nil { + assert.ErrorContains(t, err, tc.returnError.Error()) + return + } + + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, tc.returnError, err) + assert.Equal(t, tc.providerName, metadata.SuccessfulProvider) + }) + } +} From 7932b1c5210a8727301dd42d1e055a4766ffe025 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Tue, 31 Oct 2023 10:47:41 +0100 Subject: [PATCH 6/6] Rename UploadFloppyImage -> MountFloppyImage --- bmc/floppy.go | 32 +++++++++++++++--------------- bmc/floppy_test.go | 12 +++++------ client.go | 4 ++-- examples/floppy-image/main.go | 2 +- providers/providers.go | 4 ++-- providers/supermicro/floppy.go | 2 +- providers/supermicro/supermicro.go | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/bmc/floppy.go b/bmc/floppy.go index 2cbb4e69..891a1131 100644 --- a/bmc/floppy.go +++ b/bmc/floppy.go @@ -10,19 +10,19 @@ import ( "github.com/pkg/errors" ) -// FloppyImageUploader defines methods to upload a floppy image -type FloppyImageUploader interface { - UploadFloppyImage(ctx context.Context, image io.Reader) (err error) +// FloppyImageMounter defines methods to upload a floppy image +type FloppyImageMounter interface { + MountFloppyImage(ctx context.Context, image io.Reader) (err error) } // floppyImageUploaderProvider is an internal struct to correlate an implementation/provider and its name type floppyImageUploaderProvider struct { name string - impl FloppyImageUploader + impl FloppyImageMounter } -// uploadFloppyImage is a wrapper method to invoke methods for the FloppyImageUploader interface -func uploadFloppyImage(ctx context.Context, image io.Reader, p []floppyImageUploaderProvider) (metadata Metadata, err error) { +// mountFloppyImage is a wrapper method to invoke methods for the FloppyImageMounter interface +func mountFloppyImage(ctx context.Context, image io.Reader, p []floppyImageUploaderProvider) (metadata Metadata, err error) { var metadataLocal Metadata for _, elem := range p { @@ -37,7 +37,7 @@ func uploadFloppyImage(ctx context.Context, image io.Reader, p []floppyImageUplo return metadata, err default: metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name) - uploadErr := elem.impl.UploadFloppyImage(ctx, image) + uploadErr := elem.impl.MountFloppyImage(ctx, image) if uploadErr != nil { err = multierror.Append(err, errors.WithMessagef(uploadErr, "provider: %v", elem.name)) continue @@ -48,20 +48,20 @@ func uploadFloppyImage(ctx context.Context, image io.Reader, p []floppyImageUplo } } - return metadataLocal, multierror.Append(err, errors.New("failed to upload floppy image")) + return metadataLocal, multierror.Append(err, errors.New("failed to mount floppy image")) } -// UploadFloppyImageFromInterfaces identifies implementations of the FloppyImageUploader interface and passes the found implementations to the uploadFloppyImage() wrapper -func UploadFloppyImageFromInterfaces(ctx context.Context, image io.Reader, p []interface{}) (metadata Metadata, err error) { +// MountFloppyImageFromInterfaces identifies implementations of the FloppyImageMounter interface and passes the found implementations to the mountFloppyImage() wrapper +func MountFloppyImageFromInterfaces(ctx context.Context, image io.Reader, p []interface{}) (metadata Metadata, err error) { providers := make([]floppyImageUploaderProvider, 0) for _, elem := range p { temp := floppyImageUploaderProvider{name: getProviderName(elem)} switch p := elem.(type) { - case FloppyImageUploader: + case FloppyImageMounter: temp.impl = p providers = append(providers, temp) default: - e := fmt.Sprintf("not a FloppyImageUploader implementation: %T", p) + e := fmt.Sprintf("not a FloppyImageMounter implementation: %T", p) err = multierror.Append(err, errors.New(e)) } } @@ -71,16 +71,16 @@ func UploadFloppyImageFromInterfaces(ctx context.Context, image io.Reader, p []i err, errors.Wrap( bmclibErrs.ErrProviderImplementation, - "no FloppyImageUploader implementations found", + "no FloppyImageMounter implementations found", ), ) } - return uploadFloppyImage(ctx, image, providers) + return mountFloppyImage(ctx, image, providers) } -// FloppyImageUploader defines methods to unmount a floppy image +// FloppyImageMounter defines methods to unmount a floppy image type FloppyImageUnmounter interface { UnmountFloppyImage(ctx context.Context) (err error) } @@ -121,7 +121,7 @@ func unmountFloppyImage(ctx context.Context, p []floppyImageUnmounterProvider) ( return metadataLocal, multierror.Append(err, errors.New("failed to unmount floppy image")) } -// UploadFloppyImageFromInterfaces identifies implementations of the FloppyImageUnmounter interface and passes the found implementations to the unmountFloppyImage() wrapper +// MountFloppyImageFromInterfaces identifies implementations of the FloppyImageUnmounter interface and passes the found implementations to the unmountFloppyImage() wrapper func UnmountFloppyImageFromInterfaces(ctx context.Context, p []interface{}) (metadata Metadata, err error) { providers := make([]floppyImageUnmounterProvider, 0) for _, elem := range p { diff --git a/bmc/floppy_test.go b/bmc/floppy_test.go index bbb413e2..3107b8c9 100644 --- a/bmc/floppy_test.go +++ b/bmc/floppy_test.go @@ -10,19 +10,19 @@ import ( "github.com/stretchr/testify/assert" ) -type uploadFloppyImageTester struct { +type mountFloppyImageTester struct { returnError error } -func (p *uploadFloppyImageTester) UploadFloppyImage(ctx context.Context, reader io.Reader) (err error) { +func (p *mountFloppyImageTester) MountFloppyImage(ctx context.Context, reader io.Reader) (err error) { return p.returnError } -func (p *uploadFloppyImageTester) Name() string { +func (p *mountFloppyImageTester) Name() string { return "foo" } -func TestUploadFloppyFromInterfaces(t *testing.T) { +func TestMountFloppyFromInterfaces(t *testing.T) { testCases := []struct { testName string image io.Reader @@ -43,10 +43,10 @@ func TestUploadFloppyFromInterfaces(t *testing.T) { badImplementation := struct{}{} generic = []interface{}{&badImplementation} } else { - testImplementation := &uploadFloppyImageTester{returnError: tc.returnError} + testImplementation := &mountFloppyImageTester{returnError: tc.returnError} generic = []interface{}{testImplementation} } - metadata, err := UploadFloppyImageFromInterfaces(context.Background(), tc.image, generic) + metadata, err := MountFloppyImageFromInterfaces(context.Background(), tc.image, generic) if tc.returnError != nil { assert.ErrorContains(t, err, tc.returnError.Error()) return diff --git a/client.go b/client.go index e0c9e5a0..4f62e6ad 100644 --- a/client.go +++ b/client.go @@ -454,8 +454,8 @@ func (c *Client) ClearSystemEventLog(ctx context.Context) (err error) { return err } -func (c *Client) UploadFloppyImage(ctx context.Context, image io.Reader) (err error) { - metadata, err := bmc.UploadFloppyImageFromInterfaces(ctx, image, c.registry().GetDriverInterfaces()) +func (c *Client) MountFloppyImage(ctx context.Context, image io.Reader) (err error) { + metadata, err := bmc.MountFloppyImageFromInterfaces(ctx, image, c.registry().GetDriverInterfaces()) c.setMetadata(metadata) return err diff --git a/examples/floppy-image/main.go b/examples/floppy-image/main.go index d7a25374..60eb29e0 100644 --- a/examples/floppy-image/main.go +++ b/examples/floppy-image/main.go @@ -70,7 +70,7 @@ func main() { } defer fh.Close() - err = cl.UploadFloppyImage(ctx, fh) + err = cl.MountFloppyImage(ctx, fh) if err != nil { l.Fatal(err) } diff --git a/providers/providers.go b/providers/providers.go index fd558b63..b32749b4 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -23,10 +23,10 @@ const ( FeatureBootDeviceSet registrar.Feature = "bootdeviceset" // FeaturesVirtualMedia means an implementation can manage virtual media devices FeatureVirtualMedia registrar.Feature = "virtualmedia" - // FeatureUploadFloppyImage means an implementation uploads a floppy image for mounting as virtual media. + // FeatureMountFloppyImage means an implementation uploads a floppy image for mounting as virtual media. // // note: This is differs from FeatureVirtualMedia which is limited to accepting a URL to download the image from. - FeatureUploadFloppyImage registrar.Feature = "uploadFloppyImage" + FeatureMountFloppyImage registrar.Feature = "mountFloppyImage" // FeatureUnmountFloppyImage means an implementation removes a floppy image that was previously uploaded. FeatureUnmountFloppyImage registrar.Feature = "unmountFloppyImage" // FeatureFirmwareInstall means an implementation that initiates the firmware install process diff --git a/providers/supermicro/floppy.go b/providers/supermicro/floppy.go index 72ee8434..3cd3dceb 100644 --- a/providers/supermicro/floppy.go +++ b/providers/supermicro/floppy.go @@ -38,7 +38,7 @@ func (c *Client) floppyImageMounted(ctx context.Context) (bool, error) { return false, nil } -func (c *Client) UploadFloppyImage(ctx context.Context, image io.Reader) error { +func (c *Client) MountFloppyImage(ctx context.Context, image io.Reader) error { mounted, err := c.floppyImageMounted(ctx) if err != nil { return err diff --git a/providers/supermicro/supermicro.go b/providers/supermicro/supermicro.go index ca03fc86..29e235a0 100644 --- a/providers/supermicro/supermicro.go +++ b/providers/supermicro/supermicro.go @@ -41,7 +41,7 @@ var ( providers.FeatureScreenshot, providers.FeatureFirmwareInstall, providers.FeatureFirmwareInstallStatus, - providers.FeatureUploadFloppyImage, + providers.FeatureMountFloppyImage, providers.FeatureUnmountFloppyImage, } )