From 9d6c66ea94bff31bd585de02c83e1fe8508d5f3b Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Thu, 17 Sep 2020 13:11:28 +0300 Subject: [PATCH 1/7] #6: Update path creation and implemented possibility save data after removing PV --- .../provisioner.go | 87 ++++++++++++++----- 1 file changed, 63 insertions(+), 24 deletions(-) diff --git a/cmd/nfs-subdir-external-provisioner/provisioner.go b/cmd/nfs-subdir-external-provisioner/provisioner.go index 50b94070..96ad423d 100644 --- a/cmd/nfs-subdir-external-provisioner/provisioner.go +++ b/cmd/nfs-subdir-external-provisioner/provisioner.go @@ -22,14 +22,14 @@ import ( "fmt" "os" "path/filepath" - "strconv" + "regexp" "strings" "k8s.io/kubernetes/pkg/apis/core/v1/helper" "github.com/golang/glog" - "sigs.k8s.io/sig-storage-lib-external-provisioner/controller" - "k8s.io/api/core/v1" + "github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/controller" + v1 "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" @@ -47,13 +47,36 @@ type nfsProvisioner struct { path string } +type pvcMetadata struct { + data map[string]string + labels map[string]string + annotations map[string]string +} + +func (meta *pvcMetadata) stringParser(str string) string { + pattern := regexp.MustCompile(`{pvc\.((labels|annotations)\.(.*?)|.*?)}`) + result := pattern.FindAllStringSubmatch(str, -1) + for _, r := range result { + switch r[2] { + case "labels": + str = strings.Replace(str, r[0], meta.labels[r[3]], -1) + case "annotations": + fmt.Println(r[0], r[3], meta.annotations[r[3]]) + str = strings.Replace(str, r[0], meta.annotations[r[3]], -1) + default: + str = strings.Replace(str, r[0], meta.data[r[1]], -1) + } + } + return str +} + const ( mountPath = "/persistentvolumes" ) var _ controller.Provisioner = &nfsProvisioner{} -func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.PersistentVolume, error) { +func (p *nfsProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) { if options.PVC.Spec.Selector != nil { return nil, fmt.Errorf("claim Selector is not supported") } @@ -64,23 +87,39 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per pvName := strings.Join([]string{pvcNamespace, pvcName, options.PVName}, "-") + metadata := &pvcMetadata{ + data: map[string]string{ + "name": pvcName, + "namespace": pvcNamespace, + }, + labels: options.PVC.Labels, + annotations: options.PVC.Annotations, + } + fullPath := filepath.Join(mountPath, pvName) + path := filepath.Join(p.path, pvName) + + pathPattern, exists := options.Parameters["pathPattern"] + if exists { + customPath := metadata.stringParser(pathPattern) + path = filepath.Join(p.path, customPath) + fullPath = filepath.Join(mountPath, customPath) + } + glog.V(4).Infof("creating path %s", fullPath) if err := os.MkdirAll(fullPath, 0777); err != nil { return nil, errors.New("unable to create directory to provision new pv: " + err.Error()) } os.Chmod(fullPath, 0777) - path := filepath.Join(p.path, pvName) - pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: options.PVName, }, Spec: v1.PersistentVolumeSpec{ - PersistentVolumeReclaimPolicy: *options.StorageClass.ReclaimPolicy, + PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy, AccessModes: options.PVC.Spec.AccessModes, - //MountOptions: options.MountOptions, + MountOptions: options.MountOptions, Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], }, @@ -98,8 +137,9 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { path := volume.Spec.PersistentVolumeSource.NFS.Path - pvName := filepath.Base(path) - oldPath := filepath.Join(mountPath, pvName) + relativePath := strings.Replace(path, p.path, "", 1) + oldPath := filepath.Join(mountPath, relativePath) + if _, err := os.Stat(oldPath); os.IsNotExist(err) { glog.Warningf("path %s does not exist, deletion skipped", oldPath) return nil @@ -112,21 +152,20 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { // Determine if the "archiveOnDelete" parameter exists. // If it exists and has a false value, delete the directory. // Otherwise, archive it. - archiveOnDelete, exists := storageClass.Parameters["archiveOnDelete"] - if exists { - archiveBool, err := strconv.ParseBool(archiveOnDelete) - if err != nil { - return err - } - if !archiveBool { - return os.RemoveAll(oldPath) - } + onDelete := storageClass.Parameters["onDelete"] + switch onDelete { + + case "delete": + return os.RemoveAll(oldPath) + + case "retain": + return nil + + default: + archivePath := filepath.Join(mountPath, "archived-"+volume.Name) + glog.V(4).Infof("archiving path %s to %s", oldPath, archivePath) + return os.Rename(oldPath, archivePath) } - - archivePath := filepath.Join(mountPath, "archived-"+pvName) - glog.V(4).Infof("archiving path %s to %s", oldPath, archivePath) - return os.Rename(oldPath, archivePath) - } // getClassForVolume returns StorageClass From fe9be3d5d882f420bac2773ea37c637df96fca9f Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Mon, 21 Sep 2020 15:56:30 +0300 Subject: [PATCH 2/7] fixed : 37,102 lines --- cmd/nfs-subdir-external-provisioner/provisioner.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/nfs-subdir-external-provisioner/provisioner.go b/cmd/nfs-subdir-external-provisioner/provisioner.go index 96ad423d..f4b1a2d0 100644 --- a/cmd/nfs-subdir-external-provisioner/provisioner.go +++ b/cmd/nfs-subdir-external-provisioner/provisioner.go @@ -53,15 +53,15 @@ type pvcMetadata struct { annotations map[string]string } +var pattern = regexp.MustCompile(`{pvc\.((labels|annotations)\.(.*?)|.*?)}`) + func (meta *pvcMetadata) stringParser(str string) string { - pattern := regexp.MustCompile(`{pvc\.((labels|annotations)\.(.*?)|.*?)}`) result := pattern.FindAllStringSubmatch(str, -1) for _, r := range result { switch r[2] { case "labels": str = strings.Replace(str, r[0], meta.labels[r[3]], -1) case "annotations": - fmt.Println(r[0], r[3], meta.annotations[r[3]]) str = strings.Replace(str, r[0], meta.annotations[r[3]], -1) default: str = strings.Replace(str, r[0], meta.data[r[1]], -1) From a5f4a8b72bb06e622350b8509cc450f41c1c3fa5 Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Mon, 21 Sep 2020 16:01:14 +0300 Subject: [PATCH 3/7] fixed : 37,102 lines --- cmd/nfs-subdir-external-provisioner/provisioner.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/nfs-subdir-external-provisioner/provisioner.go b/cmd/nfs-subdir-external-provisioner/provisioner.go index f4b1a2d0..88be3c85 100644 --- a/cmd/nfs-subdir-external-provisioner/provisioner.go +++ b/cmd/nfs-subdir-external-provisioner/provisioner.go @@ -25,16 +25,15 @@ import ( "regexp" "strings" - "k8s.io/kubernetes/pkg/apis/core/v1/helper" - "github.com/golang/glog" - "github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/controller" v1 "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "sigs.k8s.io/sig-storage-lib-external-provisioner/controller" ) const ( @@ -76,7 +75,7 @@ const ( var _ controller.Provisioner = &nfsProvisioner{} -func (p *nfsProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) { +func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.PersistentVolume, error) { if options.PVC.Spec.Selector != nil { return nil, fmt.Errorf("claim Selector is not supported") } @@ -99,7 +98,7 @@ func (p *nfsProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis fullPath := filepath.Join(mountPath, pvName) path := filepath.Join(p.path, pvName) - pathPattern, exists := options.Parameters["pathPattern"] + pathPattern, exists := options.StorageClass.Parameters["pathPattern"] if exists { customPath := metadata.stringParser(pathPattern) path = filepath.Join(p.path, customPath) @@ -117,9 +116,9 @@ func (p *nfsProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis Name: options.PVName, }, Spec: v1.PersistentVolumeSpec{ - PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy, + PersistentVolumeReclaimPolicy: *options.StorageClass.ReclaimPolicy, AccessModes: options.PVC.Spec.AccessModes, - MountOptions: options.MountOptions, + // MountOptions: options.MountOptions, Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], }, From 30d9813bdf0234f1aa7115164ce5e1be581a489b Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Fri, 2 Oct 2020 10:41:11 +0300 Subject: [PATCH 4/7] Updated README and saved archiveOnDelete --- README.md | 20 ++++++++--- .../provisioner.go | 35 ++++++++++++++----- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 308da047..cefc39be 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,17 @@ spec: You may also want to change the PROVISIONER_NAME above from ``fuseim.pri/ifs`` to something more descriptive like ``nfs-storage``, but if you do remember to also change the PROVISIONER_NAME in the storage class definition below: +**Step 5: Deploying your storage class** + +***Paraments:*** + +| Name | Description | Default | +|------|-------------|:--------:| +| onDelete | If it exists and has a delete value, delete the directory, if it exists and has a retain value, save the directory. | will be archived with name on the share: `archived-+volume.Name` | +| archiveOnDelete | If it exists and has a false value, delete the directory. if `onDelete` exists will be ignored. | will be archived with name on the share: `archived-+volume.Name` | +| archiveOnDelete | If it exists and has a false value, delete the directory. if `onDelete` exists will be ignored. | will be archived with name on the share: `archived-+volume.Name` | +| pathPattern | Specifies a template for creating a directory path via PVC metadata's such as labels, annotations, name or namespace. To specify metadata use `${.PVC.}`: `${PVC.namespace}`| n/a | + This is `deploy/class.yaml` which defines the NFS-Client's Kubernetes Storage Class: ```yaml @@ -116,11 +127,11 @@ metadata: name: managed-nfs-storage provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME' parameters: - archiveOnDelete: "false" # When set to "false" your PVs will not be archived - # by the provisioner upon deletion of the PVC. + pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}" # waits for nfs.io/storage-path annotation, if not specified will accept as empty string. + onDelete: delete ``` -**Step 5: Finally, test your environment!** +**Step 6: Finally, test your environment!** Now we'll test your NFS provisioner. @@ -138,7 +149,7 @@ kubectl delete -f deploy/test-pod.yaml -f deploy/test-claim.yaml Now check the folder has been deleted. -**Step 6: Deploying your own PersistentVolumeClaims**. To deploy your own PVC, make sure that you have the correct `storage-class` as indicated by your `deploy/class.yaml` file. +**Step 7: Deploying your own PersistentVolumeClaims**. To deploy your own PVC, make sure that you have the correct `storage-class` as indicated by your `deploy/class.yaml` file. For example: @@ -149,6 +160,7 @@ metadata: name: test-claim annotations: volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" + nfs.io/storage-path: "test-path" # not required, depending on whether this annotation was shown in the storage class description spec: accessModes: - ReadWriteMany diff --git a/cmd/nfs-subdir-external-provisioner/provisioner.go b/cmd/nfs-subdir-external-provisioner/provisioner.go index 88be3c85..d199293c 100644 --- a/cmd/nfs-subdir-external-provisioner/provisioner.go +++ b/cmd/nfs-subdir-external-provisioner/provisioner.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "regexp" + "strconv" "strings" "github.com/golang/glog" @@ -52,7 +53,7 @@ type pvcMetadata struct { annotations map[string]string } -var pattern = regexp.MustCompile(`{pvc\.((labels|annotations)\.(.*?)|.*?)}`) +var pattern = regexp.MustCompile(`\${\.PVC\.((labels|annotations)\.(.*?)|.*?)}`) func (meta *pvcMetadata) stringParser(str string) string { result := pattern.FindAllStringSubmatch(str, -1) @@ -148,9 +149,10 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { if err != nil { return err } - // Determine if the "archiveOnDelete" parameter exists. - // If it exists and has a false value, delete the directory. - // Otherwise, archive it. + + // Determine if the "onDelete" parameter exists. + // If it exists and has a delete value, delete the directory. + // If it exists and has a retain value, safe the directory. onDelete := storageClass.Parameters["onDelete"] switch onDelete { @@ -159,12 +161,27 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { case "retain": return nil - - default: - archivePath := filepath.Join(mountPath, "archived-"+volume.Name) - glog.V(4).Infof("archiving path %s to %s", oldPath, archivePath) - return os.Rename(oldPath, archivePath) } + + // Determine if the "archiveOnDelete" parameter exists. + // If it exists and has a false value, delete the directory. + // Otherwise, archive it. + archiveOnDelete, exists := storageClass.Parameters["archiveOnDelete"] + if exists { + if exists { + archiveBool, err := strconv.ParseBool(archiveOnDelete) + if err != nil { + return err + } + if !archiveBool { + return os.RemoveAll(oldPath) + } + } + } + + archivePath := filepath.Join(mountPath, "archived-"+volume.Name) + glog.V(4).Infof("archiving path %s to %s", oldPath, archivePath) + return os.Rename(oldPath, archivePath) } // getClassForVolume returns StorageClass From 8433ff96f961b3f3df684ff0cf2a2bd3ef092a93 Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Fri, 2 Oct 2020 10:48:45 +0300 Subject: [PATCH 5/7] Updated README and saved archiveOnDelete --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index cefc39be..7789f6dd 100644 --- a/README.md +++ b/README.md @@ -114,8 +114,7 @@ You may also want to change the PROVISIONER_NAME above from ``fuseim.pri/ifs`` t | Name | Description | Default | |------|-------------|:--------:| | onDelete | If it exists and has a delete value, delete the directory, if it exists and has a retain value, save the directory. | will be archived with name on the share: `archived-+volume.Name` | -| archiveOnDelete | If it exists and has a false value, delete the directory. if `onDelete` exists will be ignored. | will be archived with name on the share: `archived-+volume.Name` | -| archiveOnDelete | If it exists and has a false value, delete the directory. if `onDelete` exists will be ignored. | will be archived with name on the share: `archived-+volume.Name` | +| archiveOnDelete | If it exists and has a false value, delete the directory. if `onDelete` exists, `archiveOnDelete` will be ignored. | will be archived with name on the share: `archived-+volume.Name` | | pathPattern | Specifies a template for creating a directory path via PVC metadata's such as labels, annotations, name or namespace. To specify metadata use `${.PVC.}`: `${PVC.namespace}`| n/a | This is `deploy/class.yaml` which defines the NFS-Client's Kubernetes Storage Class: From 513433d4b16b88173f4173dfe9dc6a6edbfea1a4 Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Thu, 8 Oct 2020 15:40:37 +0300 Subject: [PATCH 6/7] Update README, remove dublicated lines --- README.md | 2 +- cmd/nfs-subdir-external-provisioner/provisioner.go | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7789f6dd..326f085f 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ You may also want to change the PROVISIONER_NAME above from ``fuseim.pri/ifs`` t **Step 5: Deploying your storage class** -***Paraments:*** +***paraments:*** | Name | Description | Default | |------|-------------|:--------:| diff --git a/cmd/nfs-subdir-external-provisioner/provisioner.go b/cmd/nfs-subdir-external-provisioner/provisioner.go index d199293c..d220f07f 100644 --- a/cmd/nfs-subdir-external-provisioner/provisioner.go +++ b/cmd/nfs-subdir-external-provisioner/provisioner.go @@ -168,14 +168,12 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { // Otherwise, archive it. archiveOnDelete, exists := storageClass.Parameters["archiveOnDelete"] if exists { - if exists { - archiveBool, err := strconv.ParseBool(archiveOnDelete) - if err != nil { - return err - } - if !archiveBool { - return os.RemoveAll(oldPath) - } + archiveBool, err := strconv.ParseBool(archiveOnDelete) + if err != nil { + return err + } + if !archiveBool { + return os.RemoveAll(oldPath) } } From 1d8c18e11cb3424bd6050cac7df0ef2ed998e9a0 Mon Sep 17 00:00:00 2001 From: Hanna Bledai Date: Fri, 9 Oct 2020 10:16:47 +0300 Subject: [PATCH 7/7] fixed Parameters --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 326f085f..bafc001b 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ You may also want to change the PROVISIONER_NAME above from ``fuseim.pri/ifs`` t **Step 5: Deploying your storage class** -***paraments:*** +***Parameters:*** | Name | Description | Default | |------|-------------|:--------:|