Skip to content

Commit 7cb5df6

Browse files
committed
Fix race condition between actual and desired state in kublet volume
manager This PR fixes the issue kubernetes#75345. This fix modified the checking volume in actual state when validating whether volume can be removed from desired state or not. Only if volume status is already mounted in actual state, it can be removed from desired state. For the case of mounting fails always, it can still work because the check also validate whether pod still exist in pod manager. In case of mount fails, pod should be able to removed from pod manager so that volume can also be removed from desired state.
1 parent a4f2590 commit 7cb5df6

File tree

2 files changed

+119
-4
lines changed

2 files changed

+119
-4
lines changed

pkg/kubelet/volumemanager/populator/desired_state_of_world_populator.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,15 @@ func (dswp *desiredStateOfWorldPopulator) findAndRemoveDeletedPods() {
253253

254254
if runningContainers {
255255
klog.V(4).Infof(
256-
"Pod %q has been removed from pod manager. However, it still has one or more containers in the non-exited state. Therefore, it will not be removed from volume manager.",
256+
"Pod %q still has one or more containers in the non-exited state. Therefore, it will not be removed from desired state.",
257257
format.Pod(volumeToMount.Pod))
258258
continue
259259
}
260-
261-
if !dswp.actualStateOfWorld.VolumeExists(volumeToMount.VolumeName) && podExists {
262-
klog.V(4).Infof(volumeToMount.GenerateMsgDetailed("Actual state has not yet has this information skip removing volume from desired state", ""))
260+
exists, _, _ := dswp.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName)
261+
if !exists && podExists {
262+
klog.V(4).Infof(
263+
volumeToMount.GenerateMsgDetailed(fmt.Sprintf("Actual state has not yet has this volume mounted information and pod (%q) still exists in pod manager, skip removing volume from desired state",
264+
format.Pod(volumeToMount.Pod)), ""))
263265
continue
264266
}
265267
klog.V(4).Infof(volumeToMount.GenerateMsgDetailed("Removing volume from desired state", ""))

pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,119 @@ func TestFindAndAddNewPods_FindAndRemoveDeletedPods(t *testing.T) {
152152

153153
}
154154

155+
func TestFindAndRemoveDeletedPodsWithActualState(t *testing.T) {
156+
// create dswp
157+
mode := v1.PersistentVolumeFilesystem
158+
pv := &v1.PersistentVolume{
159+
ObjectMeta: metav1.ObjectMeta{
160+
Name: "dswp-test-volume-name",
161+
},
162+
Spec: v1.PersistentVolumeSpec{
163+
ClaimRef: &v1.ObjectReference{Namespace: "ns", Name: "file-bound"},
164+
VolumeMode: &mode,
165+
},
166+
}
167+
pvc := &v1.PersistentVolumeClaim{
168+
Spec: v1.PersistentVolumeClaimSpec{
169+
VolumeName: "dswp-test-volume-name",
170+
},
171+
Status: v1.PersistentVolumeClaimStatus{
172+
Phase: v1.ClaimBound,
173+
},
174+
}
175+
dswp, fakePodManager, fakesDSW := createDswpWithVolume(t, pv, pvc)
176+
177+
// create pod
178+
containers := []v1.Container{
179+
{
180+
VolumeMounts: []v1.VolumeMount{
181+
{
182+
Name: "dswp-test-volume-name",
183+
MountPath: "/mnt",
184+
},
185+
},
186+
},
187+
}
188+
pod := createPodWithVolume("dswp-test-pod", "dswp-test-volume-name", "file-bound", containers)
189+
190+
fakePodManager.AddPod(pod)
191+
192+
podName := util.GetUniquePodName(pod)
193+
194+
generatedVolumeName := "fake-plugin/" + pod.Spec.Volumes[0].Name
195+
196+
dswp.findAndAddNewPods()
197+
198+
if !dswp.pods.processedPods[podName] {
199+
t.Fatalf("Failed to record that the volumes for the specified pod: %s have been processed by the populator", podName)
200+
}
201+
202+
expectedVolumeName := v1.UniqueVolumeName(generatedVolumeName)
203+
204+
volumeExists := fakesDSW.VolumeExists(expectedVolumeName)
205+
if !volumeExists {
206+
t.Fatalf(
207+
"VolumeExists(%q) failed. Expected: <true> Actual: <%v>",
208+
expectedVolumeName,
209+
volumeExists)
210+
}
211+
212+
if podExistsInVolume := fakesDSW.PodExistsInVolume(
213+
podName, expectedVolumeName); !podExistsInVolume {
214+
t.Fatalf(
215+
"DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>",
216+
podExistsInVolume)
217+
}
218+
219+
verifyVolumeExistsInVolumesToMount(
220+
t, v1.UniqueVolumeName(generatedVolumeName), false /* expectReportedInUse */, fakesDSW)
221+
222+
//let the pod be terminated
223+
podGet, exist := fakePodManager.GetPodByName(pod.Namespace, pod.Name)
224+
if !exist {
225+
t.Fatalf("Failed to get pod by pod name: %s and namespace: %s", pod.Name, pod.Namespace)
226+
}
227+
podGet.Status.Phase = v1.PodFailed
228+
229+
dswp.findAndRemoveDeletedPods()
230+
// Although Pod status is terminated, pod still exists in pod manager and actual state does not has this pod and volume information
231+
// desired state populator will fail to delete this pod and volume first
232+
volumeExists = fakesDSW.VolumeExists(expectedVolumeName)
233+
if !volumeExists {
234+
t.Fatalf(
235+
"VolumeExists(%q) failed. Expected: <true> Actual: <%v>",
236+
expectedVolumeName,
237+
volumeExists)
238+
}
239+
240+
if podExistsInVolume := fakesDSW.PodExistsInVolume(
241+
podName, expectedVolumeName); !podExistsInVolume {
242+
t.Fatalf(
243+
"DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>",
244+
podExistsInVolume)
245+
}
246+
247+
// reconcile with actual state so that volume is added into the actual state
248+
// desired state populator now can successfully delete the pod and volume
249+
fakeASW := dswp.actualStateOfWorld
250+
reconcileASW(fakeASW, fakesDSW, t)
251+
dswp.findAndRemoveDeletedPods()
252+
volumeExists = fakesDSW.VolumeExists(expectedVolumeName)
253+
if volumeExists {
254+
t.Fatalf(
255+
"VolumeExists(%q) failed. Expected: <false> Actual: <%v>",
256+
expectedVolumeName,
257+
volumeExists)
258+
}
259+
260+
if podExistsInVolume := fakesDSW.PodExistsInVolume(
261+
podName, expectedVolumeName); podExistsInVolume {
262+
t.Fatalf(
263+
"DSW PodExistsInVolume returned incorrect value. Expected: <false> Actual: <%v>",
264+
podExistsInVolume)
265+
}
266+
}
267+
155268
func TestFindAndAddNewPods_FindAndRemoveDeletedPods_Valid_Block_VolumeDevices(t *testing.T) {
156269
// Enable BlockVolume feature gate
157270
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, true)()

0 commit comments

Comments
 (0)