Skip to content

Commit 79821b2

Browse files
committed
fix: only cleanup empty parent directories during DeleteVolume
1 parent bd2fa2f commit 79821b2

File tree

3 files changed

+108
-9
lines changed

3 files changed

+108
-9
lines changed

pkg/nfs/controllerserver.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -292,17 +292,18 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
292292
}
293293
klog.V(2).Infof("archived subdirectory %s --> %s", internalVolumePath, archivedInternalVolumePath)
294294
} else {
295-
rootDir := getRootDir(nfsVol.subDir)
296-
if rootDir != "" {
297-
rootDir = filepath.Join(getInternalMountPath(cs.Driver.workingMountDir, nfsVol), rootDir)
298-
} else {
299-
rootDir = internalVolumePath
300-
}
301-
// delete subdirectory under base-dir
302-
klog.V(2).Infof("removing subdirectory at %v on internalVolumePath %s", rootDir, internalVolumePath)
303-
if err = os.RemoveAll(rootDir); err != nil {
295+
klog.V(2).Infof("removing subdirectory at %v", internalVolumePath)
296+
if err = os.RemoveAll(internalVolumePath); err != nil {
304297
return nil, status.Errorf(codes.Internal, "delete subdirectory(%s) failed with %v", internalVolumePath, err)
305298
}
299+
300+
parentDir := filepath.Dir(internalVolumePath)
301+
if parentDir != "" {
302+
klog.V(2).Infof("DeleteVolume: removing empty directories in %s", parentDir)
303+
if err = removeEmptyDirs(getInternalMountPath(cs.Driver.workingMountDir, nfsVol), parentDir); err != nil {
304+
return nil, status.Errorf(codes.Internal, "failed to remove empty directories: %v", err)
305+
}
306+
}
306307
}
307308
} else {
308309
klog.V(2).Infof("DeleteVolume: volume(%s) is set to retain, not deleting/archiving subdirectory", volumeID)

pkg/nfs/utils.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package nfs
1919
import (
2020
"fmt"
2121
"os"
22+
"path/filepath"
2223
"strings"
2324
"sync"
2425
"time"
@@ -222,6 +223,48 @@ func getRootDir(path string) string {
222223
return parts[0]
223224
}
224225

226+
// removeEmptyDirs removes empty directories in the given directory dir until the parent directory parentDir
227+
// It will remove all empty directories in the path from the given directory to the parent directory
228+
// It will not remove the parent directory parentDir
229+
func removeEmptyDirs(parentDir, dir string) error {
230+
if parentDir == "" || dir == "" {
231+
return nil
232+
}
233+
234+
absParentDir, err := filepath.Abs(parentDir)
235+
if err != nil {
236+
return err
237+
}
238+
239+
absDir, err := filepath.Abs(dir)
240+
if err != nil {
241+
return err
242+
}
243+
244+
var depth int
245+
for absDir != absParentDir {
246+
entries, err := os.ReadDir(absDir)
247+
if err != nil {
248+
return err
249+
}
250+
if len(entries) == 0 {
251+
klog.V(2).Infof("Removing empty directory %s", absDir)
252+
if err := os.Remove(absDir); err != nil {
253+
return err
254+
}
255+
} else {
256+
klog.V(2).Infof("Directory %s is not empty", absDir)
257+
break
258+
}
259+
if depth++; depth > 10 {
260+
return fmt.Errorf("depth of directory %s is too deep", dir)
261+
}
262+
absDir = filepath.Dir(absDir)
263+
}
264+
265+
return nil
266+
}
267+
225268
// ExecFunc returns a exec function's output and error
226269
type ExecFunc func() (err error)
227270

pkg/nfs/utils_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,61 @@ func TestGetRootPath(t *testing.T) {
429429
}
430430
}
431431

432+
func TestRemoveEmptyDirs(t *testing.T) {
433+
parentDir, _ := os.Getwd()
434+
emptyDirOneLevel, _ := getWorkDirPath("emptyDir1")
435+
emptyDirTwoLevels, _ := getWorkDirPath("emptyDir2/emptyDir2")
436+
emptyDirThreeLevels, _ := getWorkDirPath("emptyDir3/emptyDir2/emptyDir3")
437+
438+
tests := []struct {
439+
desc string
440+
parentDir string
441+
dir string
442+
expected error
443+
}{
444+
{
445+
desc: "empty path",
446+
parentDir: parentDir,
447+
expected: nil,
448+
},
449+
{
450+
desc: "empty dir with one level",
451+
parentDir: parentDir,
452+
dir: emptyDirOneLevel,
453+
expected: nil,
454+
},
455+
{
456+
desc: "empty dir with two levels",
457+
parentDir: parentDir,
458+
dir: emptyDirTwoLevels,
459+
expected: nil,
460+
},
461+
{
462+
desc: "empty dir with three levels",
463+
parentDir: parentDir,
464+
dir: emptyDirThreeLevels,
465+
expected: nil,
466+
},
467+
}
468+
469+
for _, test := range tests {
470+
if strings.Contains(test.dir, "emptyDir") {
471+
_ = makeDir(test.dir)
472+
defer os.RemoveAll(test.dir)
473+
}
474+
err := removeEmptyDirs(test.parentDir, test.dir)
475+
if !reflect.DeepEqual(err, test.expected) {
476+
t.Errorf("test[%s]: unexpected output: %v, expected result: %v", test.desc, err, test.expected)
477+
}
478+
if strings.Contains(test.dir, "emptyDir") {
479+
// directory should be removed
480+
if _, err := os.Stat(emptyDirOneLevel); !os.IsNotExist(err) {
481+
t.Errorf("test[%s]: directory %s should be removed", test.desc, emptyDirOneLevel)
482+
}
483+
}
484+
}
485+
}
486+
432487
func TestWaitUntilTimeout(t *testing.T) {
433488
tests := []struct {
434489
desc string

0 commit comments

Comments
 (0)