@@ -19,8 +19,11 @@ package plugin
19
19
import (
20
20
"bytes"
21
21
"context"
22
+ "errors"
23
+ "flag"
22
24
"fmt"
23
25
"reflect"
26
+ "strings"
24
27
"sync"
25
28
"testing"
26
29
"time"
@@ -35,6 +38,7 @@ import (
35
38
"k8s.io/apimachinery/pkg/types"
36
39
"k8s.io/apimachinery/pkg/util/rand"
37
40
"k8s.io/client-go/tools/cache"
41
+ "k8s.io/klog/v2"
38
42
credentialproviderapi "k8s.io/kubelet/pkg/apis/credentialprovider"
39
43
credentialproviderv1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1"
40
44
credentialproviderv1alpha1 "k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1"
@@ -188,12 +192,19 @@ func TestSingleflightProvide(t *testing.T) {
188
192
}
189
193
190
194
func Test_Provide (t * testing.T ) {
195
+ klog .InitFlags (nil )
196
+ if err := flag .Set ("v" , "6" ); err != nil {
197
+ t .Fatalf ("failed to set log level: %v" , err )
198
+ }
199
+ flag .Parse ()
200
+
191
201
tclock := clock.RealClock {}
192
202
testcases := []struct {
193
203
name string
194
204
pluginProvider * perPodPluginProvider
195
205
image string
196
206
dockerconfig credentialprovider.DockerConfig
207
+ wantLog string
197
208
}{
198
209
{
199
210
name : "exact image match, with Registry cache key" ,
@@ -357,17 +368,162 @@ func Test_Provide(t *testing.T) {
357
368
},
358
369
},
359
370
},
371
+ {
372
+ name : "[service account mode] sa name required but empty" ,
373
+ pluginProvider : & perPodPluginProvider {
374
+ provider : & pluginProvider {
375
+ matchImages : []string {"test.registry.io" },
376
+ serviceAccountProvider : & serviceAccountProvider {
377
+ requireServiceAccount : true ,
378
+ },
379
+ },
380
+ podName : "pod-name" ,
381
+ podNamespace : "ns" ,
382
+ },
383
+ image : "test.registry.io/foo/bar" ,
384
+ dockerconfig : credentialprovider.DockerConfig {},
385
+ wantLog : "Service account name is empty for pod ns/pod-name" ,
386
+ },
387
+ {
388
+ name : "[service account mode] sa does not have required annotations" ,
389
+ pluginProvider : & perPodPluginProvider {
390
+ provider : & pluginProvider {
391
+ matchImages : []string {"test.registry.io" },
392
+ serviceAccountProvider : & serviceAccountProvider {
393
+ requireServiceAccount : true ,
394
+ requiredServiceAccountAnnotationKeys : []string {
395
+ "domain.io/identity-id" ,
396
+ },
397
+ getServiceAccountFunc : func (_ , _ string ) (* v1.ServiceAccount , error ) {
398
+ return & v1.ServiceAccount {
399
+ ObjectMeta : metav1.ObjectMeta {
400
+ Name : "sa-name" ,
401
+ Namespace : "ns" ,
402
+ Annotations : map [string ]string {},
403
+ },
404
+ }, nil
405
+ },
406
+ },
407
+ },
408
+ podName : "pod-name" ,
409
+ podNamespace : "ns" ,
410
+ serviceAccountName : "sa-name" ,
411
+ },
412
+ image : "test.registry.io/foo/bar" ,
413
+ dockerconfig : credentialprovider.DockerConfig {},
414
+ wantLog : "Failed to get service account data ns/sa-name: required annotation domain.io/identity-id not found" ,
415
+ },
416
+ {
417
+ name : "[service account mode] failed to get service account token" ,
418
+ pluginProvider : & perPodPluginProvider {
419
+ provider : & pluginProvider {
420
+ matchImages : []string {"test.registry.io" },
421
+ serviceAccountProvider : & serviceAccountProvider {
422
+ requireServiceAccount : true ,
423
+ requiredServiceAccountAnnotationKeys : []string {
424
+ "domain.io/identity-id" ,
425
+ },
426
+ optionalServiceAccountAnnotationKeys : []string {
427
+ "domain.io/identity-type" ,
428
+ },
429
+ getServiceAccountFunc : func (_ , _ string ) (* v1.ServiceAccount , error ) {
430
+ return & v1.ServiceAccount {
431
+ ObjectMeta : metav1.ObjectMeta {
432
+ Name : "sa-name" ,
433
+ Namespace : "ns" ,
434
+ Annotations : map [string ]string {
435
+ "domain.io/identity-id" : "id" ,
436
+ },
437
+ },
438
+ }, nil
439
+ },
440
+ getServiceAccountTokenFunc : func (_ , _ string , tr * authenticationv1.TokenRequest ) (* authenticationv1.TokenRequest , error ) {
441
+ return nil , errors .New ("failed to get token" )
442
+ },
443
+ },
444
+ },
445
+ podName : "pod-name" ,
446
+ podNamespace : "ns" ,
447
+ serviceAccountName : "sa-name" ,
448
+ },
449
+ image : "test.registry.io/foo/bar" ,
450
+ dockerconfig : credentialprovider.DockerConfig {},
451
+ wantLog : "Error getting service account token ns/sa-name: failed to get token" ,
452
+ },
453
+ {
454
+ name : "[service account mode] exact image match" ,
455
+ pluginProvider : & perPodPluginProvider {
456
+ provider : & pluginProvider {
457
+ clock : tclock ,
458
+ lastCachePurge : tclock .Now (),
459
+ matchImages : []string {"test.registry.io" },
460
+ cache : cache .NewExpirationStore (cacheKeyFunc , & cacheExpirationPolicy {clock : tclock }),
461
+ plugin : & fakeExecPlugin {
462
+ cacheKeyType : credentialproviderapi .ImagePluginCacheKeyType ,
463
+ auth : map [string ]credentialproviderapi.AuthConfig {
464
+ "test.registry.io/foo/bar" : {
465
+ Username : "user" ,
466
+ Password : "password" ,
467
+ },
468
+ },
469
+ },
470
+ serviceAccountProvider : & serviceAccountProvider {
471
+ requireServiceAccount : true ,
472
+ requiredServiceAccountAnnotationKeys : []string {
473
+ "domain.io/identity-id" ,
474
+ },
475
+ optionalServiceAccountAnnotationKeys : []string {
476
+ "domain.io/identity-type" ,
477
+ },
478
+ getServiceAccountFunc : func (_ , _ string ) (* v1.ServiceAccount , error ) {
479
+ return & v1.ServiceAccount {
480
+ ObjectMeta : metav1.ObjectMeta {
481
+ Name : "sa-name" ,
482
+ Namespace : "ns" ,
483
+ Annotations : map [string ]string {
484
+ "domain.io/identity-id" : "id" ,
485
+ "domain.io/identity-type" : "type" ,
486
+ },
487
+ },
488
+ }, nil
489
+ },
490
+ getServiceAccountTokenFunc : func (_ , _ string , tr * authenticationv1.TokenRequest ) (* authenticationv1.TokenRequest , error ) {
491
+ return & authenticationv1.TokenRequest {Status : authenticationv1.TokenRequestStatus {Token : "token" }}, nil
492
+ },
493
+ },
494
+ },
495
+ podName : "pod-name" ,
496
+ podNamespace : "ns" ,
497
+ serviceAccountName : "sa-name" ,
498
+ },
499
+ image : "test.registry.io/foo/bar" ,
500
+ dockerconfig : credentialprovider.DockerConfig {
501
+ "test.registry.io/foo/bar" : credentialprovider.DockerConfigEntry {
502
+ Username : "user" ,
503
+ Password : "password" ,
504
+ },
505
+ },
506
+ },
360
507
}
361
508
362
509
for _ , testcase := range testcases {
363
510
testcase := testcase
364
511
t .Run (testcase .name , func (t * testing.T ) {
365
- t .Parallel ()
366
- dockerconfig := testcase .pluginProvider .Provide (testcase .image )
367
- if ! reflect .DeepEqual (dockerconfig , testcase .dockerconfig ) {
368
- t .Logf ("actual docker config: %v" , dockerconfig )
369
- t .Logf ("expected docker config: %v" , testcase .dockerconfig )
370
- t .Error ("unexpected docker config" )
512
+ var buf bytes.Buffer
513
+ klog .SetOutput (& buf )
514
+ klog .LogToStderr (false )
515
+ defer klog .LogToStderr (true )
516
+
517
+ if got := testcase .pluginProvider .Provide (testcase .image ); ! reflect .DeepEqual (got , testcase .dockerconfig ) {
518
+ t .Errorf ("unexpected docker config: %v, expected: %v" , got , testcase .dockerconfig )
519
+ }
520
+
521
+ klog .Flush ()
522
+ klog .SetOutput (& bytes.Buffer {}) // prevent further writes into buf
523
+ capturedOutput := buf .String ()
524
+
525
+ if len (testcase .wantLog ) > 0 && ! strings .Contains (capturedOutput , testcase .wantLog ) {
526
+ t .Errorf ("expected log message %q not found in captured output: %q" , testcase .wantLog , capturedOutput )
371
527
}
372
528
})
373
529
}
@@ -1568,3 +1724,30 @@ func TestGenerateCacheKey(t *testing.T) {
1568
1724
})
1569
1725
}
1570
1726
}
1727
+
1728
+ func TestRequiredAnnotationNotFoundErr (t * testing.T ) {
1729
+ tests := []struct {
1730
+ name string
1731
+ err error
1732
+ expected bool
1733
+ }{
1734
+ {
1735
+ name : "required annotation not found error" ,
1736
+ err : requiredAnnotationNotFoundError ("something" ),
1737
+ expected : true ,
1738
+ },
1739
+ {
1740
+ name : "other error" ,
1741
+ err : errors .New ("some other error" ),
1742
+ expected : false ,
1743
+ },
1744
+ }
1745
+
1746
+ for _ , test := range tests {
1747
+ t .Run (test .name , func (t * testing.T ) {
1748
+ if got := isRequiredAnnotationNotFoundError (test .err ); got != test .expected {
1749
+ t .Errorf ("expected %v, got %v" , test .expected , got )
1750
+ }
1751
+ })
1752
+ }
1753
+ }
0 commit comments