...

Source file src/github.com/linkerd/linkerd2/controller/api/destination/watcher/cluster_store_test.go

Documentation: github.com/linkerd/linkerd2/controller/api/destination/watcher

     1  package watcher
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/linkerd/linkerd2/controller/k8s"
     8  )
     9  
    10  func TestClusterStoreHandlers(t *testing.T) {
    11  	for _, tt := range []struct {
    12  		name                 string
    13  		k8sConfigs           []string
    14  		enableEndpointSlices bool
    15  		expectedClusters     map[string]clusterConfig
    16  		deleteClusters       map[string]struct{}
    17  	}{
    18  		{
    19  			name: "add and remove remote watcher when Secret is valid",
    20  			k8sConfigs: []string{
    21  				validRemoteSecret,
    22  			},
    23  			enableEndpointSlices: true,
    24  			expectedClusters: map[string]clusterConfig{
    25  				"remote": {
    26  					TrustDomain:   "identity.org",
    27  					ClusterDomain: "cluster.local",
    28  				},
    29  			},
    30  			deleteClusters: map[string]struct{}{
    31  				"remote": {},
    32  			},
    33  		},
    34  		{
    35  			name: "add and remove more than one watcher when Secrets are valid",
    36  			k8sConfigs: []string{
    37  				validRemoteSecret,
    38  				validTargetSecret,
    39  			},
    40  			enableEndpointSlices: false,
    41  			expectedClusters: map[string]clusterConfig{
    42  				"remote": {
    43  					TrustDomain:   "identity.org",
    44  					ClusterDomain: "cluster.local",
    45  				},
    46  				"target": {
    47  					TrustDomain:   "cluster.target.local",
    48  					ClusterDomain: "cluster.target.local",
    49  				},
    50  			},
    51  			deleteClusters: map[string]struct{}{
    52  				"remote": {},
    53  			},
    54  		},
    55  		{
    56  			name: "malformed secrets shouldn't result in created watchers",
    57  			k8sConfigs: []string{
    58  				validRemoteSecret,
    59  				noClusterSecret,
    60  				noDomainSecret,
    61  				noIdentitySecret,
    62  				invalidTypeSecret,
    63  			},
    64  			enableEndpointSlices: true,
    65  			expectedClusters: map[string]clusterConfig{
    66  				"remote": {
    67  					TrustDomain:   "identity.org",
    68  					ClusterDomain: "cluster.local",
    69  				},
    70  			},
    71  			deleteClusters: map[string]struct{}{
    72  				"remote": {},
    73  			},
    74  		},
    75  	} {
    76  		tt := tt // Pin
    77  		t.Run(tt.name, func(t *testing.T) {
    78  			k8sAPI, err := k8s.NewFakeAPI(tt.k8sConfigs...)
    79  			if err != nil {
    80  				t.Fatalf("NewFakeAPI returned an error: %s", err)
    81  			}
    82  
    83  			cs, err := NewClusterStoreWithDecoder(k8sAPI.Client, "linkerd", tt.enableEndpointSlices, CreateMockDecoder())
    84  			if err != nil {
    85  				t.Fatalf("Unexpected error when starting watcher cache: %s", err)
    86  			}
    87  
    88  			cs.Sync(nil)
    89  
    90  			// Wait for the update to be processed because there is no blocking call currently in k8s that we can wait on
    91  			time.Sleep(50 * time.Millisecond)
    92  
    93  			cs.RLock()
    94  			actualLen := len(cs.store)
    95  			cs.RUnlock()
    96  
    97  			if actualLen != len(tt.expectedClusters) {
    98  				t.Fatalf("Unexpected error: expected to see %d cache entries, got: %d", len(tt.expectedClusters), actualLen)
    99  			}
   100  
   101  			for k, expected := range tt.expectedClusters {
   102  				_, cfg, found := cs.Get(k)
   103  				if !found {
   104  					t.Fatalf("Unexpected error: cluster %s is missing from the cache", k)
   105  				}
   106  
   107  				if cfg.ClusterDomain != expected.ClusterDomain {
   108  					t.Fatalf("Unexpected error: expected cluster domain %s for cluster '%s', got: %s", expected.ClusterDomain, k, cfg.ClusterDomain)
   109  				}
   110  
   111  				if cfg.TrustDomain != expected.TrustDomain {
   112  					t.Fatalf("Unexpected error: expected cluster domain %s for cluster '%s', got: %s", expected.TrustDomain, k, cfg.TrustDomain)
   113  				}
   114  			}
   115  
   116  			// Handle delete events
   117  			for k := range tt.deleteClusters {
   118  				watcher, _, found := cs.Get(k)
   119  				if !found {
   120  					t.Fatalf("Unexpected error: watcher %s should exist in the cache", k)
   121  				}
   122  				// Unfortunately, mock k8s client does not propagate
   123  				// deletes, so we have to call remove directly.
   124  				cs.removeCluster(k)
   125  				// Leave it to do its thing and gracefully shutdown
   126  				time.Sleep(50 * time.Millisecond)
   127  				var hasStopped bool
   128  				if tt.enableEndpointSlices {
   129  					hasStopped = watcher.k8sAPI.ES().Informer().IsStopped()
   130  				} else {
   131  					hasStopped = watcher.k8sAPI.Endpoint().Informer().IsStopped()
   132  				}
   133  				if !hasStopped {
   134  					t.Fatalf("Unexpected error: informers for watcher %s should be stopped", k)
   135  				}
   136  
   137  				if _, _, found := cs.Get(k); found {
   138  					t.Fatalf("Unexpected error: watcher %s should have been removed from the cache", k)
   139  				}
   140  
   141  			}
   142  
   143  			cs.UnregisterGauges()
   144  		})
   145  	}
   146  }
   147  
   148  var validRemoteSecret = `
   149  apiVersion: v1
   150  kind: Secret
   151  type: mirror.linkerd.io/remote-kubeconfig
   152  metadata:
   153    namespace: linkerd
   154    name: remote-cluster-credentials
   155    labels:
   156      multicluster.linkerd.io/cluster-name: remote
   157    annotations:
   158      multicluster.linkerd.io/trust-domain: identity.org
   159      multicluster.linkerd.io/cluster-domain: cluster.local
   160  data:
   161    kubeconfig: dmVyeSB0b3Agc2VjcmV0IGluZm9ybWF0aW9uIGhlcmUK
   162  `
   163  
   164  var validTargetSecret = `
   165  apiversion: v1
   166  kind: Secret
   167  type: mirror.linkerd.io/remote-kubeconfig
   168  metadata:
   169    namespace: linkerd
   170    name: target-cluster-credentials
   171    labels:
   172      multicluster.linkerd.io/cluster-name: target
   173    annotations:
   174      multicluster.linkerd.io/trust-domain: cluster.target.local
   175      multicluster.linkerd.io/cluster-domain: cluster.target.local
   176  data:
   177    kubeconfig: dmvyesb0b3agc2vjcmv0igluzm9ybwf0aw9uighlcmuk
   178  `
   179  
   180  var noDomainSecret = `
   181  apiVersion: v1
   182  kind: Secret
   183  type: mirror.linkerd.io/remote-kubeconfig
   184  metadata:
   185    namespace: linkerd
   186    name: target-1-cluster-credentials
   187    labels:
   188      multicluster.linkerd.io/cluster-name: target-1
   189    annotations:
   190      multicluster.linkerd.io/trust-domain: cluster.local
   191  data:
   192    kubeconfig: dmVyeSB0b3Agc2VjcmV0IGluZm9ybWF0aW9uIGhlcmUK
   193  `
   194  
   195  var noClusterSecret = `
   196  apiVersion: v1
   197  kind: Secret
   198  type: mirror.linkerd.io/remote-kubeconfig
   199  metadata:
   200    namespace: linkerd
   201    name: target-2-cluster-credentials
   202    annotations:
   203      multicluster.linkerd.io/trust-domain: cluster.local
   204      multicluster.linkerd.io/cluster-domain: cluster.local
   205  data:
   206    kubeconfig: dmVyeSB0b3Agc2VjcmV0IGluZm9ybWF0aW9uIGhlcmUK
   207  `
   208  
   209  var noIdentitySecret = `
   210  apiversion: v1
   211  kind: Secret
   212  type: mirror.linkerd.io/remote-kubeconfig
   213  metadata:
   214    namespace: linkerd
   215    name: target-3-cluster-credentials
   216    labels:
   217      multicluster.linkerd.io/cluster-name: target-3
   218    annotations:
   219      multicluster.linkerd.io/cluster-domain: cluster.local
   220  data:
   221    kubeconfig: dmvyesb0b3agc2vjcmv0igluzm9ybwf0aw9uighlcmuk
   222  `
   223  var invalidTypeSecret = `
   224  apiversion: v1
   225  kind: Secret
   226  type: kubernetes.io/tls
   227  metadata:
   228    namespace: linkerd
   229    name: target-cluster-credentials
   230    labels:
   231      multicluster.linkerd.io/cluster-name: target
   232    annotations:
   233      multicluster.linkerd.io/trust-domain: cluster.local
   234      multicluster.linkerd.io/cluster-domain: cluster.local
   235  data:
   236    kubeconfig: dmvyesb0b3agc2vjcmv0igluzm9ybwf0aw9uighlcmuk
   237  `
   238  

View as plain text