Merge pull request #530 from navilg/feature/on-delete-archive

feat: archive on delete support
This commit is contained in:
Kubernetes Prow Robot 2023-11-09 04:17:34 +01:00 committed by GitHub
commit be6ca6fc7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 102 additions and 21 deletions

View File

@ -68,7 +68,7 @@ The following table lists the configurable parameters of the latest NFS CSI Driv
| `controller.runOnMaster` | run controller on master node(deprecated on k8s 1.25+) |`false` |
| `controller.runOnControlPlane` | run controller on control plane node |`false` |
| `controller.dnsPolicy` | dnsPolicy of controller driver, available values: `Default`, `ClusterFirstWithHostNet`, `ClusterFirst` | `ClusterFirstWithHostNet` |
| `controller.defaultOnDeletePolicy` | default policy for deleting subdirectory when deleting a volume, available values: `delete`, `retain` | `delete` |
| `controller.defaultOnDeletePolicy` | default policy for deleting subdirectory when deleting a volume, available values: `delete`, `retain`, `archive` | `delete` |
| `controller.logLevel` | controller driver log level |`5` |
| `controller.workingMountDir` | working directory for provisioner to mount nfs shares temporarily | `/tmp` |
| `controller.affinity` | controller pod affinity | `{}` |

View File

@ -10,7 +10,7 @@ server | NFS Server address | domain name `nfs-server.default.svc.cluster.local`
share | NFS share path | `/` | Yes |
subDir | sub directory under nfs share | | No | if sub directory does not exist, this driver would create a new one
mountPermissions | mounted folder permissions. The default is `0`, if set as non-zero, driver will perform `chmod` after mount | | No |
onDelete | when volume is deleted, keep the directory if it's `retain` | `delete`(default), `retain` | No | `delete`
onDelete | when volume is deleted, keep the directory if it's `retain` | `delete`(default), `retain`, `archive` | No | `delete`
- VolumeID(`volumeHandle`) is the identifier of the volume handled by the driver, format of VolumeID:
```

View File

@ -240,15 +240,27 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
}
}()
// delete subdirectory under base-dir
internalVolumePath := getInternalVolumePath(cs.Driver.workingMountDir, nfsVol)
klog.V(2).Infof("Removing subdirectory at %v", internalVolumePath)
if err = os.RemoveAll(internalVolumePath); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error())
if strings.EqualFold(nfsVol.onDelete, archive) {
archivedNfsVol := *nfsVol
archivedNfsVol.subDir = "archived-" + nfsVol.subDir
archivedInternalVolumePath := getArchivedInternalVolumePath(cs.Driver.workingMountDir, nfsVol, &archivedNfsVol)
// archive subdirectory under base-dir
klog.V(2).Infof("archiving subdirectory %s --> %s", internalVolumePath, archivedInternalVolumePath)
if err = os.Rename(internalVolumePath, archivedInternalVolumePath); err != nil {
return nil, status.Errorf(codes.Internal, "archive subdirectory(%s, %s) failed with %v", internalVolumePath, archivedInternalVolumePath, err.Error())
}
} else {
// delete subdirectory under base-dir
klog.V(2).Infof("removing subdirectory at %v", internalVolumePath)
if err = os.RemoveAll(internalVolumePath); err != nil {
return nil, status.Errorf(codes.Internal, "delete subdirectory(%s) failed with %v", internalVolumePath, err.Error())
}
}
} else {
klog.V(2).Infof("DeleteVolume: volume(%s) is set to retain, not deleting subdirectory", volumeID)
klog.V(2).Infof("DeleteVolume: volume(%s) is set to retain, not deleting/archiving subdirectory", volumeID)
}
return &csi.DeleteVolumeResponse{}, nil
@ -674,6 +686,10 @@ func getInternalVolumePath(workingMountDir string, vol *nfsVolume) string {
return filepath.Join(getInternalMountPath(workingMountDir, vol), vol.subDir)
}
func getArchivedInternalVolumePath(workingMountDir string, vol *nfsVolume, archVol *nfsVolume) string {
return filepath.Join(getInternalMountPath(workingMountDir, vol), archVol.subDir)
}
// Given a nfsVolume, return a CSI volume id
func getVolumeIDFromNfsVol(vol *nfsVolume) string {
idElements := make([]string, totalIDElements)
@ -681,9 +697,10 @@ func getVolumeIDFromNfsVol(vol *nfsVolume) string {
idElements[idBaseDir] = strings.Trim(vol.baseDir, "/")
idElements[idSubDir] = strings.Trim(vol.subDir, "/")
idElements[idUUID] = vol.uuid
if strings.EqualFold(vol.onDelete, retain) {
if strings.EqualFold(vol.onDelete, retain) || strings.EqualFold(vol.onDelete, archive) {
idElements[idOnDelete] = vol.onDelete
}
return strings.Join(idElements, separator)
}

View File

@ -38,18 +38,19 @@ import (
)
const (
testServer = "test-server"
testBaseDir = "test-base-dir"
testBaseDirNested = "test/base/dir"
testCSIVolume = "volume-name"
testVolumeID = "test-server/test-base-dir/volume-name"
newTestVolumeID = "test-server#test-base-dir#volume-name##"
newTestVolumeWithVolumeID = "test-server#test-base-dir#volume-name#volume-name#"
testVolumeIDNested = "test-server/test/base/dir/volume-name"
newTestVolumeIDNested = "test-server#test/base/dir#volume-name#"
newTestVolumeIDUUID = "test-server#test-base-dir#volume-name#uuid"
newTestVolumeOnDeleteRetain = "test-server#test-base-dir#volume-name#uuid#retain"
newTestVolumeOnDeleteDelete = "test-server#test-base-dir#volume-name#uuid#delete"
testServer = "test-server"
testBaseDir = "test-base-dir"
testBaseDirNested = "test/base/dir"
testCSIVolume = "volume-name"
testVolumeID = "test-server/test-base-dir/volume-name"
newTestVolumeID = "test-server#test-base-dir#volume-name##"
newTestVolumeWithVolumeID = "test-server#test-base-dir#volume-name#volume-name#"
testVolumeIDNested = "test-server/test/base/dir/volume-name"
newTestVolumeIDNested = "test-server#test/base/dir#volume-name#"
newTestVolumeIDUUID = "test-server#test-base-dir#volume-name#uuid"
newTestVolumeOnDeleteRetain = "test-server#test-base-dir#volume-name#uuid#retain"
newTestVolumeOnDeleteDelete = "test-server#test-base-dir#volume-name#uuid#delete"
newTestVolumeOnDeleteArchive = "test-server#test-base-dir#volume-name##archive"
)
func initTestController(t *testing.T) *ControllerServer {
@ -287,6 +288,14 @@ func TestDeleteVolume(t *testing.T) {
expectedErr: nil,
expectedDeleteSubDir: false,
},
{
desc: "Valid request with onDelete:archive",
testOnWindows: false,
req: &csi.DeleteVolumeRequest{VolumeId: newTestVolumeOnDeleteArchive},
resp: &csi.DeleteVolumeResponse{},
expectedErr: nil,
expectedDeleteSubDir: true,
},
}
for _, test := range cases {
@ -493,6 +502,19 @@ func TestNfsVolFromId(t *testing.T) {
},
expectErr: false,
},
{
name: "valid request nested ondelete archive",
volumeID: newTestVolumeOnDeleteArchive,
resp: &nfsVolume{
id: newTestVolumeOnDeleteArchive,
server: testServer,
baseDir: testBaseDir,
subDir: testCSIVolume,
uuid: "",
onDelete: "archive",
},
expectErr: false,
},
}
for _, test := range cases {

View File

@ -36,9 +36,10 @@ const (
separator = "#"
delete = "delete"
retain = "retain"
archive = "archive"
)
var supportedOnDeleteValues = []string{"", delete, retain}
var supportedOnDeleteValues = []string{"", delete, retain, archive}
func validateOnDeleteValue(onDelete string) error {
for _, v := range supportedOnDeleteValues {

View File

@ -333,6 +333,16 @@ func TestValidateOnDeleteValue(t *testing.T) {
onDelete: "Delete",
expected: nil,
},
{
desc: "Archive value",
onDelete: "Archive",
expected: nil,
},
{
desc: "archive value",
onDelete: "archive",
expected: nil,
},
{
desc: "invalid value",
onDelete: "invalid",

View File

@ -350,4 +350,27 @@ var _ = ginkgo.Describe("Dynamic Provisioning", func() {
}
test.Run(cs, ns)
})
ginkgo.It("should create a volume on demand with archive subdir on delete [nfs.csi.k8s.io]", func() {
pods := []testsuites.PodDetails{
{
Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data",
Volumes: []testsuites.VolumeDetails{
{
ClaimSize: "10Gi",
VolumeMount: testsuites.VolumeMountDetails{
NameGenerate: "test-volume-",
MountPathGenerate: "/mnt/test-",
},
},
},
},
}
test := testsuites.DynamicallyProvisionedCmdVolumeTest{
CSIDriver: testDriver,
Pods: pods,
StorageClassParameters: archiveStorageClassParameters,
}
test.Run(cs, ns)
})
})

View File

@ -75,6 +75,14 @@ var (
"mountPermissions": "0755",
"onDelete": "retain",
}
archiveStorageClassParameters = map[string]string{
"server": nfsServerAddress,
"share": nfsShare,
"csi.storage.k8s.io/provisioner-secret-name": "mount-options",
"csi.storage.k8s.io/provisioner-secret-namespace": "default",
"mountPermissions": "0755",
"onDelete": "archive",
}
controllerServer *nfs.ControllerServer
)