Skip to content

Commit

Permalink
Revert "Revert kubernetes#114605: its unit test requires root permiss…
Browse files Browse the repository at this point in the history
…ion"
  • Loading branch information
mochizuki875 authored and cartermckinnon committed Aug 8, 2023
1 parent b93a5b8 commit bb56e91
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 26 deletions.
57 changes: 31 additions & 26 deletions staging/src/k8s.io/mount-utils/mount_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,31 +362,19 @@ func (mounter *Mounter) Unmount(target string) error {
command := exec.Command("umount", target)
output, err := command.CombinedOutput()
if err != nil {
if err.Error() == errNoChildProcesses {
if command.ProcessState.Success() {
// We don't consider errNoChildProcesses an error if the process itself succeeded (see - k/k issue #103753).
return nil
}
// Rewrite err with the actual exit error of the process.
err = &exec.ExitError{ProcessState: command.ProcessState}
}
if mounter.withSafeNotMountedBehavior && strings.Contains(string(output), errNotMounted) {
klog.V(4).Infof("ignoring 'not mounted' error for %s", target)
return nil
}
return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", err, target, string(output))
return checkUmountError(target, command, output, err, mounter.withSafeNotMountedBehavior)
}
return nil
}

// UnmountWithForce unmounts given target but will retry unmounting with force option
// after given timeout.
func (mounter *Mounter) UnmountWithForce(target string, umountTimeout time.Duration) error {
err := tryUnmount(target, umountTimeout)
err := tryUnmount(target, mounter.withSafeNotMountedBehavior, umountTimeout)
if err != nil {
if err == context.DeadlineExceeded {
klog.V(2).Infof("Timed out waiting for unmount of %s, trying with -f", target)
err = forceUmount(target)
err = forceUmount(target, mounter.withSafeNotMountedBehavior)
}
return err
}
Expand Down Expand Up @@ -774,32 +762,49 @@ func (mounter *Mounter) IsMountPoint(file string) (bool, error) {
}

// tryUnmount calls plain "umount" and waits for unmountTimeout for it to finish.
func tryUnmount(path string, unmountTimeout time.Duration) error {
klog.V(4).Infof("Unmounting %s", path)
func tryUnmount(target string, withSafeNotMountedBehavior bool, unmountTimeout time.Duration) error {
klog.V(4).Infof("Unmounting %s", target)
ctx, cancel := context.WithTimeout(context.Background(), unmountTimeout)
defer cancel()

cmd := exec.CommandContext(ctx, "umount", path)
out, cmderr := cmd.CombinedOutput()
command := exec.CommandContext(ctx, "umount", target)
output, err := command.CombinedOutput()

// CombinedOutput() does not return DeadlineExceeded, make sure it's
// propagated on timeout.
if ctx.Err() != nil {
return ctx.Err()
}

if cmderr != nil {
return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", cmderr, path, string(out))
if err != nil {
return checkUmountError(target, command, output, err, withSafeNotMountedBehavior)
}
return nil
}

func forceUmount(path string) error {
cmd := exec.Command("umount", "-f", path)
out, cmderr := cmd.CombinedOutput()
func forceUmount(target string, withSafeNotMountedBehavior bool) error {
command := exec.Command("umount", "-f", target)
output, err := command.CombinedOutput()

if cmderr != nil {
return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", cmderr, path, string(out))
if err != nil {
return checkUmountError(target, command, output, err, withSafeNotMountedBehavior)
}
return nil
}

// checkUmountError checks a result of umount command and determine a return value.
func checkUmountError(target string, command *exec.Cmd, output []byte, err error, withSafeNotMountedBehavior bool) error {
if err.Error() == errNoChildProcesses {
if command.ProcessState.Success() {
// We don't consider errNoChildProcesses an error if the process itself succeeded (see - k/k issue #103753).
return nil
}
// Rewrite err with the actual exit error of the process.
err = &exec.ExitError{ProcessState: command.ProcessState}
}
if withSafeNotMountedBehavior && strings.Contains(string(output), errNotMounted) {
klog.V(4).Infof("ignoring 'not mounted' error for %s", target)
return nil
}
return fmt.Errorf("unmount failed: %v\nUnmounting arguments: %s\nOutput: %s", err, target, string(output))
}
25 changes: 25 additions & 0 deletions staging/src/k8s.io/mount-utils/mount_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,3 +620,28 @@ func makeFakeCommandAction(stdout string, err error) testexec.FakeCommandAction
return testexec.InitFakeCmd(&c, cmd, args...)
}
}

func TestNotMountedBehaviorOfUnmount(t *testing.T) {
target, err := ioutil.TempDir("", "kubelet-umount")
if err != nil {
t.Errorf("Cannot create temp dir: %v", err)
}

defer os.RemoveAll(target)

m := Mounter{withSafeNotMountedBehavior: true}
if err = m.Unmount(target); err != nil {
t.Errorf(`Expect complete Unmount(), but it dose not: %v`, err)
}

if err = tryUnmount(target, m.withSafeNotMountedBehavior, time.Minute); err != nil {
t.Errorf(`Expect complete tryUnmount(), but it does not: %v`, err)
}

// forceUmount exec "umount -f", so skip this case if user is not root.
if os.Getuid() == 0 {
if err = forceUmount(target, m.withSafeNotMountedBehavior); err != nil {
t.Errorf(`Expect complete forceUnmount(), but it does not: %v`, err)
}
}
}

0 comments on commit bb56e91

Please sign in to comment.