diff --git a/README.md b/README.md index c383afcd9..18f09073a 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,8 @@ data: "node":"yasker-lp-dev3", "paths":[] } - ] + ], + "folderExpression":"{{.pvName}}-{{.namespace}}-{{.pvcName}}" } setup: |- #!/bin/sh @@ -193,6 +194,12 @@ In addition `volumeBindingMode: Immediate` can be used in StorageClass definiti Please note that `nodePathMap` and `sharedFileSystemPath` are mutually exclusive. If `sharedFileSystemPath` is used, then `nodePathMap` must be set to `[]`. +`folderExpression` You can customize expressions produced by folders. pvcName,namespace,pvName are now supported. +The default expression is {{.pvName}}-{{.namespace}}-{{.pvcName}} + +Of course, you can also set the currently used folder name by injecting the pvc annotation `rancher.io/customFolderName` value. +Note that this may cause multiple pvc to use the same directory + ##### Rules The configuration must obey following rules: 1. `config.json` must be a valid json file. diff --git a/examples/pod-with-custom-folder/kustomization.yaml b/examples/pod-with-custom-folder/kustomization.yaml new file mode 100644 index 000000000..3608a2acc --- /dev/null +++ b/examples/pod-with-custom-folder/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- pvc.yaml +- pod.yaml diff --git a/examples/pod-with-custom-folder/pod.yaml b/examples/pod-with-custom-folder/pod.yaml new file mode 100644 index 000000000..05757ac1d --- /dev/null +++ b/examples/pod-with-custom-folder/pod.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: custom-test +spec: + containers: + - name: custom-test + image: nginx:stable-alpine + imagePullPolicy: IfNotPresent + volumeMounts: + - name: volv + mountPath: /data + ports: + - containerPort: 80 + volumes: + - name: volv + persistentVolumeClaim: + claimName: custom-folder-pvc diff --git a/examples/pod-with-custom-folder/pvc.yaml b/examples/pod-with-custom-folder/pvc.yaml new file mode 100644 index 000000000..65c0e7921 --- /dev/null +++ b/examples/pod-with-custom-folder/pvc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: custom-folder-pvc + annotations: + "rancher.io/customFolderName": "demo1" +spec: + accessModes: + - ReadWriteOnce + storageClassName: local-path + resources: + requests: + storage: 128Mi diff --git a/provisioner.go b/provisioner.go index 795a423d4..bdfe96ef6 100644 --- a/provisioner.go +++ b/provisioner.go @@ -30,7 +30,8 @@ const ( ) const ( - KeyNode = "kubernetes.io/hostname" + KeyNode = "kubernetes.io/hostname" + customFolderNameAnnotation = "rancher.io/customFolderName" NodeDefaultNonListedNodes = "DEFAULT_PATH_FOR_NON_LISTED_NODES" @@ -45,6 +46,7 @@ const ( const ( defaultCmdTimeoutSeconds = 120 + defaultFolderExpression = "{{.pvName}}-{{.namespace}}-{{.pvcName}}" ) var ( @@ -77,6 +79,7 @@ type ConfigData struct { NodePathMap []*NodePathMapData `json:"nodePathMap,omitempty"` CmdTimeoutSeconds int `json:"cmdTimeoutSeconds,omitempty"` SharedFileSystemPath string `json:"sharedFileSystemPath,omitempty"` + FolderExpression string `json:"folderExpression,omitempty"` } type NodePathMap struct { @@ -87,6 +90,7 @@ type Config struct { NodePathMap map[string]*NodePathMap CmdTimeoutSeconds int SharedFileSystemPath string + FolderExpression string } func NewProvisioner(ctx context.Context, kubeClient *clientset.Clientset, @@ -258,15 +262,20 @@ func (p *LocalPathProvisioner) Provision(ctx context.Context, opts pvController. } name := opts.PVName - folderName := strings.Join([]string{name, opts.PVC.Namespace, opts.PVC.Name}, "_") - + folderName := "" + if pvc.GetAnnotations()[customFolderNameAnnotation] != "" { + folderName = pvc.GetAnnotations()[customFolderNameAnnotation] + } else { + folderName := strings.Replace(p.config.FolderExpression, "{{.namespace}}", opts.PVC.Namespace, -1) + folderName = strings.Replace(folderName, "{{.pvName}}", name, -1) + folderName = strings.Replace(folderName, "{{.pvcName}}", opts.PVC.Name, -1) + } path := filepath.Join(basePath, folderName) if nodeName == "" { logrus.Infof("Creating volume %v at %v", name, path) } else { logrus.Infof("Creating volume %v at %v:%v", name, nodeName, path) } - storage := pvc.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] provisionCmd := []string{"/bin/sh", "/script/setup"} if err := p.createHelperPod(ActionTypeCreate, provisionCmd, volumeOptions{ @@ -653,5 +662,10 @@ func canonicalizeConfig(data *ConfigData) (cfg *Config, err error) { } else { cfg.CmdTimeoutSeconds = defaultCmdTimeoutSeconds } + if data.FolderExpression != "" { + cfg.FolderExpression = data.FolderExpression + } else { + cfg.FolderExpression = defaultFolderExpression + } return cfg, nil } diff --git a/test/pod_test.go b/test/pod_test.go index f7be8106a..8061b7553 100644 --- a/test/pod_test.go +++ b/test/pod_test.go @@ -1,3 +1,4 @@ +//go:build e2e // +build e2e package test @@ -6,9 +7,9 @@ import ( "fmt" "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/suite" + "strings" "testing" "time" - "strings" ) const ( @@ -131,6 +132,12 @@ func (p *PodTestSuite) TestPodWithSubpath() { runTest(p, []string{p.config.IMAGE}, "ready", hostPathVolumeType) } +func (p *PodTestSuite) TestPodWithCustomFolder() { + p.kustomizeDir = "pod-with-custom-folder" + + runTest(p, []string{p.config.IMAGE}, "ready", hostPathVolumeType) +} + func runTest(p *PodTestSuite, images []string, waitCondition, volumeType string) { kustomizeDir := testdataFile(p.kustomizeDir) diff --git a/test/testdata/pod-with-custom-folder/kustomization.yaml b/test/testdata/pod-with-custom-folder/kustomization.yaml new file mode 100644 index 000000000..486f7c14f --- /dev/null +++ b/test/testdata/pod-with-custom-folder/kustomization.yaml @@ -0,0 +1,10 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ../../../deploy +- ../../../examples/pod-with-custom-folder +commonLabels: + app: local-path-provisioner +images: +- name: rancher/local-path-provisioner + newTag: dev