Skip to content

Commit

Permalink
Merge pull request #17 from axeora/use-file-config
Browse files Browse the repository at this point in the history
Co-authored-by: Anton Zuenko <anton@zuenko.ru>
Use rclone.conf - like configuration, in addition to cmd arguments
  • Loading branch information
Jancis committed Sep 30, 2022
2 parents d728b51 + 8a37645 commit 6e048e8
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 16 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ stringData:
s3-secret-access-key: "SECRET_ACCESS_KEY"
```

Alternatively, you may specify rclone configuration file directly in the secret under `configData` field.

```
apiVersion: v1
kind: Secret
metadata:
name: rclone-secret
type: Opaque
stringData:
remote: "my-s3"
remotePath: "projectname"
configData: |
[my-s3]
type = s3
provider = Minio
access_key_id = ACCESS_KEY_ID
secret_access_key = SECRET_ACCESS_KEY
endpoint = http://minio-release.default:9000
```

Deploy example secret
> `kubectl apply -f example/kubernetes/rclone-secret-example.yaml --namespace kube-system`
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.3.0
v1.3.1
2 changes: 1 addition & 1 deletion deploy/kubernetes/1.13/csi-controller-rclone.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ spec:
- name: socket-dir
mountPath: /csi
- name: rclone
image: wunderio/csi-rclone:v1.3.0
image: wunderio/csi-rclone:v1.3.1
args :
- "/bin/csi-rclone-plugin"
- "--nodeid=$(NODE_ID)"
Expand Down
2 changes: 1 addition & 1 deletion deploy/kubernetes/1.13/csi-nodeplugin-rclone.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ spec:
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
image: wunderio/csi-rclone:v1.3.0
image: wunderio/csi-rclone:v1.3.1
args:
- "/bin/csi-rclone-plugin"
- "--nodeid=$(NODE_ID)"
Expand Down
2 changes: 1 addition & 1 deletion deploy/kubernetes/1.19/csi-controller-rclone.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ spec:
- name: socket-dir
mountPath: /csi
- name: rclone
image: wunderio/csi-rclone:v1.3.0
image: wunderio/csi-rclone:v1.3.1
args :
- "/bin/csi-rclone-plugin"
- "--nodeid=$(NODE_ID)"
Expand Down
2 changes: 1 addition & 1 deletion deploy/kubernetes/1.19/csi-nodeplugin-rclone.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ spec:
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
image: wunderio/csi-rclone:v1.3.0
image: wunderio/csi-rclone:v1.3.1
args:
- "/bin/csi-rclone-plugin"
- "--nodeid=$(NODE_ID)"
Expand Down
16 changes: 16 additions & 0 deletions example/kubernetes/rclone-secret-file-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Secret
metadata:
name: rclone-secret
namespace: csi-rclone
type: Opaque
stringData:
remote: "my-s3"
remotePath: "projectname"
configData: |
[my-s3]
type = s3
provider = Minio
access_key_id = ACCESS_KEY_ID
secret_access_key = SECRET_ACCESS_KEY
endpoint = http://minio-release.default:9000
60 changes: 49 additions & 11 deletions pkg/rclone/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
// Load default connection settings from secret
secret, e := getSecret("rclone-secret")

remote, remotePath, flags, e := extractFlags(req.GetVolumeContext(), secret)
remote, remotePath, configData, flags, e := extractFlags(req.GetVolumeContext(), secret)
if e != nil {
klog.Warningf("storage parameter error: %s", e)
return nil, e
}

e = Mount(remote, remotePath, targetPath, flags)
e = Mount(remote, remotePath, targetPath, configData, flags)
if e != nil {
if os.IsPermission(e) {
return nil, status.Error(codes.PermissionDenied, e.Error())
Expand All @@ -97,7 +97,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
return &csi.NodePublishVolumeResponse{}, nil
}

func extractFlags(volumeContext map[string]string, secret *v1.Secret) (string, string, map[string]string, error) {
func extractFlags(volumeContext map[string]string, secret *v1.Secret) (string, string, string, map[string]string, error) {

// Empty argument list
flags := make(map[string]string)
Expand All @@ -120,7 +120,7 @@ func extractFlags(volumeContext map[string]string, secret *v1.Secret) (string, s
}

if e := validateFlags(flags); e != nil {
return "", "", flags, e
return "", "", "", flags, e
}

remote := flags["remote"]
Expand All @@ -131,10 +131,17 @@ func extractFlags(volumeContext map[string]string, secret *v1.Secret) (string, s
delete(flags, "remotePathSuffix")
}

configData := ""
ok := false

if configData, ok = flags["configData"]; ok {
delete(flags, "configData")
}

delete(flags, "remote")
delete(flags, "remotePath")

return remote, remotePath, flags, nil
return remote, remotePath, configData, flags, nil
}

func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) {
Expand Down Expand Up @@ -221,7 +228,7 @@ func getSecret(secretName string) (*v1.Secret, error) {
}

// Mount routine.
func Mount(remote string, remotePath string, targetPath string, flags map[string]string) error {
func Mount(remote string, remotePath string, targetPath string, configData string, flags map[string]string) error {
mountCmd := "rclone"
mountArgs := []string{}

Expand All @@ -233,16 +240,47 @@ func Mount(remote string, remotePath string, targetPath string, flags map[string
defaultFlags["allow-non-empty"] = "true"
defaultFlags["allow-other"] = "true"

// rclone mount remote:path /path/to/mountpoint [flags]
remoteWithPath := fmt.Sprintf(":%s:%s", remote, remotePath)

if strings.Contains(configData, "[" + remote + "]") {
remoteWithPath = fmt.Sprintf("%s:%s", remote, remotePath)
klog.Infof("remote %s found in configData, remoteWithPath set to %s", remote, remoteWithPath)
}

// rclone mount remote:path /path/to/mountpoint [flags]
mountArgs = append(
mountArgs,
"mount",
fmt.Sprintf(":%s:%s", remote, remotePath),
remoteWithPath,
targetPath,
"--daemon",
)

// If a custom flag configData is defined,
// create a temporary file, fill it with configData content,
// and run rclone with --config <tmpfile> flag
if configData != "" {

configFile, err := ioutil.TempFile("", "rclone.conf")
if err != nil {
return err
}

// Normally, a defer os.Remove(configFile.Name()) should be placed here.
// However, due to a rclone mount --daemon flag, rclone forks and creates a race condition
// with this nodeplugin proceess. As a result, the config file gets deleted
// before it's reread by a forked process.

if _, err := configFile.Write([]byte(configData)); err != nil {
return err
}
if err := configFile.Close(); err != nil {
return err
}

mountArgs = append(mountArgs, "--config", configFile.Name())
}

// Add default flags
for k, v := range defaultFlags {
// Exclude overriden flags
Expand All @@ -262,12 +300,12 @@ func Mount(remote string, remotePath string, targetPath string, flags map[string
return err
}

klog.Infof("executing mount command cmd=%s, remote=:%s:%s, targetpath=%s", mountCmd, remote, remotePath, targetPath)
klog.Infof("executing mount command cmd=%s, remote=%s, targetpath=%s", mountCmd, remoteWithPath, targetPath)

out, err := exec.Command(mountCmd, mountArgs...).CombinedOutput()
if err != nil {
return fmt.Errorf("mounting failed: %v cmd: '%s' remote: ':%s:%s' targetpath: %s output: %q",
err, mountCmd, remote, remotePath, targetPath, string(out))
return fmt.Errorf("mounting failed: %v cmd: '%s' remote: '%s' targetpath: %s output: %q",
err, mountCmd, remoteWithPath, targetPath, string(out))
}

return nil
Expand Down

0 comments on commit 6e048e8

Please sign in to comment.