func setInstanceBucketName(d *driver, s3Client Client, reqLogger logr.Logger, instance *veleroInstallCR.VeleroInstall) error {
	bucketLog := reqLogger.WithValues("StorageBucket.Name", instance.Status.StorageBucket.Name, "StorageBucket.Region", d.Config.Region)
	bucketLog.Info("No S3 bucket defined. Searching for existing bucket to use")
	bucketlist, err := ListBucketsInRegion(s3Client, d.Config.Region)
	if err != nil {
		return err
	}
	bucketinfo, err := ListBucketTags(s3Client, bucketlist.Buckets)
	if err != nil {
		return err
	}
	existingBucket := FindMatchingTags(bucketinfo, d.Config.InfraName)
	if existingBucket != "" {
		bucketLog.Info("Recovered existing bucket", "StorageBucket.Name", existingBucket)
		instance.Status.StorageBucket.Name = existingBucket
		instance.Status.StorageBucket.Provisioned = true
		return instance.StatusUpdate(reqLogger, d.KubeClient)
	}
	proposedName := generateBucketName(storageConstants.StorageBucketPrefix)
	proposedBucketExists, err := DoesBucketExist(s3Client, proposedName)
	if err != nil {
		return err
	}
	if proposedBucketExists {
		return fmt.Errorf("proposed bucket %s already exists, retrying", proposedName)
	}
	bucketLog.Info("Setting proposed bucket name", "StorageBucket.Name", proposedName)
	instance.Status.StorageBucket.Name = proposedName
	instance.Status.StorageBucket.Provisioned = false
	return instance.StatusUpdate(reqLogger, d.KubeClient)
}
setInstanceBucketName generates a bucket name for the S3 Bucket, tests to
confirm if the bucket is accessible and then updates the instance status
with the name
package s3
import (
	"context"
	"fmt"
	"time"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"github.com/go-logr/logr"
	"github.com/google/uuid"
	configv1 "github.com/openshift/api/config/v1"
	veleroInstallCR "github.com/openshift/managed-velero-operator/pkg/apis/managed/v1alpha2"
	storageBase "github.com/openshift/managed-velero-operator/pkg/storage/base"
	storageConstants "github.com/openshift/managed-velero-operator/pkg/storage/constants"
	"sigs.k8s.io/controller-runtime/pkg/client"
)
type S3 struct {
	Region    string
	InfraName string
}
type driver struct {
	storageBase.Driver
	Config *S3
}
func NewDriver(ctx context.Context, cfg *configv1.InfrastructureStatus, clnt client.Client) *driver {
	drv := driver{
		Config: &S3{
			Region:    cfg.PlatformStatus.AWS.Region,
			InfraName: cfg.InfrastructureName,
		},
	}
	drv.Context = ctx
	drv.KubeClient = clnt
	return &drv
}
func (d *driver) GetPlatformType() configv1.PlatformType {
	return configv1.AWSPlatformType
}
func (d *driver) CreateStorage(reqLogger logr.Logger, instance *veleroInstallCR.VeleroInstall) error {
	var err error
	s3Client, err := NewS3Client(d.KubeClient, d.Config.Region)
	if err != nil {
		return err
	}
	bucketLog := reqLogger.WithValues("StorageBucket.Name", instance.Status.StorageBucket.Name, "StorageBucket.Region", d.Config.Region)
	switch {
	case instance.Status.StorageBucket.Name == "":
		err = setInstanceBucketName(d, s3Client, reqLogger, instance)
		if err != nil {
			return err
		}
	case instance.Status.StorageBucket.Name != "" && !instance.Status.StorageBucket.Provisioned:
		bucketLog.Info("S3 bucket defined, but not provisioned")
		bucketLog.Info("Creating S3 Bucket")
		err = CreateBucket(s3Client, instance.Status.StorageBucket.Name)
		if err != nil {
			if aerr, ok := err.(awserr.Error); ok {
				switch aerr.Code() {
				case s3.ErrCodeBucketAlreadyExists:
					bucketLog.Info("Bucket exists, but is not owned by current user; retrying")
					instance.Status.StorageBucket.Name = ""
					return instance.StatusUpdate(reqLogger, d.KubeClient)
				case s3.ErrCodeBucketAlreadyOwnedByYou:
					bucketLog.Info("Bucket exists, and is owned by current user; continue")
				default:
					return fmt.Errorf("error occurred when creating bucket %v: %v", instance.Status.StorageBucket.Name, aerr.Error())
				}
			} else {
				return fmt.Errorf("error occurred when creating bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
			}
		}
		err = TagBucket(s3Client, instance.Status.StorageBucket.Name, storageConstants.DefaultVeleroBackupStorageLocation, d.Config.InfraName)
		if err != nil {
			return fmt.Errorf("error occurred when tagging bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
		}
	}
	bucketLog.Info("Verifing S3 Bucket exists")
	exists, err := d.StorageExists(instance.Status.StorageBucket.Name)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("error occurred when verifying bucket %v: %v", instance.Status.StorageBucket.Name, aerr.Error())
		}
		return fmt.Errorf("error occurred when verifying bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
	}
	if !exists {
		bucketLog.Error(nil, "S3 bucket doesn't appear to exist")
		instance.Status.StorageBucket.Provisioned = false
		return instance.StatusUpdate(reqLogger, d.KubeClient)
	}
	bucketLog.Info("Enforcing S3 Bucket encryption")
	err = EncryptBucket(s3Client, instance.Status.StorageBucket.Name)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("error occurred when encrypting bucket %v: %v", instance.Status.StorageBucket.Name, aerr.Error())
		}
		return fmt.Errorf("error occurred when encrypting bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
	}
	bucketLog.Info("Enforcing S3 Bucket public access policy")
	err = BlockBucketPublicAccess(s3Client, instance.Status.StorageBucket.Name)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("error occurred when blocking public access to bucket %v: %v", instance.Status.StorageBucket.Name, aerr.Error())
		}
		return fmt.Errorf("error occurred when blocking public access to bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
	}
	bucketLog.Info("Enforcing S3 Bucket lifecycle rules on S3 Bucket")
	err = SetBucketLifecycle(s3Client, instance.Status.StorageBucket.Name)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			return fmt.Errorf("error occurred when configuring lifecycle rules on bucket %v: %v", instance.Status.StorageBucket.Name, aerr.Error())
		}
		return fmt.Errorf("error occurred when configuring lifecycle rules on bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
	}
	bucketLog.Info("Enforcing S3 Bucket tags on S3 Bucket")
	err = TagBucket(s3Client, instance.Status.StorageBucket.Name, storageConstants.DefaultVeleroBackupStorageLocation, d.Config.InfraName)
	if err != nil {
		return fmt.Errorf("error occurred when tagging bucket %v: %v", instance.Status.StorageBucket.Name, err.Error())
	}
	instance.Status.StorageBucket.Provisioned = true
	instance.Status.StorageBucket.LastSyncTimestamp = &metav1.Time{
		Time: time.Now(),
	}
	return instance.StatusUpdate(reqLogger, d.KubeClient)
}
func (d *driver) StorageExists(bucketName string) (bool, error) {
	s3Client, err := NewS3Client(d.KubeClient, d.Config.Region)
	if err != nil {
		return false, err
	}
	input := &s3.HeadBucketInput{
		Bucket: aws.String(bucketName),
	}
	_, err = s3Client.HeadBucket(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			case s3.ErrCodeNoSuchBucket, "NotFound":
				return false, nil
			default:
				return false, fmt.Errorf("unable to determine bucket %v status: %v", bucketName, aerr.Error())
			}
		} else {
			return false, fmt.Errorf("unable to determine bucket %v status: %v", bucketName, aerr.Error())
		}
	}
	return true, nil
}
func generateBucketName(prefix string) string {
	id := uuid.New().String()
	return prefix + id
}