Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable mounting an existing bucket #55 #60

Merged
merged 2 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,27 @@ parameters:

If the bucket is specified, it will still be created if it does not exist on the backend. Every volume will get its own prefix within the bucket which matches the volume ID. When deleting a volume, also just the prefix will be deleted.

#### Using an existing bucket with custom prefix

If you have an existing bucket and with or without a prefix (subpath), you can specify to use a prefixed configuration by setting the parameters as:
ctrox marked this conversation as resolved.
Show resolved Hide resolved

```yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: csi-s3-existing-bucket
provisioner: ch.ctrox.csi.s3-driver
reclaimPolicy: Retain
parameters:
mounter: rclone
bucket: some-existing-bucket-name
# 'usePrefix' must be true in order to enable the prefix feature and to avoid the removal of the prefix or bucket
usePrefix: "true"
# 'prefix' can be empty (it will mount on the root of the bucket), an existing prefix or a new one.
prefix: custom-prefix
```
**Note:** all volumes created with this `StorageClass` will always be mounted to the same bucket and path, meaning they will be identical.

### Mounter

As S3 is not a real file system there are some limitations to consider here. Depending on what mounter you are using, you will have different levels of POSIX compability. Also depending on what S3 storage backend you are using there are not always [consistency guarantees](https://github.com/gaul/are-we-consistent-yet#observed-consistency).
Expand Down
22 changes: 20 additions & 2 deletions pkg/driver/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"fmt"
"io"
"path"
"strconv"
"strings"

"github.com/ctrox/csi-s3/pkg/mounter"
Expand Down Expand Up @@ -50,6 +51,8 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
volumeID := sanitizeVolumeID(req.GetName())
bucketName := volumeID
prefix := ""
usePrefix, usePrefixError := strconv.ParseBool(params[mounter.UsePrefix])
defaultFsPath := defaultFsPath

// check if bucket name is overridden
if nameOverride, ok := params[mounter.BucketKey]; ok {
Expand All @@ -58,6 +61,16 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
volumeID = path.Join(bucketName, prefix)
}

// check if volume prefix is overridden
if overridePrefix := usePrefix; usePrefixError == nil && overridePrefix {
prefix = ""
defaultFsPath = ""
if prefixOverride, ok := params[mounter.VolumePrefix]; ok && prefixOverride != "" {
prefix = prefixOverride
}
volumeID = path.Join(bucketName, prefix)
}

if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil {
glog.V(3).Infof("invalid create volume req: %v", req)
return nil, err
Expand All @@ -75,6 +88,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol

meta := &s3.FSMeta{
BucketName: bucketName,
UsePrefix: usePrefix,
Prefix: prefix,
Mounter: mounterType,
CapacityBytes: capacityBytes,
Expand Down Expand Up @@ -108,7 +122,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
}
}

if err = client.CreatePrefix(bucketName, path.Join(prefix, defaultFsPath)); err != nil {
if err = client.CreatePrefix(bucketName, path.Join(prefix, defaultFsPath)); err != nil && prefix != "" {
return nil, fmt.Errorf("failed to create prefix %s: %v", path.Join(prefix, defaultFsPath), err)
}

Expand Down Expand Up @@ -153,7 +167,11 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
}

var deleteErr error
if prefix == "" {
if meta.UsePrefix {
// UsePrefix is true, we do not delete anything
glog.V(4).Infof("Nothing to remove for %s", bucketName)
return &csi.DeleteVolumeResponse{}, nil
} else if prefix == "" {
ctrox marked this conversation as resolved.
Show resolved Hide resolved
// prefix is empty, we delete the whole bucket
if err := client.RemoveBucket(bucketName); err != nil {
deleteErr = err
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type driver struct {
}

var (
vendorVersion = "v1.2.0-rc.1"
vendorVersion = "v1.2.0-rc.2"
driverName = "ch.ctrox.csi.s3-driver"
)

Expand Down
2 changes: 2 additions & 0 deletions pkg/mounter/mounter.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const (
rcloneMounterType = "rclone"
TypeKey = "mounter"
BucketKey = "bucket"
VolumePrefix = "prefix"
UsePrefix = "usePrefix"
)

// New returns a new mounter depending on the mounterType parameter
Expand Down
8 changes: 4 additions & 4 deletions pkg/s3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/url"
"path"

"github.com/golang/glog"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"io"
"net/url"
"path"
)

const (
Expand All @@ -36,6 +35,7 @@ type Config struct {
type FSMeta struct {
BucketName string `json:"Name"`
Prefix string `json:"Prefix"`
UsePrefix bool `json:"UsePrefix"`
Mounter string `json:"Mounter"`
FSPath string `json:"FSPath"`
CapacityBytes int64 `json:"CapacityBytes"`
Expand Down