diff --git a/pkg/kubelet/volumemanager/populator/BUILD b/pkg/kubelet/volumemanager/populator/BUILD index c844e3e68a3..76a541ab7c0 100644 --- a/pkg/kubelet/volumemanager/populator/BUILD +++ b/pkg/kubelet/volumemanager/populator/BUILD @@ -5,6 +5,7 @@ licenses(["notice"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( @@ -42,3 +43,25 @@ filegroup( srcs = [":package-srcs"], tags = ["automanaged"], ) + +go_test( + name = "go_default_test", + srcs = ["desired_state_of_world_populator_test.go"], + library = ":go_default_library", + tags = ["automanaged"], + deps = [ + "//pkg/api/v1:go_default_library", + "//pkg/client/clientset_generated/clientset/fake:go_default_library", + "//pkg/kubelet/container/testing:go_default_library", + "//pkg/kubelet/pod:go_default_library", + "//pkg/kubelet/pod/testing:go_default_library", + "//pkg/kubelet/secret:go_default_library", + "//pkg/kubelet/status:go_default_library", + "//pkg/kubelet/status/testing:go_default_library", + "//pkg/kubelet/volumemanager/cache:go_default_library", + "//pkg/volume/testing:go_default_library", + "//pkg/volume/util/types:go_default_library", + "//pkg/volume/util/volumehelper:go_default_library", + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + ], +) diff --git a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go new file mode 100644 index 00000000000..66d74ed0e71 --- /dev/null +++ b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go @@ -0,0 +1,179 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package populator + +import ( + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" + containertest "k8s.io/kubernetes/pkg/kubelet/container/testing" + kubepod "k8s.io/kubernetes/pkg/kubelet/pod" + podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing" + "k8s.io/kubernetes/pkg/kubelet/secret" + "k8s.io/kubernetes/pkg/kubelet/status" + statustest "k8s.io/kubernetes/pkg/kubelet/status/testing" + "k8s.io/kubernetes/pkg/kubelet/volumemanager/cache" + volumetesting "k8s.io/kubernetes/pkg/volume/testing" + "k8s.io/kubernetes/pkg/volume/util/types" + "k8s.io/kubernetes/pkg/volume/util/volumehelper" +) + +func TestFindAndAddNewPods_FindAndRemoveDeletedPods(t *testing.T) { + fakeVolumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t) + fakeClient := &fake.Clientset{} + + fakeSecretManager := secret.NewFakeManager() + fakePodManager := kubepod.NewBasicPodManager( + podtest.NewFakeMirrorClient(), fakeSecretManager) + + fakesDSW := cache.NewDesiredStateOfWorld(fakeVolumePluginMgr) + fakeRuntime := &containertest.FakeRuntime{} + + fakeStatusManager := status.NewManager(fakeClient, fakePodManager, &statustest.FakePodDeletionSafetyProvider{}) + + dswp := &desiredStateOfWorldPopulator{ + kubeClient: fakeClient, + loopSleepDuration: 100 * time.Millisecond, + getPodStatusRetryDuration: 2 * time.Second, + podManager: fakePodManager, + podStatusProvider: fakeStatusManager, + desiredStateOfWorld: fakesDSW, + pods: processedPods{ + processedPods: make(map[types.UniquePodName]bool)}, + kubeContainerRuntime: fakeRuntime, + keepTerminatedPodVolumes: false, + } + + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dswp-test-pod", + UID: "dswp-test-pod-uid", + Namespace: "dswp-test", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "dswp-test-volume-name", + VolumeSource: v1.VolumeSource{ + GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ + PDName: "dswp-test-fake-device", + }, + }, + }, + }, + }, + Status: v1.PodStatus{ + Phase: v1.PodPhase("Running"), + }, + } + + fakePodManager.AddPod(pod) + + podName := volumehelper.GetUniquePodName(pod) + + generatedVolumeName := "fake-plugin/" + pod.Spec.Volumes[0].Name + + dswp.findAndAddNewPods() + + if !dswp.pods.processedPods[podName] { + t.Fatalf("Failed to record that the volumes for the specified pod: %s have been processed by the populator", podName) + } + + expectedVolumeName := v1.UniqueVolumeName(generatedVolumeName) + + volumeExists := fakesDSW.VolumeExists(expectedVolumeName) + if !volumeExists { + t.Fatalf( + "VolumeExists(%q) failed. Expected: Actual: <%v>", + expectedVolumeName, + volumeExists) + } + + if podExistsInVolume := fakesDSW.PodExistsInVolume( + podName, expectedVolumeName); !podExistsInVolume { + t.Fatalf( + "DSW PodExistsInVolume returned incorrect value. Expected: Actual: <%v>", + podExistsInVolume) + } + + verifyVolumeExistsInVolumesToMount( + t, v1.UniqueVolumeName(generatedVolumeName), false /* expectReportedInUse */, fakesDSW) + + //let the pod be terminated + podGet, exist := fakePodManager.GetPodByName(pod.Namespace, pod.Name) + if !exist { + t.Fatalf("Failed to get pod by pod name: %s and namespace: %s", pod.Name, pod.Namespace) + } + podGet.Status.Phase = v1.PodFailed + + //pod is added to fakePodManager but fakeRuntime can not get the pod,so here findAndRemoveDeletedPods() will remove the pod and volumes it is mounted + dswp.findAndRemoveDeletedPods() + + if dswp.pods.processedPods[podName] { + t.Fatalf("Failed to remove pods from desired state of world since they no longer exist") + } + + volumeExists = fakesDSW.VolumeExists(expectedVolumeName) + if volumeExists { + t.Fatalf( + "VolumeExists(%q) failed. Expected: Actual: <%v>", + expectedVolumeName, + volumeExists) + } + + if podExistsInVolume := fakesDSW.PodExistsInVolume( + podName, expectedVolumeName); podExistsInVolume { + t.Fatalf( + "DSW PodExistsInVolume returned incorrect value. Expected: Actual: <%v>", + podExistsInVolume) + } + + volumesToMount := fakesDSW.GetVolumesToMount() + for _, volume := range volumesToMount { + if volume.VolumeName == expectedVolumeName { + t.Fatalf( + "Found volume %v in the list of desired state of world volumes to mount. Expected not", + expectedVolumeName) + } + } + +} + +func verifyVolumeExistsInVolumesToMount(t *testing.T, expectedVolumeName v1.UniqueVolumeName, expectReportedInUse bool, dsw cache.DesiredStateOfWorld) { + volumesToMount := dsw.GetVolumesToMount() + for _, volume := range volumesToMount { + if volume.VolumeName == expectedVolumeName { + if volume.ReportedInUse != expectReportedInUse { + t.Fatalf( + "Found volume %v in the list of VolumesToMount, but ReportedInUse incorrect. Expected: <%v> Actual: <%v>", + expectedVolumeName, + expectReportedInUse, + volume.ReportedInUse) + } + + return + } + } + + t.Fatalf( + "Could not find volume %v in the list of desired state of world volumes to mount %+v", + expectedVolumeName, + volumesToMount) +}