Skip to content

Commit e230b7f

Browse files
authored
Merge pull request #878 from andyzhangx/fix-remove-root-dir-issue
fix: only cleanup empty parent directories during DeleteVolume
2 parents bd2fa2f + 0d8402b commit e230b7f

File tree

3 files changed

+95
-35
lines changed

3 files changed

+95
-35
lines changed

pkg/nfs/controllerserver.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -292,17 +292,16 @@ 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+
klog.V(2).Infof("DeleteVolume: removing empty directories in %s", parentDir)
302+
if err = removeEmptyDirs(getInternalMountPath(cs.Driver.workingMountDir, nfsVol), parentDir); err != nil {
303+
return nil, status.Errorf(codes.Internal, "failed to remove empty directories: %v", err)
304+
}
306305
}
307306
} else {
308307
klog.V(2).Infof("DeleteVolume: volume(%s) is set to retain, not deleting/archiving subdirectory", volumeID)

pkg/nfs/utils.go

Lines changed: 45 additions & 4 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"
@@ -216,10 +217,50 @@ func waitForPathNotExistWithTimeout(path string, timeout time.Duration) error {
216217
}
217218
}
218219

219-
// getRootDir returns the root directory of the given directory
220-
func getRootDir(path string) string {
221-
parts := strings.Split(path, "/")
222-
return parts[0]
220+
// removeEmptyDirs removes empty directories in the given directory dir until the parent directory parentDir
221+
// It will remove all empty directories in the path from the given directory to the parent directory
222+
// It will not remove the parent directory parentDir
223+
func removeEmptyDirs(parentDir, dir string) error {
224+
if parentDir == "" || dir == "" {
225+
return nil
226+
}
227+
228+
absParentDir, err := filepath.Abs(parentDir)
229+
if err != nil {
230+
return err
231+
}
232+
233+
absDir, err := filepath.Abs(dir)
234+
if err != nil {
235+
return err
236+
}
237+
238+
if !strings.HasPrefix(absDir, absParentDir) {
239+
return fmt.Errorf("dir %s is not a subdirectory of parentDir %s", dir, parentDir)
240+
}
241+
242+
var depth int
243+
for absDir != absParentDir {
244+
entries, err := os.ReadDir(absDir)
245+
if err != nil {
246+
return err
247+
}
248+
if len(entries) == 0 {
249+
klog.V(2).Infof("Removing empty directory %s", absDir)
250+
if err := os.Remove(absDir); err != nil {
251+
return err
252+
}
253+
} else {
254+
klog.V(2).Infof("Directory %s is not empty", absDir)
255+
break
256+
}
257+
if depth++; depth > 10 {
258+
return fmt.Errorf("depth of directory %s is too deep", dir)
259+
}
260+
absDir = filepath.Dir(absDir)
261+
}
262+
263+
return nil
223264
}
224265

225266
// ExecFunc returns a exec function's output and error

pkg/nfs/utils_test.go

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -388,43 +388,63 @@ func TestWaitForPathNotExistWithTimeout(t *testing.T) {
388388
}
389389
}
390390

391-
func TestGetRootPath(t *testing.T) {
391+
func TestRemoveEmptyDirs(t *testing.T) {
392+
parentDir, _ := os.Getwd()
393+
emptyDirOneLevel, _ := getWorkDirPath("emptyDir1")
394+
emptyDirTwoLevels, _ := getWorkDirPath("emptyDir2/emptyDir2")
395+
emptyDirThreeLevels, _ := getWorkDirPath("emptyDir3/emptyDir2/emptyDir3")
396+
392397
tests := []struct {
393-
desc string
394-
dir string
395-
expected string
398+
desc string
399+
parentDir string
400+
dir string
401+
expected error
396402
}{
397403
{
398-
desc: "empty path",
399-
dir: "",
400-
expected: "",
404+
desc: "empty path",
405+
parentDir: parentDir,
406+
expected: nil,
401407
},
402408
{
403-
desc: "root path",
404-
dir: "/",
405-
expected: "",
409+
desc: "empty dir with one level",
410+
parentDir: parentDir,
411+
dir: emptyDirOneLevel,
412+
expected: nil,
406413
},
407414
{
408-
desc: "subdir path",
409-
dir: "/subdir",
410-
expected: "",
415+
desc: "dir is not a subdirectory of parentDir",
416+
parentDir: "/dir1",
417+
dir: "/dir2",
418+
expected: fmt.Errorf("dir /dir2 is not a subdirectory of parentDir /dir1"),
411419
},
412420
{
413-
desc: "subdir path without leading slash",
414-
dir: "subdir",
415-
expected: "subdir",
421+
desc: "empty dir with two levels",
422+
parentDir: parentDir,
423+
dir: emptyDirTwoLevels,
424+
expected: nil,
416425
},
417426
{
418-
desc: "multiple subdir path without leading slash",
419-
dir: "subdir/subdir2",
420-
expected: "subdir",
427+
desc: "empty dir with three levels",
428+
parentDir: parentDir,
429+
dir: emptyDirThreeLevels,
430+
expected: nil,
421431
},
422432
}
423433

424434
for _, test := range tests {
425-
result := getRootDir(test.dir)
426-
if result != test.expected {
427-
t.Errorf("Unexpected result: %s, expected: %s", result, test.expected)
435+
if strings.Contains(test.dir, "emptyDir") {
436+
_ = makeDir(test.dir)
437+
defer os.RemoveAll(test.dir)
438+
}
439+
err := removeEmptyDirs(test.parentDir, test.dir)
440+
if !reflect.DeepEqual(err, test.expected) {
441+
t.Errorf("test[%s]: unexpected output: %v, expected result: %v", test.desc, err, test.expected)
442+
}
443+
if strings.Contains(test.dir, "emptyDir") {
444+
// directory should be removed
445+
if _, err := os.Stat(emptyDirOneLevel); !os.IsNotExist(err) {
446+
t.Errorf("test[%s]: directory %s should be removed", test.desc, emptyDirOneLevel)
447+
}
428448
}
429449
}
430450
}

0 commit comments

Comments
 (0)