@@ -19,6 +19,8 @@ package reconciler
19
19
import (
20
20
"crypto/md5"
21
21
"fmt"
22
+ csitrans "k8s.io/csi-translation-lib"
23
+ "k8s.io/kubernetes/pkg/volume/csimigration"
22
24
"testing"
23
25
"time"
24
26
@@ -177,6 +179,105 @@ func Test_Run_Positive_VolumeAttachAndMount(t *testing.T) {
177
179
assert .NoError (t , volumetesting .VerifyZeroDetachCallCount (fakePlugin ))
178
180
}
179
181
182
+ // Populates desiredStateOfWorld cache with one volume/pod.
183
+ // Calls Run()
184
+ // Verifies there is are attach/mount/etc calls and no detach/unmount calls.
185
+ func Test_Run_Positive_VolumeAttachAndMountMigrationEnabled (t * testing.T ) {
186
+ // Arrange
187
+ intreeToCSITranslator := csitrans .New ()
188
+ node := & v1.Node {
189
+ ObjectMeta : metav1.ObjectMeta {
190
+ Name : string (nodeName ),
191
+ },
192
+ Spec : v1.NodeSpec {},
193
+ Status : v1.NodeStatus {
194
+ VolumesAttached : []v1.AttachedVolume {
195
+ {
196
+ Name : v1 .UniqueVolumeName (fmt .Sprintf ("fake-plugin/%s" , "pd.csi.storage.gke.io-fake-device1" )),
197
+ DevicePath : "fake/path" ,
198
+ },
199
+ },
200
+ },
201
+ }
202
+ volumePluginMgr , fakePlugin := volumetesting .GetTestKubeletVolumePluginMgrWithNode (t , node )
203
+ dsw := cache .NewDesiredStateOfWorld (volumePluginMgr )
204
+
205
+ asw := cache .NewActualStateOfWorld (nodeName , volumePluginMgr )
206
+ kubeClient := createTestClient (v1.AttachedVolume {
207
+ Name : v1 .UniqueVolumeName (fmt .Sprintf ("fake-plugin/%s" , "pd.csi.storage.gke.io-fake-device1" )),
208
+ DevicePath : "fake/path" ,
209
+ })
210
+
211
+ fakeRecorder := & record.FakeRecorder {}
212
+ fakeHandler := volumetesting .NewBlockVolumePathHandler ()
213
+ oex := operationexecutor .NewOperationExecutor (operationexecutor .NewOperationGenerator (
214
+ kubeClient ,
215
+ volumePluginMgr ,
216
+ fakeRecorder ,
217
+ fakeHandler ))
218
+ reconciler := NewReconciler (
219
+ kubeClient ,
220
+ true , /* controllerAttachDetachEnabled */
221
+ reconcilerLoopSleepDuration ,
222
+ waitForAttachTimeout ,
223
+ nodeName ,
224
+ dsw ,
225
+ asw ,
226
+ hasAddedPods ,
227
+ oex ,
228
+ mount .NewFakeMounter (nil ),
229
+ hostutil .NewFakeHostUtil (nil ),
230
+ volumePluginMgr ,
231
+ kubeletPodsDir )
232
+ pod := & v1.Pod {
233
+ ObjectMeta : metav1.ObjectMeta {
234
+ Name : "pod1" ,
235
+ UID : "pod1uid" ,
236
+ },
237
+ Spec : v1.PodSpec {
238
+ Volumes : []v1.Volume {
239
+ {
240
+ Name : "volume-name" ,
241
+ VolumeSource : v1.VolumeSource {
242
+ GCEPersistentDisk : & v1.GCEPersistentDiskVolumeSource {
243
+ PDName : "fake-device1" ,
244
+ },
245
+ },
246
+ },
247
+ },
248
+ },
249
+ }
250
+
251
+ volumeSpec := & volume.Spec {Volume : & pod .Spec .Volumes [0 ]}
252
+ migratedSpec , err := csimigration .TranslateInTreeSpecToCSI (volumeSpec , pod .Namespace , intreeToCSITranslator )
253
+ if err != nil {
254
+ t .Fatalf ("unexpected error while translating spec %v: %v" , volumeSpec , err )
255
+ }
256
+
257
+ podName := util .GetUniquePodName (pod )
258
+ generatedVolumeName , err := dsw .AddPodToVolume (
259
+ podName , pod , migratedSpec , migratedSpec .Name (), "" /* volumeGidValue */ )
260
+
261
+ // Assert
262
+ if err != nil {
263
+ t .Fatalf ("AddPodToVolume failed. Expected: <no error> Actual: <%v>" , err )
264
+ }
265
+ dsw .MarkVolumesReportedInUse ([]v1.UniqueVolumeName {generatedVolumeName })
266
+
267
+ // Act
268
+ runReconciler (reconciler )
269
+ waitForMount (t , fakePlugin , generatedVolumeName , asw )
270
+ // Assert
271
+ assert .NoError (t , volumetesting .VerifyWaitForAttachCallCount (
272
+ 1 /* expectedWaitForAttachCallCount */ , fakePlugin ))
273
+ assert .NoError (t , volumetesting .VerifyMountDeviceCallCount (
274
+ 1 /* expectedMountDeviceCallCount */ , fakePlugin ))
275
+ assert .NoError (t , volumetesting .VerifySetUpCallCount (
276
+ 1 /* expectedSetUpCallCount */ , fakePlugin ))
277
+ assert .NoError (t , volumetesting .VerifyZeroTearDownCallCount (fakePlugin ))
278
+ assert .NoError (t , volumetesting .VerifyZeroDetachCallCount (fakePlugin ))
279
+ }
280
+
180
281
// Populates desiredStateOfWorld cache with one volume/pod.
181
282
// Enables controllerAttachDetachEnabled.
182
283
// Calls Run()
@@ -1896,21 +1997,25 @@ func retryWithExponentialBackOff(initialDuration time.Duration, fn wait.Conditio
1896
1997
return wait .ExponentialBackoff (backoff , fn )
1897
1998
}
1898
1999
1899
- func createTestClient () * fake.Clientset {
2000
+ func createTestClient (attachedVolumes ... v1. AttachedVolume ) * fake.Clientset {
1900
2001
fakeClient := & fake.Clientset {}
2002
+ if len (attachedVolumes ) == 0 {
2003
+ attachedVolumes = append (attachedVolumes , v1.AttachedVolume {
2004
+ Name : "fake-plugin/fake-device1" ,
2005
+ DevicePath : "fake/path" ,
2006
+ })
2007
+ }
1901
2008
fakeClient .AddReactor ("get" , "nodes" ,
1902
2009
func (action core.Action ) (bool , runtime.Object , error ) {
1903
2010
return true , & v1.Node {
1904
2011
ObjectMeta : metav1.ObjectMeta {Name : string (nodeName )},
1905
2012
Status : v1.NodeStatus {
1906
- VolumesAttached : []v1.AttachedVolume {
1907
- {
1908
- Name : "fake-plugin/fake-device1" ,
1909
- DevicePath : "/fake/path" ,
1910
- },
1911
- }},
2013
+ VolumesAttached : attachedVolumes ,
2014
+ },
1912
2015
}, nil
1913
- })
2016
+ },
2017
+ )
2018
+
1914
2019
fakeClient .AddReactor ("*" , "*" , func (action core.Action ) (bool , runtime.Object , error ) {
1915
2020
return true , nil , fmt .Errorf ("no reaction implemented for %s" , action )
1916
2021
})
0 commit comments