Skip to content

Commit 14c6964

Browse files
authored
Merge pull request kubernetes#87166 from jingxu97/Jan/mountcheckfix
Fix issue in kubelet getMountedVolumePathListFromDisk
2 parents e529bd0 + 7012994 commit 14c6964

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
lines changed

pkg/kubelet/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ go_library(
152152
"//vendor/k8s.io/utils/mount:go_default_library",
153153
"//vendor/k8s.io/utils/net:go_default_library",
154154
"//vendor/k8s.io/utils/path:go_default_library",
155+
"//vendor/k8s.io/utils/strings:go_default_library",
155156
] + select({
156157
"@io_bazel_rules_go//go/platform:windows": [
157158
"//pkg/kubelet/winstats:go_default_library",

pkg/kubelet/kubelet_getters.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"k8s.io/klog/v2"
2828
"k8s.io/utils/mount"
2929
utilpath "k8s.io/utils/path"
30+
utilstrings "k8s.io/utils/strings"
3031

3132
v1 "k8s.io/api/core/v1"
3233
"k8s.io/apimachinery/pkg/types"
@@ -35,6 +36,7 @@ import (
3536
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
3637
kubelettypes "k8s.io/kubernetes/pkg/kubelet/types"
3738
utilnode "k8s.io/kubernetes/pkg/util/node"
39+
"k8s.io/kubernetes/pkg/volume/csi"
3840
)
3941

4042
// getRootDir returns the full path to the directory under which kubelet can
@@ -310,8 +312,22 @@ func (kl *Kubelet) getPodVolumePathListFromDisk(podUID types.UID) ([]string, err
310312
if err != nil {
311313
return volumes, fmt.Errorf("could not read directory %s: %v", volumePluginPath, err)
312314
}
313-
for _, volumeDir := range volumeDirs {
314-
volumes = append(volumes, filepath.Join(volumePluginPath, volumeDir))
315+
unescapePluginName := utilstrings.UnescapeQualifiedName(volumePluginName)
316+
317+
if unescapePluginName != csi.CSIPluginName {
318+
for _, volumeDir := range volumeDirs {
319+
volumes = append(volumes, filepath.Join(volumePluginPath, volumeDir))
320+
}
321+
} else {
322+
// For CSI volumes, the mounted volume path has an extra sub path "/mount", so also add it
323+
// to the list if the mounted path exists.
324+
for _, volumeDir := range volumeDirs {
325+
path := filepath.Join(volumePluginPath, volumeDir)
326+
csimountpath := csi.GetCSIMounterPath(path)
327+
if pathExists, _ := mount.PathExists(csimountpath); pathExists {
328+
volumes = append(volumes, csimountpath)
329+
}
330+
}
315331
}
316332
}
317333
return volumes, nil
@@ -323,10 +339,15 @@ func (kl *Kubelet) getMountedVolumePathListFromDisk(podUID types.UID) ([]string,
323339
if err != nil {
324340
return mountedVolumes, err
325341
}
342+
// Only use IsLikelyNotMountPoint to check might not cover all cases. For CSI volumes that
343+
// either: 1) don't mount or 2) bind mount in the rootfs, the mount check will not work as expected.
344+
// We plan to remove this mountpoint check as a condition before deleting pods since it is
345+
// not reliable and the condition might be different for different types of volumes. But it requires
346+
// a reliable way to clean up unused volume dir to avoid problems during pod deletion. See discussion in issue #74650
326347
for _, volumePath := range volumePaths {
327348
isNotMount, err := kl.mounter.IsLikelyNotMountPoint(volumePath)
328349
if err != nil {
329-
return mountedVolumes, err
350+
return mountedVolumes, fmt.Errorf("fail to check mount point %q: %v", volumePath, err)
330351
}
331352
if !isNotMount {
332353
mountedVolumes = append(mountedVolumes, volumePath)

pkg/kubelet/kubelet_volumes_linux_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ import (
2828
v1 "k8s.io/api/core/v1"
2929
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3030

31+
"k8s.io/apimachinery/pkg/types"
3132
_ "k8s.io/kubernetes/pkg/apis/core/install"
33+
"k8s.io/utils/mount"
3234
)
3335

3436
func validateDirExists(dir string) error {
@@ -154,3 +156,115 @@ func TestCleanupOrphanedPodDirs(t *testing.T) {
154156
})
155157
}
156158
}
159+
160+
func TestPodVolumesExistWithMount(t *testing.T) {
161+
poduid := types.UID("poduid")
162+
testCases := map[string]struct {
163+
prepareFunc func(kubelet *Kubelet) error
164+
expected bool
165+
}{
166+
"noncsivolume-dir-not-exist": {
167+
prepareFunc: func(kubelet *Kubelet) error {
168+
return nil
169+
},
170+
expected: false,
171+
},
172+
"noncsivolume-dir-exist-noplugins": {
173+
prepareFunc: func(kubelet *Kubelet) error {
174+
podDir := kubelet.getPodDir(poduid)
175+
return os.MkdirAll(filepath.Join(podDir, "volumes/"), 0750)
176+
},
177+
expected: false,
178+
},
179+
"noncsivolume-dir-exist-nomount": {
180+
prepareFunc: func(kubelet *Kubelet) error {
181+
podDir := kubelet.getPodDir(poduid)
182+
return os.MkdirAll(filepath.Join(podDir, "volumes/plugin/name"), 0750)
183+
},
184+
expected: false,
185+
},
186+
"noncsivolume-dir-exist-with-mount": {
187+
prepareFunc: func(kubelet *Kubelet) error {
188+
podDir := kubelet.getPodDir(poduid)
189+
volumePath := filepath.Join(podDir, "volumes/plugin/name")
190+
if err := os.MkdirAll(volumePath, 0750); err != nil {
191+
return err
192+
}
193+
fm := mount.NewFakeMounter(
194+
[]mount.MountPoint{
195+
{Device: "/dev/sdb", Path: volumePath},
196+
})
197+
kubelet.mounter = fm
198+
return nil
199+
},
200+
expected: true,
201+
},
202+
"noncsivolume-dir-exist-nomount-withcsimountpath": {
203+
prepareFunc: func(kubelet *Kubelet) error {
204+
podDir := kubelet.getPodDir(poduid)
205+
volumePath := filepath.Join(podDir, "volumes/plugin/name/mount")
206+
if err := os.MkdirAll(volumePath, 0750); err != nil {
207+
return err
208+
}
209+
fm := mount.NewFakeMounter(
210+
[]mount.MountPoint{
211+
{Device: "/dev/sdb", Path: volumePath},
212+
})
213+
kubelet.mounter = fm
214+
return nil
215+
},
216+
expected: false,
217+
},
218+
"csivolume-dir-exist-nomount": {
219+
prepareFunc: func(kubelet *Kubelet) error {
220+
podDir := kubelet.getPodDir(poduid)
221+
volumePath := filepath.Join(podDir, "volumes/kubernetes.io~csi/name")
222+
return os.MkdirAll(volumePath, 0750)
223+
},
224+
expected: false,
225+
},
226+
"csivolume-dir-exist-mount-nocsimountpath": {
227+
prepareFunc: func(kubelet *Kubelet) error {
228+
podDir := kubelet.getPodDir(poduid)
229+
volumePath := filepath.Join(podDir, "volumes/kubernetes.io~csi/name/mount")
230+
return os.MkdirAll(volumePath, 0750)
231+
},
232+
expected: false,
233+
},
234+
"csivolume-dir-exist-withcsimountpath": {
235+
prepareFunc: func(kubelet *Kubelet) error {
236+
podDir := kubelet.getPodDir(poduid)
237+
volumePath := filepath.Join(podDir, "volumes/kubernetes.io~csi/name/mount")
238+
if err := os.MkdirAll(volumePath, 0750); err != nil {
239+
return err
240+
}
241+
fm := mount.NewFakeMounter(
242+
[]mount.MountPoint{
243+
{Device: "/dev/sdb", Path: volumePath},
244+
})
245+
kubelet.mounter = fm
246+
return nil
247+
},
248+
expected: true,
249+
},
250+
}
251+
252+
for name, tc := range testCases {
253+
t.Run(name, func(t *testing.T) {
254+
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
255+
defer testKubelet.Cleanup()
256+
kubelet := testKubelet.kubelet
257+
258+
if tc.prepareFunc != nil {
259+
if err := tc.prepareFunc(kubelet); err != nil {
260+
t.Fatalf("%s failed preparation: %v", name, err)
261+
}
262+
}
263+
264+
exist := kubelet.podVolumesExist(poduid)
265+
if tc.expected != exist {
266+
t.Errorf("%s failed: expected %t, got %t", name, tc.expected, exist)
267+
}
268+
})
269+
}
270+
}

pkg/volume/csi/csi_mounter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ type csiMountMgr struct {
8282
var _ volume.Volume = &csiMountMgr{}
8383

8484
func (c *csiMountMgr) GetPath() string {
85-
dir := filepath.Join(getTargetPath(c.podUID, c.specVolumeID, c.plugin.host), "/mount")
85+
dir := GetCSIMounterPath(filepath.Join(getTargetPath(c.podUID, c.specVolumeID, c.plugin.host)))
8686
klog.V(4).Info(log("mounter.GetPath generated [%s]", dir))
8787
return dir
8888
}

pkg/volume/csi/csi_util.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,8 @@ func getPVSourceFromSpec(spec *volume.Spec) (*api.CSIPersistentVolumeSource, err
171171
}
172172
return pvSrc, nil
173173
}
174+
175+
// GetCSIMounterPath returns the mounter path given the base path.
176+
func GetCSIMounterPath(path string) string {
177+
return filepath.Join(path, "/mount")
178+
}

0 commit comments

Comments
 (0)