mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
Fix bug:Kubelet failure to umount mount points
This commit is contained in:
parent
f5f6f3e715
commit
19003486bf
@ -147,15 +147,12 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core/install:go_default_library",
|
"//pkg/apis/core/install:go_default_library",
|
||||||
"//pkg/apis/core/v1/helper:go_default_library",
|
"//pkg/apis/core/v1/helper:go_default_library",
|
||||||
|
"//pkg/util/mount:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
] + select({
|
"//vendor/k8s.io/client-go/util/testing:go_default_library",
|
||||||
"@io_bazel_rules_go//go/platform:linux": [
|
],
|
||||||
"//vendor/k8s.io/client-go/util/testing:go_default_library",
|
|
||||||
],
|
|
||||||
"//conditions:default": [],
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
@ -96,29 +97,42 @@ func UnmountPath(mountPath string, mounter mount.Interface) error {
|
|||||||
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
|
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
|
||||||
// IsNotMountPoint is more expensive but properly handles bind mounts.
|
// IsNotMountPoint is more expensive but properly handles bind mounts.
|
||||||
func UnmountMountPoint(mountPath string, mounter mount.Interface, extensiveMountPointCheck bool) error {
|
func UnmountMountPoint(mountPath string, mounter mount.Interface, extensiveMountPointCheck bool) error {
|
||||||
if pathExists, pathErr := PathExists(mountPath); pathErr != nil {
|
pathExists, pathErr := PathExists(mountPath)
|
||||||
return fmt.Errorf("Error checking if path exists: %v", pathErr)
|
if !pathExists {
|
||||||
} else if !pathExists {
|
|
||||||
glog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
|
glog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
corruptedMnt := isCorruptedMnt(pathErr)
|
||||||
var notMnt bool
|
if pathErr != nil && !corruptedMnt {
|
||||||
var err error
|
return fmt.Errorf("Error checking path: %v", pathErr)
|
||||||
|
|
||||||
if extensiveMountPointCheck {
|
|
||||||
notMnt, err = mount.IsNotMountPoint(mounter, mountPath)
|
|
||||||
} else {
|
|
||||||
notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
|
|
||||||
}
|
}
|
||||||
|
return doUnmountMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
// doUnmountMountPoint is a common unmount routine that unmounts the given path and
|
||||||
return err
|
// deletes the remaining directory if successful.
|
||||||
}
|
// if extensiveMountPointCheck is true
|
||||||
|
// IsNotMountPoint will be called instead of IsLikelyNotMountPoint.
|
||||||
|
// IsNotMountPoint is more expensive but properly handles bind mounts.
|
||||||
|
// if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, Take it as an argument for convenience of testing
|
||||||
|
func doUnmountMountPoint(mountPath string, mounter mount.Interface, extensiveMountPointCheck bool, corruptedMnt bool) error {
|
||||||
|
if !corruptedMnt {
|
||||||
|
var notMnt bool
|
||||||
|
var err error
|
||||||
|
if extensiveMountPointCheck {
|
||||||
|
notMnt, err = mount.IsNotMountPoint(mounter, mountPath)
|
||||||
|
} else {
|
||||||
|
notMnt, err = mounter.IsLikelyNotMountPoint(mountPath)
|
||||||
|
}
|
||||||
|
|
||||||
if notMnt {
|
if err != nil {
|
||||||
glog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
|
return err
|
||||||
return os.Remove(mountPath)
|
}
|
||||||
|
|
||||||
|
if notMnt {
|
||||||
|
glog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath)
|
||||||
|
return os.Remove(mountPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount the mount path
|
// Unmount the mount path
|
||||||
@ -128,7 +142,7 @@ func UnmountMountPoint(mountPath string, mounter mount.Interface, extensiveMount
|
|||||||
}
|
}
|
||||||
notMnt, mntErr := mounter.IsLikelyNotMountPoint(mountPath)
|
notMnt, mntErr := mounter.IsLikelyNotMountPoint(mountPath)
|
||||||
if mntErr != nil {
|
if mntErr != nil {
|
||||||
return err
|
return mntErr
|
||||||
}
|
}
|
||||||
if notMnt {
|
if notMnt {
|
||||||
glog.V(4).Infof("%q is unmounted, deleting the directory", mountPath)
|
glog.V(4).Infof("%q is unmounted, deleting the directory", mountPath)
|
||||||
@ -144,11 +158,32 @@ func PathExists(path string) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
} else if os.IsNotExist(err) {
|
} else if os.IsNotExist(err) {
|
||||||
return false, nil
|
return false, nil
|
||||||
|
} else if isCorruptedMnt(err) {
|
||||||
|
return true, err
|
||||||
} else {
|
} else {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isCorruptedMnt return true if err is about corrupted mount point
|
||||||
|
func isCorruptedMnt(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var underlyingError error
|
||||||
|
switch pe := err.(type) {
|
||||||
|
case nil:
|
||||||
|
return false
|
||||||
|
case *os.PathError:
|
||||||
|
underlyingError = pe.Err
|
||||||
|
case *os.LinkError:
|
||||||
|
underlyingError = pe.Err
|
||||||
|
case *os.SyscallError:
|
||||||
|
underlyingError = pe.Err
|
||||||
|
}
|
||||||
|
return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE
|
||||||
|
}
|
||||||
|
|
||||||
// GetSecretForPod locates secret by name in the pod's namespace and returns secret map
|
// GetSecretForPod locates secret by name in the pod's namespace and returns secret map
|
||||||
func GetSecretForPod(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (map[string]string, error) {
|
func GetSecretForPod(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (map[string]string, error) {
|
||||||
secret := make(map[string]string)
|
secret := make(map[string]string)
|
||||||
|
@ -24,10 +24,12 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
utiltesting "k8s.io/client-go/util/testing"
|
||||||
// util.go uses api.Codecs.LegacyCodec so import this package to do some
|
// util.go uses api.Codecs.LegacyCodec so import this package to do some
|
||||||
// resource initialization.
|
// resource initialization.
|
||||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||||
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
var nodeLabels map[string]string = map[string]string{
|
var nodeLabels map[string]string = map[string]string{
|
||||||
@ -263,3 +265,42 @@ func TestZonesToSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDoUnmountMountPoint(t *testing.T) {
|
||||||
|
|
||||||
|
tmpDir1, err1 := utiltesting.MkTmpdir("umount_test1")
|
||||||
|
if err1 != nil {
|
||||||
|
t.Fatalf("error creating temp dir: %v", err1)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir1)
|
||||||
|
|
||||||
|
tmpDir2, err2 := utiltesting.MkTmpdir("umount_test2")
|
||||||
|
if err2 != nil {
|
||||||
|
t.Fatalf("error creating temp dir: %v", err2)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir2)
|
||||||
|
|
||||||
|
// Second part: want no error
|
||||||
|
tests := []struct {
|
||||||
|
mountPath string
|
||||||
|
corruptedMnt bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
mountPath: tmpDir1,
|
||||||
|
corruptedMnt: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mountPath: tmpDir2,
|
||||||
|
corruptedMnt: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fake := &mount.FakeMounter{}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
err := doUnmountMountPoint(tt.mountPath, fake, false, tt.corruptedMnt)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("err Expected nil, but got: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user