Skip to content

Commit

Permalink
[S3 gateway] Return HTTP 409 (Conflict) when creating existing repo (#…
Browse files Browse the repository at this point in the history
…2451)

* [S3 gateway] Return HTTP 409 (Conflict) when creating existing repo

When copying to a new key, Rclone likes to try to create _all_ the S3 path
down (it seems to think it's on a POSIXy filesystem so it `mkdir -p`s).  A
repository cannot be created by the gateway -- there is not enough info on
the request -- but if we return a 409 (conflict) then Rclone continues and
succeeds.

There is no S3 gateway test, so tested manually using Rclone.

Fixes #2447.

* [CR] Require CreateRepositoryAction (not ReadRepositoryAction)
  • Loading branch information
arielshaqed committed Sep 5, 2021
1 parent 3a9b871 commit a0713b3
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 1 deletion.
1 change: 1 addition & 0 deletions pkg/gateway/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ func NewHandler(
operations.OperationIDDeleteObject: PathOperationHandler(sc, &operations.DeleteObject{}),
operations.OperationIDDeleteObjects: RepoOperationHandler(sc, &operations.DeleteObjects{}),
operations.OperationIDGetObject: PathOperationHandler(sc, &operations.GetObject{}),
operations.OperationIDPutBucket: RepoOperationHandler(sc, &operations.PutBucket{}),
operations.OperationIDHeadBucket: RepoOperationHandler(sc, &operations.HeadBucket{}),
operations.OperationIDHeadObject: PathOperationHandler(sc, &operations.HeadObject{}),
operations.OperationIDListBuckets: OperationHandler(sc, &operations.ListBuckets{}),
Expand Down
4 changes: 3 additions & 1 deletion pkg/gateway/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,10 @@ func pathBasedOperationID(method string) operations.OperationID {

func repositoryBasedOperationID(method string) operations.OperationID {
switch method {
case http.MethodDelete, http.MethodPut:
case http.MethodDelete:
return operations.OperationIDUnsupportedOperation
case http.MethodPut:
return operations.OperationIDPutBucket
case http.MethodHead:
return operations.OperationIDHeadBucket
case http.MethodPost:
Expand Down
1 change: 1 addition & 0 deletions pkg/gateway/operations/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
OperationIDListObjects OperationID = "list_objects"
OperationIDPostObject OperationID = "post_object"
OperationIDPutObject OperationID = "put_object"
OperationIDPutBucket OperationID = "put_bucket"

OperationIDUnsupportedOperation OperationID = "unsupported"
OperationIDOperationNotFound OperationID = "not_found"
Expand Down
35 changes: 35 additions & 0 deletions pkg/gateway/operations/putbucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package operations

import (
"net/http"

gatewayerrors "github.com/treeverse/lakefs/pkg/gateway/errors"
"github.com/treeverse/lakefs/pkg/permissions"
)

// PutBucket handles S3 Create Bucket operations. It does *not* actually
// create new repos (there is not enough information in the S3 request to
// create a new repo), but *does* detect whether the repo already exists.
type PutBucket struct{}

func (controller *PutBucket) RequiredPermissions(_ *http.Request, repoID string) ([]permissions.Permission, error) {
return []permissions.Permission{
{
// Mimic S3, which requires s3:CreateBucket to call
// create-bucket, even if we only want to receive
// 409.
Action: permissions.CreateRepositoryAction,
Resource: permissions.RepoArn(repoID),
},
}, nil
}

func (controller *PutBucket) Handle(w http.ResponseWriter, req *http.Request, o *RepoOperation) {
o.Incr("put_repo")
if o.Repository == nil {
// No repo, would have to create it, but not enough
// information -- so not supported.
o.EncodeError(w, req, gatewayerrors.ERRLakeFSNotSupported.ToAPIErr())
}
o.EncodeError(w, req, gatewayerrors.ErrBucketAlreadyExists.ToAPIErr())
}

0 comments on commit a0713b3

Please sign in to comment.