// Calls Run() // Verifies there are no calls to attach, detach, mount, unmount, etc. func Test_Run_Positive_DoNothing(t *testing.T) { // Arrange volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) kubeClient := createTestClient() oex := operationexecutor.NewOperationExecutor(kubeClient, volumePluginMgr) reconciler := NewReconciler( kubeClient, false, /* controllerAttachDetachEnabled */ reconcilerLoopSleepDuration, reconcilerReconstructSleepPeriod, waitForAttachTimeout, nodeName, dsw, asw, oex, &mount.FakeMounter{}, volumePluginMgr, kubeletPodsDir) // Act runReconciler(reconciler) // Assert assert.NoError(t, volumetesting.VerifyZeroAttachCalls(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroWaitForAttachCallCount(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroMountDeviceCallCount(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroSetUpCallCount(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroTearDownCallCount(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin)) }
// NewVolumeManager returns a new concrete instance implementing the // VolumeManager interface. // // kubeClient - kubeClient is the kube API client used by DesiredStateOfWorldPopulator // to communicate with the API server to fetch PV and PVC objects // volumePluginMgr - the volume plugin manager used to access volume plugins. // Must be pre-initialized. func NewVolumeManager( controllerAttachDetachEnabled bool, nodeName k8stypes.NodeName, podManager pod.Manager, kubeClient clientset.Interface, volumePluginMgr *volume.VolumePluginMgr, kubeContainerRuntime kubecontainer.Runtime, mounter mount.Interface, kubeletPodsDir string, recorder record.EventRecorder, checkNodeCapabilitiesBeforeMount bool) (VolumeManager, error) { vm := &volumeManager{ kubeClient: kubeClient, volumePluginMgr: volumePluginMgr, desiredStateOfWorld: cache.NewDesiredStateOfWorld(volumePluginMgr), actualStateOfWorld: cache.NewActualStateOfWorld(nodeName, volumePluginMgr), operationExecutor: operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( kubeClient, volumePluginMgr, recorder, checkNodeCapabilitiesBeforeMount), ), } vm.reconciler = reconciler.NewReconciler( kubeClient, controllerAttachDetachEnabled, reconcilerLoopSleepPeriod, reconcilerSyncStatesSleepPeriod, waitForAttachTimeout, nodeName, vm.desiredStateOfWorld, vm.actualStateOfWorld, vm.operationExecutor, mounter, volumePluginMgr, kubeletPodsDir) vm.desiredStateOfWorldPopulator = populator.NewDesiredStateOfWorldPopulator( kubeClient, desiredStateOfWorldPopulatorLoopSleepPeriod, desiredStateOfWorldPopulatorGetPodStatusRetryDuration, podManager, vm.desiredStateOfWorld, kubeContainerRuntime) return vm, nil }
// NewVolumeManager returns a new concrete instance implementing the // VolumeManager interface. // // kubeClient - kubeClient is the kube API client used by DesiredStateOfWorldPopulator // to communicate with the API server to fetch PV and PVC objects // volumePluginMgr - the volume plugin manager used to access volume plugins. // Must be pre-initialized. func NewVolumeManager( controllerAttachDetachEnabled bool, hostName string, podManager pod.Manager, kubeClient internalclientset.Interface, volumePluginMgr *volume.VolumePluginMgr, kubeContainerRuntime kubecontainer.Runtime, mounter mount.Interface, kubeletPodsDir string, recorder record.EventRecorder) (VolumeManager, error) { vm := &volumeManager{ kubeClient: kubeClient, volumePluginMgr: volumePluginMgr, desiredStateOfWorld: cache.NewDesiredStateOfWorld(volumePluginMgr), actualStateOfWorld: cache.NewActualStateOfWorld(hostName, volumePluginMgr), operationExecutor: operationexecutor.NewOperationExecutor( kubeClient, volumePluginMgr, recorder), } vm.reconciler = reconciler.NewReconciler( kubeClient, controllerAttachDetachEnabled, reconcilerLoopSleepPeriod, reconcilerReconstructSleepPeriod, waitForAttachTimeout, hostName, vm.desiredStateOfWorld, vm.actualStateOfWorld, vm.operationExecutor, mounter, volumePluginMgr, kubeletPodsDir) vm.desiredStateOfWorldPopulator = populator.NewDesiredStateOfWorldPopulator( kubeClient, desiredStateOfWorldPopulatorLoopSleepPeriod, desiredStateOfWorldPopulatorGetPodStatusRetryDuration, podManager, vm.desiredStateOfWorld, kubeContainerRuntime) return vm, nil }
// Populates desiredStateOfWorld cache with one volume/pod. // Calls Run() // Verifies there is are attach/mount/etc calls and no detach/unmount calls. func Test_Run_Positive_VolumeAttachAndMount(t *testing.T) { // Arrange volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) kubeClient := createTestClient() oex := operationexecutor.NewOperationExecutor(kubeClient, volumePluginMgr) reconciler := NewReconciler( kubeClient, false, /* controllerAttachDetachEnabled */ reconcilerLoopSleepDuration, reconcilerReconstructSleepPeriod, waitForAttachTimeout, nodeName, dsw, asw, oex, &mount.FakeMounter{}, volumePluginMgr, kubeletPodsDir) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod1", UID: "pod1uid", }, Spec: api.PodSpec{ Volumes: []api.Volume{ { Name: "volume-name", VolumeSource: api.VolumeSource{ GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{ PDName: "fake-device1", }, }, }, }, }, } volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} podName := volumehelper.GetUniquePodName(pod) generatedVolumeName, err := dsw.AddPodToVolume( podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) // Assert if err != nil { t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) } // Act runReconciler(reconciler) waitForMount(t, fakePlugin, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyAttachCallCount( 1 /* expectedAttachCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifyWaitForAttachCallCount( 1 /* expectedWaitForAttachCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifyMountDeviceCallCount( 1 /* expectedMountDeviceCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifySetUpCallCount( 1 /* expectedSetUpCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroTearDownCallCount(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin)) }
// Populates desiredStateOfWorld cache with one volume/pod. // Enables controllerAttachDetachEnabled. // Calls Run() // Verifies one mount call is made and no unmount calls. // Deletes volume/pod from desired state of world. // Verifies one unmount call is made. // Verifies there are no attach/detach calls made. func Test_Run_Positive_VolumeUnmountControllerAttachEnabled(t *testing.T) { // Arrange volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) kubeClient := createTestClient() fakeRecorder := &record.FakeRecorder{} oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(kubeClient, volumePluginMgr, fakeRecorder, false /* checkNodeCapabilitiesBeforeMount */)) reconciler := NewReconciler( kubeClient, true, /* controllerAttachDetachEnabled */ reconcilerLoopSleepDuration, reconcilerSyncStatesSleepPeriod, waitForAttachTimeout, nodeName, dsw, asw, oex, &mount.FakeMounter{}, volumePluginMgr, kubeletPodsDir) pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "pod1", UID: "pod1uid", }, Spec: v1.PodSpec{ Volumes: []v1.Volume{ { Name: "volume-name", VolumeSource: v1.VolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName: "fake-device1", }, }, }, }, }, } volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]} podName := volumehelper.GetUniquePodName(pod) generatedVolumeName, err := dsw.AddPodToVolume( podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) // Assert if err != nil { t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err) } // Act runReconciler(reconciler) dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeName}) waitForMount(t, fakePlugin, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyZeroAttachCalls(fakePlugin)) assert.NoError(t, volumetesting.VerifyWaitForAttachCallCount( 1 /* expectedWaitForAttachCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifyMountDeviceCallCount( 1 /* expectedMountDeviceCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifySetUpCallCount( 1 /* expectedSetUpCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroTearDownCallCount(fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin)) // Act dsw.DeletePodFromVolume(podName, generatedVolumeName) waitForDetach(t, fakePlugin, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyTearDownCallCount( 1 /* expectedTearDownCallCount */, fakePlugin)) assert.NoError(t, volumetesting.VerifyZeroDetachCallCount(fakePlugin)) }