From caa58f1ebe86d7e657d08edfa45a4236febb3c18 Mon Sep 17 00:00:00 2001 From: Joel Rebello Date: Mon, 11 Sep 2023 10:24:51 +0200 Subject: [PATCH] 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