From 08408625bd8034ea4fedd1b9006d9a034eebd6d3 Mon Sep 17 00:00:00 2001
From: Vitaliy Filippov <vitalif@yourcmc.ru>
Date: Fri, 16 Jul 2021 16:12:57 +0300
Subject: [PATCH] Add mount options support

---
 pkg/driver/controllerserver.go | 16 ++++++++++++++++
 pkg/mounter/goofys.go          | 19 ++++++++++++++++---
 pkg/mounter/mounter.go         |  1 +
 pkg/mounter/rclone.go          |  2 +-
 pkg/mounter/s3fs.go            |  1 +
 pkg/s3/client.go               |  1 +
 6 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/pkg/driver/controllerserver.go b/pkg/driver/controllerserver.go
index 319c444..abd663b 100644
--- a/pkg/driver/controllerserver.go
+++ b/pkg/driver/controllerserver.go
@@ -22,6 +22,7 @@ import (
 	"fmt"
 	"io"
 	"path"
+	"regexp"
 	"strings"
 
 	"github.com/ctrox/csi-s3/pkg/mounter"
@@ -50,6 +51,20 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
 	volumeID := sanitizeVolumeID(req.GetName())
 	bucketName := volumeID
 	prefix := ""
+	mountOptions := make([]string, 0)
+	mountOptStr := params[mounter.OptionsKey]
+	if mountOptStr != "" {
+		re, _ := regexp.Compile(`([^\s"]+|"([^"\\]+|\\")*")+`)
+		re2, _ := regexp.Compile(`"([^"\\]+|\\")*"`)
+		re3, _ := regexp.Compile(`\\(.)`)
+		for _, opt := range re.FindAll([]byte(mountOptStr), -1) {
+			// Unquote options
+			opt = re2.ReplaceAllFunc(opt, func(q []byte) []byte {
+				return re3.ReplaceAll(q[1 : len(q)-1], []byte("$1"))
+			})
+			mountOptions = append(mountOptions, string(opt))
+		}
+	}
 
 	// check if bucket name is overridden
 	if nameOverride, ok := params[mounter.BucketKey]; ok {
@@ -77,6 +92,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
 		BucketName:    bucketName,
 		Prefix:        prefix,
 		Mounter:       mounterType,
+		MountOptions:  mountOptions,
 		CapacityBytes: capacityBytes,
 		FSPath:        defaultFsPath,
 	}
diff --git a/pkg/mounter/goofys.go b/pkg/mounter/goofys.go
index e7bccc8..3fab96d 100644
--- a/pkg/mounter/goofys.go
+++ b/pkg/mounter/goofys.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"os"
 	"path"
+	"strings"
 
 	"context"
 
@@ -49,15 +50,27 @@ func (goofys *goofysMounter) Unstage(stageTarget string) error {
 }
 
 func (goofys *goofysMounter) Mount(source string, target string) error {
+	mountOptions := make(map[string]string)
+	for _, opt := range goofys.meta.MountOptions {
+		s := 0
+		if len(opt) >= 2 && opt[0] == '-' && opt[1] == byte('-') {
+			s = 2
+		}
+		p := strings.Index(opt, "=")
+		if p > 0 {
+			mountOptions[string(opt[s : p])] = string(opt[p : ])
+		} else {
+			mountOptions[string(opt[s : ])] = ""
+		}
+	}
+	mountOptions["allow_other"] = ""
 	goofysCfg := &goofysApi.Config{
 		MountPoint: target,
 		Endpoint:   goofys.endpoint,
 		Region:     goofys.region,
 		DirMode:    0755,
 		FileMode:   0644,
-		MountOptions: map[string]string{
-			"allow_other": "",
-		},
+		MountOptions: mountOptions,
 	}
 
 	os.Setenv("AWS_ACCESS_KEY_ID", goofys.accessKeyID)
diff --git a/pkg/mounter/mounter.go b/pkg/mounter/mounter.go
index 5e0f45c..99c65e2 100644
--- a/pkg/mounter/mounter.go
+++ b/pkg/mounter/mounter.go
@@ -31,6 +31,7 @@ const (
 	rcloneMounterType   = "rclone"
 	TypeKey             = "mounter"
 	BucketKey           = "bucket"
+	OptionsKey          = "options"
 )
 
 // New returns a new mounter depending on the mounterType parameter
diff --git a/pkg/mounter/rclone.go b/pkg/mounter/rclone.go
index 038c6aa..f5e4c43 100644
--- a/pkg/mounter/rclone.go
+++ b/pkg/mounter/rclone.go
@@ -50,9 +50,9 @@ func (rclone *rcloneMounter) Mount(source string, target string) error {
 		fmt.Sprintf("--s3-region=%s", rclone.region),
 		fmt.Sprintf("--s3-endpoint=%s", rclone.url),
 		"--allow-other",
-		// TODO: make this configurable
 		"--vfs-cache-mode=writes",
 	}
+	args = append(args, rclone.meta.MountOptions...)
 	os.Setenv("AWS_ACCESS_KEY_ID", rclone.accessKeyID)
 	os.Setenv("AWS_SECRET_ACCESS_KEY", rclone.secretAccessKey)
 	return fuseMount(target, rcloneCmd, args)
diff --git a/pkg/mounter/s3fs.go b/pkg/mounter/s3fs.go
index 9649388..b59d229 100644
--- a/pkg/mounter/s3fs.go
+++ b/pkg/mounter/s3fs.go
@@ -50,6 +50,7 @@ func (s3fs *s3fsMounter) Mount(source string, target string) error {
 		"-o", "allow_other",
 		"-o", "mp_umask=000",
 	}
+	args = append(args, s3fs.meta.MountOptions...)
 	return fuseMount(target, s3fsCmd, args)
 }
 
diff --git a/pkg/s3/client.go b/pkg/s3/client.go
index 87d5df1..58d7e90 100644
--- a/pkg/s3/client.go
+++ b/pkg/s3/client.go
@@ -37,6 +37,7 @@ type FSMeta struct {
 	BucketName    string `json:"Name"`
 	Prefix        string `json:"Prefix"`
 	Mounter       string `json:"Mounter"`
+	MountOptions  []string `json:"MountOptions"`
 	FSPath        string `json:"FSPath"`
 	CapacityBytes int64  `json:"CapacityBytes"`
 }