feat: archive pv subdir on delete
fix: failed to archive subdirectory: no such file or dir fix: failed to rename archive pvc archived-pvc-1234 fix: volume name doc: include archive on delete in doc
This commit is contained in:
parent
32d2422a74
commit
e819966385
@ -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.runOnMaster` | run controller on master node(deprecated on k8s 1.25+) |`false` |
|
||||||
| `controller.runOnControlPlane` | run controller on control plane node |`false` |
|
| `controller.runOnControlPlane` | run controller on control plane node |`false` |
|
||||||
| `controller.dnsPolicy` | dnsPolicy of controller driver, available values: `Default`, `ClusterFirstWithHostNet`, `ClusterFirst` | `ClusterFirstWithHostNet` |
|
| `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.logLevel` | controller driver log level |`5` |
|
||||||
| `controller.workingMountDir` | working directory for provisioner to mount nfs shares temporarily | `/tmp` |
|
| `controller.workingMountDir` | working directory for provisioner to mount nfs shares temporarily | `/tmp` |
|
||||||
| `controller.affinity` | controller pod affinity | `{}` |
|
| `controller.affinity` | controller pod affinity | `{}` |
|
||||||
|
|||||||
@ -10,7 +10,7 @@ server | NFS Server address | domain name `nfs-server.default.svc.cluster.local`
|
|||||||
share | NFS share path | `/` | Yes |
|
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
|
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 |
|
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:
|
- VolumeID(`volumeHandle`) is the identifier of the volume handled by the driver, format of VolumeID:
|
||||||
```
|
```
|
||||||
|
|||||||
@ -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)
|
internalVolumePath := getInternalVolumePath(cs.Driver.workingMountDir, nfsVol)
|
||||||
|
|
||||||
klog.V(2).Infof("Removing subdirectory at %v", internalVolumePath)
|
if !strings.EqualFold(nfsVol.onDelete, archive) {
|
||||||
if err = os.RemoveAll(internalVolumePath); err != nil {
|
// delete subdirectory under base-dir
|
||||||
return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error())
|
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())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 at %v", internalVolumePath)
|
||||||
|
if err = os.Rename(internalVolumePath, archivedInternalVolumePath); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to archive subdirectory: %v", err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
return &csi.DeleteVolumeResponse{}, nil
|
||||||
@ -674,6 +686,10 @@ func getInternalVolumePath(workingMountDir string, vol *nfsVolume) string {
|
|||||||
return filepath.Join(getInternalMountPath(workingMountDir, vol), vol.subDir)
|
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
|
// Given a nfsVolume, return a CSI volume id
|
||||||
func getVolumeIDFromNfsVol(vol *nfsVolume) string {
|
func getVolumeIDFromNfsVol(vol *nfsVolume) string {
|
||||||
idElements := make([]string, totalIDElements)
|
idElements := make([]string, totalIDElements)
|
||||||
@ -681,9 +697,10 @@ func getVolumeIDFromNfsVol(vol *nfsVolume) string {
|
|||||||
idElements[idBaseDir] = strings.Trim(vol.baseDir, "/")
|
idElements[idBaseDir] = strings.Trim(vol.baseDir, "/")
|
||||||
idElements[idSubDir] = strings.Trim(vol.subDir, "/")
|
idElements[idSubDir] = strings.Trim(vol.subDir, "/")
|
||||||
idElements[idUUID] = vol.uuid
|
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
|
idElements[idOnDelete] = vol.onDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(idElements, separator)
|
return strings.Join(idElements, separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,18 +38,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
testServer = "test-server"
|
testServer = "test-server"
|
||||||
testBaseDir = "test-base-dir"
|
testBaseDir = "test-base-dir"
|
||||||
testBaseDirNested = "test/base/dir"
|
testBaseDirNested = "test/base/dir"
|
||||||
testCSIVolume = "volume-name"
|
testCSIVolume = "volume-name"
|
||||||
testVolumeID = "test-server/test-base-dir/volume-name"
|
testVolumeID = "test-server/test-base-dir/volume-name"
|
||||||
newTestVolumeID = "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#"
|
newTestVolumeWithVolumeID = "test-server#test-base-dir#volume-name#volume-name#"
|
||||||
testVolumeIDNested = "test-server/test/base/dir/volume-name"
|
testVolumeIDNested = "test-server/test/base/dir/volume-name"
|
||||||
newTestVolumeIDNested = "test-server#test/base/dir#volume-name#"
|
newTestVolumeIDNested = "test-server#test/base/dir#volume-name#"
|
||||||
newTestVolumeIDUUID = "test-server#test-base-dir#volume-name#uuid"
|
newTestVolumeIDUUID = "test-server#test-base-dir#volume-name#uuid"
|
||||||
newTestVolumeOnDeleteRetain = "test-server#test-base-dir#volume-name#uuid#retain"
|
newTestVolumeOnDeleteRetain = "test-server#test-base-dir#volume-name#uuid#retain"
|
||||||
newTestVolumeOnDeleteDelete = "test-server#test-base-dir#volume-name#uuid#delete"
|
newTestVolumeOnDeleteDelete = "test-server#test-base-dir#volume-name#uuid#delete"
|
||||||
|
newTestVolumeOnDeleteArchive = "test-server#test-base-dir#volume-name#uuid#archive"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initTestController(t *testing.T) *ControllerServer {
|
func initTestController(t *testing.T) *ControllerServer {
|
||||||
@ -287,6 +288,14 @@ func TestDeleteVolume(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
expectedDeleteSubDir: false,
|
expectedDeleteSubDir: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid request with onDelete:archive",
|
||||||
|
testOnWindows: true,
|
||||||
|
req: &csi.DeleteVolumeRequest{VolumeId: newTestVolumeOnDeleteArchive},
|
||||||
|
resp: &csi.DeleteVolumeResponse{},
|
||||||
|
expectedErr: nil,
|
||||||
|
expectedDeleteSubDir: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range cases {
|
for _, test := range cases {
|
||||||
@ -493,6 +502,19 @@ func TestNfsVolFromId(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "valid request nested ondelete archive",
|
||||||
|
volumeID: newTestVolumeOnDeleteArchive,
|
||||||
|
resp: &nfsVolume{
|
||||||
|
id: newTestVolumeOnDeleteArchive,
|
||||||
|
server: testServer,
|
||||||
|
baseDir: testBaseDir,
|
||||||
|
subDir: testCSIVolume,
|
||||||
|
uuid: "uuid",
|
||||||
|
onDelete: "archive",
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range cases {
|
for _, test := range cases {
|
||||||
|
|||||||
@ -36,9 +36,10 @@ const (
|
|||||||
separator = "#"
|
separator = "#"
|
||||||
delete = "delete"
|
delete = "delete"
|
||||||
retain = "retain"
|
retain = "retain"
|
||||||
|
archive = "archive"
|
||||||
)
|
)
|
||||||
|
|
||||||
var supportedOnDeleteValues = []string{"", delete, retain}
|
var supportedOnDeleteValues = []string{"", delete, retain, archive}
|
||||||
|
|
||||||
func validateOnDeleteValue(onDelete string) error {
|
func validateOnDeleteValue(onDelete string) error {
|
||||||
for _, v := range supportedOnDeleteValues {
|
for _, v := range supportedOnDeleteValues {
|
||||||
|
|||||||
@ -333,6 +333,16 @@ func TestValidateOnDeleteValue(t *testing.T) {
|
|||||||
onDelete: "Delete",
|
onDelete: "Delete",
|
||||||
expected: nil,
|
expected: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Archive value",
|
||||||
|
onDelete: "Archive",
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "archive value",
|
||||||
|
onDelete: "archive",
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "invalid value",
|
desc: "invalid value",
|
||||||
onDelete: "invalid",
|
onDelete: "invalid",
|
||||||
|
|||||||
@ -75,6 +75,14 @@ var (
|
|||||||
"mountPermissions": "0755",
|
"mountPermissions": "0755",
|
||||||
"onDelete": "retain",
|
"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
|
controllerServer *nfs.ControllerServer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user