From e4335c1c57962c88612ffb1dacc9f267924a9b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Rodr=C3=ADguez?= Date: Tue, 7 Dec 2021 13:13:11 +0100 Subject: [PATCH] Fix bucket initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Object storage platforms based on Ceph (https://ceph.io), like DigitalOcean Spaces, have an issue (https://tracker.ceph.com/issues/17398) where the function CreateBucket() does not return a ErrCodeBucketAlreadyOwnedByYou code. This causes the following behaviour: 1. If the bucket does not exists it is created successfully. 2. If the bucket already exists it returns a 409 BucketAlreadyExists response and crashes so it's impossible to run the service. The function HeadBucket() returns successfully if the bucket exists and the user has permissions so it can be used to check if the bucket exists and do an early return to avoid calling CreateBucket() when it already exists. Also, there is a second possible corner case with calling CreateBucket() without checking if the bucket exists with HeadBucket() first as stated in the AWS SDK docs (https://pkg.go.dev/github.com/aws/aws-sdk-go@v1.40.37/service/s3?utm_source=gopls#S3.CreateBucket): > ErrCodeBucketAlreadyOwnedByYou "BucketAlreadyOwnedByYou" > The bucket you tried to create already exists, and you own it. Amazon S3 > returns this error in all Amazon Web Services Regions except in the North > Virginia Region. For legacy compatibility, if you re-create an existing bucket > that you already own in the North Virginia Region, Amazon S3 returns 200 > OK and resets the bucket access control lists (ACLs). Changelog: Title Signed-off-by: Emilio Rodríguez --- s3/filestorage.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/s3/filestorage.go b/s3/filestorage.go index a7f38c5a3..72d15f71d 100644 --- a/s3/filestorage.go +++ b/s3/filestorage.go @@ -164,6 +164,19 @@ func getArtifactByTenant(ctx context.Context, objectID string) string { } func (s *SimpleStorageService) InitBucket(ctx context.Context, bucket string) error { + hparams := &s3.HeadBucketInput{ + Bucket: aws.String(bucket), + } + + headBucketCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + _, err := s.client.HeadBucketWithContext(headBucketCtx, hparams) + if nil == err { + // bucket exists and have permission to access it + return nil + } + // minio requires explicit bucket creation cparams := &s3.CreateBucketInput{ Bucket: aws.String(bucket), // Required @@ -174,7 +187,7 @@ func (s *SimpleStorageService) InitBucket(ctx context.Context, bucket string) er ctxWithTimeout, cancelFn := context.WithTimeout(ctx, 5*time.Second) defer cancelFn() - _, err := s.client.CreateBucketWithContext(ctxWithTimeout, cparams) + _, err = s.client.CreateBucketWithContext(ctxWithTimeout, cparams) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() != ErrCodeBucketAlreadyOwnedByYou {