Unverified Commit 3623b4c2 by Kubernetes Prow Robot Committed by GitHub

Merge pull request #7 from Bledai/Update-path-creation-and-save-data-after-removing-PV

Update path creation and implemented possibility save data after removing PV
parents a8ea0c5c 9c630ed0
...@@ -107,6 +107,16 @@ spec: ...@@ -107,6 +107,16 @@ 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: 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**
***Parameters:***
| 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, `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: This is `deploy/class.yaml` which defines the NFS-Client's Kubernetes Storage Class:
```yaml ```yaml
...@@ -116,11 +126,11 @@ metadata: ...@@ -116,11 +126,11 @@ metadata:
name: managed-nfs-storage name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME' provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters: parameters:
archiveOnDelete: "false" # When set to "false" your PVs will not be archived pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}" # waits for nfs.io/storage-path annotation, if not specified will accept as empty string.
# by the provisioner upon deletion of the PVC. onDelete: delete
``` ```
**Step 5: Finally, test your environment!** **Step 6: Finally, test your environment!**
Now we'll test your NFS provisioner. Now we'll test your NFS provisioner.
...@@ -138,7 +148,7 @@ kubectl delete -f deploy/test-pod.yaml -f deploy/test-claim.yaml ...@@ -138,7 +148,7 @@ kubectl delete -f deploy/test-pod.yaml -f deploy/test-claim.yaml
Now check the folder has been deleted. 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: For example:
...@@ -149,6 +159,7 @@ metadata: ...@@ -149,6 +159,7 @@ metadata:
name: test-claim name: test-claim
annotations: annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" 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: spec:
accessModes: accessModes:
- ReadWriteMany - ReadWriteMany
......
...@@ -22,18 +22,19 @@ import ( ...@@ -22,18 +22,19 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"strconv" "strconv"
"strings" "strings"
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/sig-storage-lib-external-provisioner/controller" "sigs.k8s.io/sig-storage-lib-external-provisioner/controller"
) )
...@@ -48,6 +49,29 @@ type nfsProvisioner struct { ...@@ -48,6 +49,29 @@ type nfsProvisioner struct {
path string path string
} }
type pvcMetadata struct {
data map[string]string
labels map[string]string
annotations map[string]string
}
var pattern = regexp.MustCompile(`\${\.PVC\.((labels|annotations)\.(.*?)|.*?)}`)
func (meta *pvcMetadata) stringParser(str string) string {
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":
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 ( const (
mountPath = "/persistentvolumes" mountPath = "/persistentvolumes"
) )
...@@ -65,15 +89,31 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per ...@@ -65,15 +89,31 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per
pvName := strings.Join([]string{pvcNamespace, pvcName, options.PVName}, "-") 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) fullPath := filepath.Join(mountPath, pvName)
path := filepath.Join(p.path, pvName)
pathPattern, exists := options.StorageClass.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) glog.V(4).Infof("creating path %s", fullPath)
if err := os.MkdirAll(fullPath, 0777); err != nil { if err := os.MkdirAll(fullPath, 0777); err != nil {
return nil, errors.New("unable to create directory to provision new pv: " + err.Error()) return nil, errors.New("unable to create directory to provision new pv: " + err.Error())
} }
os.Chmod(fullPath, 0777) os.Chmod(fullPath, 0777)
path := filepath.Join(p.path, pvName)
pv := &v1.PersistentVolume{ pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: options.PVName, Name: options.PVName,
...@@ -81,7 +121,7 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per ...@@ -81,7 +121,7 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per
Spec: v1.PersistentVolumeSpec{ Spec: v1.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: *options.StorageClass.ReclaimPolicy, PersistentVolumeReclaimPolicy: *options.StorageClass.ReclaimPolicy,
AccessModes: options.PVC.Spec.AccessModes, AccessModes: options.PVC.Spec.AccessModes,
//MountOptions: options.MountOptions, // MountOptions: options.MountOptions,
Capacity: v1.ResourceList{ Capacity: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)],
}, },
...@@ -99,8 +139,9 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per ...@@ -99,8 +139,9 @@ func (p *nfsProvisioner) Provision(options controller.ProvisionOptions) (*v1.Per
func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error {
path := volume.Spec.PersistentVolumeSource.NFS.Path path := volume.Spec.PersistentVolumeSource.NFS.Path
pvName := filepath.Base(path) relativePath := strings.Replace(path, p.path, "", 1)
oldPath := filepath.Join(mountPath, pvName) oldPath := filepath.Join(mountPath, relativePath)
if _, err := os.Stat(oldPath); os.IsNotExist(err) { if _, err := os.Stat(oldPath); os.IsNotExist(err) {
glog.Warningf("path %s does not exist, deletion skipped", oldPath) glog.Warningf("path %s does not exist, deletion skipped", oldPath)
return nil return nil
...@@ -110,6 +151,20 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { ...@@ -110,6 +151,20 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error {
if err != nil { if err != nil {
return err return err
} }
// 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 {
case "delete":
return os.RemoveAll(oldPath)
case "retain":
return nil
}
// Determine if the "archiveOnDelete" parameter exists. // Determine if the "archiveOnDelete" parameter exists.
// If it exists and has a false value, delete the directory. // If it exists and has a false value, delete the directory.
// Otherwise, archive it. // Otherwise, archive it.
...@@ -124,10 +179,9 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error { ...@@ -124,10 +179,9 @@ func (p *nfsProvisioner) Delete(volume *v1.PersistentVolume) error {
} }
} }
archivePath := filepath.Join(mountPath, "archived-"+pvName) archivePath := filepath.Join(mountPath, "archived-"+volume.Name)
glog.V(4).Infof("archiving path %s to %s", oldPath, archivePath) glog.V(4).Infof("archiving path %s to %s", oldPath, archivePath)
return os.Rename(oldPath, archivePath) return os.Rename(oldPath, archivePath)
} }
// getClassForVolume returns StorageClass // getClassForVolume returns StorageClass
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment