@@ -25,8 +25,11 @@ import (
25
25
"path/filepath"
26
26
"syscall"
27
27
"testing"
28
+ "time"
28
29
29
30
v1 "k8s.io/api/core/v1"
31
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
+ "k8s.io/client-go/tools/record"
30
33
utiltesting "k8s.io/client-go/util/testing"
31
34
)
32
35
@@ -286,6 +289,7 @@ func TestSetVolumeOwnershipMode(t *testing.T) {
286
289
}
287
290
288
291
defer os .RemoveAll (tmpDir )
292
+
289
293
info , err := os .Lstat (tmpDir )
290
294
if err != nil {
291
295
t .Fatalf ("error reading permission of tmpdir: %v" , err )
@@ -296,7 +300,7 @@ func TestSetVolumeOwnershipMode(t *testing.T) {
296
300
t .Fatalf ("error reading permission stats for tmpdir: %s" , tmpDir )
297
301
}
298
302
299
- var expectedGid int64 = int64 (stat .Gid )
303
+ var expectedGid = int64 (stat .Gid )
300
304
err = test .setupFunc (tmpDir )
301
305
if err != nil {
302
306
t .Errorf ("for %s error running setup with: %v" , test .description , err )
@@ -316,6 +320,130 @@ func TestSetVolumeOwnershipMode(t *testing.T) {
316
320
}
317
321
}
318
322
323
+ func TestProgressTracking (t * testing.T ) {
324
+ alwaysApplyPolicy := v1 .FSGroupChangeAlways
325
+ var expectedGID int64 = 9999
326
+ var permissionSleepDuration = 5 * time .Millisecond
327
+ // how often to report the events
328
+ progressReportDuration = 200 * time .Millisecond
329
+ firstEventReportDuration = 50 * time .Millisecond
330
+
331
+ filePermissionChangeFunc = func (filename string , fsGroup * int64 , _ bool , _ os.FileInfo ) error {
332
+ t .Logf ("Calling file permission change for %s with gid %d" , filename , * fsGroup )
333
+ time .Sleep (permissionSleepDuration )
334
+ return nil
335
+ }
336
+ pod := & v1.Pod {
337
+ ObjectMeta : metav1.ObjectMeta {
338
+ Name : "pod1" ,
339
+ UID : "pod1uid" ,
340
+ },
341
+ Spec : v1.PodSpec {
342
+ Volumes : []v1.Volume {
343
+ {
344
+ Name : "volume-name" ,
345
+ VolumeSource : v1.VolumeSource {
346
+ GCEPersistentDisk : & v1.GCEPersistentDiskVolumeSource {
347
+ PDName : "fake-device1" ,
348
+ },
349
+ },
350
+ },
351
+ },
352
+ },
353
+ }
354
+
355
+ tests := []struct {
356
+ name string
357
+ filePermissionChangeTimeDuration time.Duration
358
+ totalWaitTime time.Duration
359
+ currentPod * v1.Pod
360
+ expectedEvents []string
361
+ }{
362
+ {
363
+ name : "When permission change finishes quickly, no events should be logged" ,
364
+ filePermissionChangeTimeDuration : 30 * time .Millisecond ,
365
+ totalWaitTime : 1 * time .Second ,
366
+ currentPod : pod ,
367
+ expectedEvents : []string {},
368
+ },
369
+ {
370
+ name : "When no pod is specified, no events should be logged" ,
371
+ filePermissionChangeTimeDuration : 300 * time .Millisecond ,
372
+ totalWaitTime : 1 * time .Second ,
373
+ currentPod : nil ,
374
+ expectedEvents : []string {},
375
+ },
376
+ {
377
+ name : "When permission change takes loo long and pod is specified" ,
378
+ filePermissionChangeTimeDuration : 300 * time .Millisecond ,
379
+ totalWaitTime : 1 * time .Second ,
380
+ currentPod : pod ,
381
+ expectedEvents : []string {
382
+ "Warning VolumePermissionChangeInProgress Setting volume ownership for pod1uid/volumes/faketype is taking longer than expected, consider using OnRootMismatch - https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#configure-volume-permission-and-ownership-change-policy-for-pods" ,
383
+ "Warning VolumePermissionChangeInProgress Setting volume ownership for pod1uid/volumes/faketype, processed 1 files." ,
384
+ },
385
+ },
386
+ }
387
+
388
+ for i := range tests {
389
+ tc := tests [i ]
390
+ t .Run (tc .name , func (t * testing.T ) {
391
+ tmpDir , err := utiltesting .MkTmpdir ("volume_linux_ownership" )
392
+ if err != nil {
393
+ t .Fatalf ("error creating temp dir: %v" , err )
394
+ }
395
+ podUID := "placeholder"
396
+ if tc .currentPod != nil {
397
+ podUID = string (tc .currentPod .UID )
398
+ }
399
+ volumePath := filepath .Join (tmpDir , podUID , "volumes" , "faketype" )
400
+ err = os .MkdirAll (volumePath , 0770 )
401
+ if err != nil {
402
+ t .Fatalf ("error creating volumePath %s: %v" , volumePath , err )
403
+ }
404
+ defer func () {
405
+ err := os .RemoveAll (tmpDir )
406
+ if err != nil {
407
+ t .Fatalf ("error removing tmpDir %s: %v" , tmpDir , err )
408
+ }
409
+ }()
410
+
411
+ mounter := & localFakeMounter {path : "FAKE_DIR_DOESNT_EXIST" } // SetVolumeOwnership() must rely on tmpDir
412
+
413
+ fakeRecorder := record .NewFakeRecorder (100 )
414
+ recordedEvents := []string {}
415
+
416
+ // Set how long file permission change takes
417
+ permissionSleepDuration = tc .filePermissionChangeTimeDuration
418
+
419
+ ownershipChanger := NewVolumeOwnership (mounter , volumePath , & expectedGID , & alwaysApplyPolicy , nil )
420
+ if tc .currentPod != nil {
421
+ ownershipChanger .AddProgressNotifier (tc .currentPod , fakeRecorder )
422
+ }
423
+ err = ownershipChanger .ChangePermissions ()
424
+ if err != nil {
425
+ t .Errorf ("unexpected error: %+v" , err )
426
+ }
427
+ time .Sleep (tc .totalWaitTime )
428
+ actualEventCount := len (fakeRecorder .Events )
429
+ if len (tc .expectedEvents ) == 0 && actualEventCount != len (tc .expectedEvents ) {
430
+ t .Errorf ("expected 0 events got %d" , actualEventCount )
431
+ }
432
+
433
+ for range actualEventCount {
434
+ event := <- fakeRecorder .Events
435
+ recordedEvents = append (recordedEvents , event )
436
+ }
437
+
438
+ for i , event := range tc .expectedEvents {
439
+ if event != recordedEvents [i ] {
440
+ t .Errorf ("expected event %d to be %s, got: %s" , i , event , recordedEvents [i ])
441
+ }
442
+ }
443
+ })
444
+ }
445
+ }
446
+
319
447
// verifyDirectoryPermission checks if given path has directory permissions
320
448
// that is expected by k8s. If returns true if it does otherwise false
321
449
func verifyDirectoryPermission (path string , readonly bool ) bool {
0 commit comments