github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/controllers/clustereventhandler_test.go (about)

     1  package controllers
     2  
     3  import (
     4  	"testing"
     5  
     6  	log "github.com/sirupsen/logrus"
     7  	"github.com/stretchr/testify/assert"
     8  	corev1 "k8s.io/api/core/v1"
     9  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    10  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/runtime"
    12  	"k8s.io/apimachinery/pkg/types"
    13  	ctrl "sigs.k8s.io/controller-runtime"
    14  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    15  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    16  
    17  	"github.com/argoproj/argo-cd/v2/applicationset/generators"
    18  	argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    19  )
    20  
    21  func TestClusterEventHandler(t *testing.T) {
    22  
    23  	scheme := runtime.NewScheme()
    24  	err := argov1alpha1.AddToScheme(scheme)
    25  	assert.Nil(t, err)
    26  
    27  	err = argov1alpha1.AddToScheme(scheme)
    28  	assert.Nil(t, err)
    29  
    30  	tests := []struct {
    31  		name             string
    32  		items            []argov1alpha1.ApplicationSet
    33  		secret           corev1.Secret
    34  		expectedRequests []ctrl.Request
    35  	}{
    36  		{
    37  			name:  "no application sets should mean no requests",
    38  			items: []argov1alpha1.ApplicationSet{},
    39  			secret: corev1.Secret{
    40  				ObjectMeta: v1.ObjectMeta{
    41  					Namespace: "argocd",
    42  					Name:      "my-secret",
    43  					Labels: map[string]string{
    44  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
    45  					},
    46  				},
    47  			},
    48  			expectedRequests: []reconcile.Request{},
    49  		},
    50  		{
    51  			name: "a cluster generator should produce a request",
    52  			items: []argov1alpha1.ApplicationSet{
    53  				{
    54  					ObjectMeta: v1.ObjectMeta{
    55  						Name:      "my-app-set",
    56  						Namespace: "argocd",
    57  					},
    58  					Spec: argov1alpha1.ApplicationSetSpec{
    59  						Generators: []argov1alpha1.ApplicationSetGenerator{
    60  							{
    61  								Clusters: &argov1alpha1.ClusterGenerator{},
    62  							},
    63  						},
    64  					},
    65  				},
    66  			},
    67  			secret: corev1.Secret{
    68  				ObjectMeta: v1.ObjectMeta{
    69  					Namespace: "argocd",
    70  					Name:      "my-secret",
    71  					Labels: map[string]string{
    72  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
    73  					},
    74  				},
    75  			},
    76  			expectedRequests: []reconcile.Request{{
    77  				NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
    78  			}},
    79  		},
    80  		{
    81  			name: "multiple cluster generators should produce multiple requests",
    82  			items: []argov1alpha1.ApplicationSet{
    83  				{
    84  					ObjectMeta: v1.ObjectMeta{
    85  						Name:      "my-app-set",
    86  						Namespace: "argocd",
    87  					},
    88  					Spec: argov1alpha1.ApplicationSetSpec{
    89  						Generators: []argov1alpha1.ApplicationSetGenerator{
    90  							{
    91  								Clusters: &argov1alpha1.ClusterGenerator{},
    92  							},
    93  						},
    94  					},
    95  				},
    96  				{
    97  					ObjectMeta: v1.ObjectMeta{
    98  						Name:      "my-app-set2",
    99  						Namespace: "argocd",
   100  					},
   101  					Spec: argov1alpha1.ApplicationSetSpec{
   102  						Generators: []argov1alpha1.ApplicationSetGenerator{
   103  							{
   104  								Clusters: &argov1alpha1.ClusterGenerator{},
   105  							},
   106  						},
   107  					},
   108  				},
   109  			},
   110  			secret: corev1.Secret{
   111  				ObjectMeta: v1.ObjectMeta{
   112  					Namespace: "argocd",
   113  					Name:      "my-secret",
   114  					Labels: map[string]string{
   115  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   116  					},
   117  				},
   118  			},
   119  			expectedRequests: []reconcile.Request{
   120  				{NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}},
   121  				{NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set2"}},
   122  			},
   123  		},
   124  		{
   125  			name: "non-cluster generator should not match",
   126  			items: []argov1alpha1.ApplicationSet{
   127  				{
   128  					ObjectMeta: v1.ObjectMeta{
   129  						Name:      "my-app-set",
   130  						Namespace: "another-namespace",
   131  					},
   132  					Spec: argov1alpha1.ApplicationSetSpec{
   133  						Generators: []argov1alpha1.ApplicationSetGenerator{
   134  							{
   135  								Clusters: &argov1alpha1.ClusterGenerator{},
   136  							},
   137  						},
   138  					},
   139  				},
   140  				{
   141  					ObjectMeta: v1.ObjectMeta{
   142  						Name:      "app-set-non-cluster",
   143  						Namespace: "argocd",
   144  					},
   145  					Spec: argov1alpha1.ApplicationSetSpec{
   146  						Generators: []argov1alpha1.ApplicationSetGenerator{
   147  							{
   148  								List: &argov1alpha1.ListGenerator{},
   149  							},
   150  						},
   151  					},
   152  				},
   153  			},
   154  			secret: corev1.Secret{
   155  				ObjectMeta: v1.ObjectMeta{
   156  					Namespace: "argocd",
   157  					Name:      "my-secret",
   158  					Labels: map[string]string{
   159  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   160  					},
   161  				},
   162  			},
   163  			expectedRequests: []reconcile.Request{
   164  				{NamespacedName: types.NamespacedName{Namespace: "another-namespace", Name: "my-app-set"}},
   165  			},
   166  		},
   167  		{
   168  			name: "non-argo cd secret should not match",
   169  			items: []argov1alpha1.ApplicationSet{
   170  				{
   171  					ObjectMeta: v1.ObjectMeta{
   172  						Name:      "my-app-set",
   173  						Namespace: "another-namespace",
   174  					},
   175  					Spec: argov1alpha1.ApplicationSetSpec{
   176  						Generators: []argov1alpha1.ApplicationSetGenerator{
   177  							{
   178  								Clusters: &argov1alpha1.ClusterGenerator{},
   179  							},
   180  						},
   181  					},
   182  				},
   183  			},
   184  			secret: corev1.Secret{
   185  				ObjectMeta: v1.ObjectMeta{
   186  					Namespace: "argocd",
   187  					Name:      "my-non-argocd-secret",
   188  				},
   189  			},
   190  			expectedRequests: []reconcile.Request{},
   191  		},
   192  		{
   193  			name: "a matrix generator with a cluster generator should produce a request",
   194  			items: []argov1alpha1.ApplicationSet{
   195  				{
   196  					ObjectMeta: v1.ObjectMeta{
   197  						Name:      "my-app-set",
   198  						Namespace: "argocd",
   199  					},
   200  					Spec: argov1alpha1.ApplicationSetSpec{
   201  						Generators: []argov1alpha1.ApplicationSetGenerator{
   202  							{
   203  								Matrix: &argov1alpha1.MatrixGenerator{
   204  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   205  										{
   206  											Clusters: &argov1alpha1.ClusterGenerator{},
   207  										},
   208  									},
   209  								},
   210  							},
   211  						},
   212  					},
   213  				},
   214  			},
   215  			secret: corev1.Secret{
   216  				ObjectMeta: v1.ObjectMeta{
   217  					Namespace: "argocd",
   218  					Name:      "my-secret",
   219  					Labels: map[string]string{
   220  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   221  					},
   222  				},
   223  			},
   224  			expectedRequests: []reconcile.Request{{
   225  				NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
   226  			}},
   227  		},
   228  		{
   229  			name: "a matrix generator with non cluster generator should not match",
   230  			items: []argov1alpha1.ApplicationSet{
   231  				{
   232  					ObjectMeta: v1.ObjectMeta{
   233  						Name:      "my-app-set",
   234  						Namespace: "argocd",
   235  					},
   236  					Spec: argov1alpha1.ApplicationSetSpec{
   237  						Generators: []argov1alpha1.ApplicationSetGenerator{
   238  							{
   239  								Matrix: &argov1alpha1.MatrixGenerator{
   240  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   241  										{
   242  											List: &argov1alpha1.ListGenerator{},
   243  										},
   244  									},
   245  								},
   246  							},
   247  						},
   248  					},
   249  				},
   250  			},
   251  			secret: corev1.Secret{
   252  				ObjectMeta: v1.ObjectMeta{
   253  					Namespace: "argocd",
   254  					Name:      "my-secret",
   255  					Labels: map[string]string{
   256  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   257  					},
   258  				},
   259  			},
   260  			expectedRequests: []reconcile.Request{},
   261  		},
   262  		{
   263  			name: "a matrix generator with a nested matrix generator containing a cluster generator should produce a request",
   264  			items: []argov1alpha1.ApplicationSet{
   265  				{
   266  					ObjectMeta: v1.ObjectMeta{
   267  						Name:      "my-app-set",
   268  						Namespace: "argocd",
   269  					},
   270  					Spec: argov1alpha1.ApplicationSetSpec{
   271  						Generators: []argov1alpha1.ApplicationSetGenerator{
   272  							{
   273  								Matrix: &argov1alpha1.MatrixGenerator{
   274  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   275  										{
   276  											Matrix: &apiextensionsv1.JSON{
   277  												Raw: []byte(
   278  													`{
   279  														"generators": [
   280  														  {
   281  															"clusters": {
   282  															  "selector": {
   283  																"matchLabels": {
   284  																  "argocd.argoproj.io/secret-type": "cluster"
   285  																}
   286  															  }
   287  															}
   288  														  }
   289  														]
   290  													  }`,
   291  												),
   292  											},
   293  										},
   294  									},
   295  								},
   296  							},
   297  						},
   298  					},
   299  				},
   300  			},
   301  			secret: corev1.Secret{
   302  				ObjectMeta: v1.ObjectMeta{
   303  					Namespace: "argocd",
   304  					Name:      "my-secret",
   305  					Labels: map[string]string{
   306  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   307  					},
   308  				},
   309  			},
   310  			expectedRequests: []reconcile.Request{{
   311  				NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
   312  			}},
   313  		},
   314  		{
   315  			name: "a matrix generator with a nested matrix generator containing non cluster generator should not match",
   316  			items: []argov1alpha1.ApplicationSet{
   317  				{
   318  					ObjectMeta: v1.ObjectMeta{
   319  						Name:      "my-app-set",
   320  						Namespace: "argocd",
   321  					},
   322  					Spec: argov1alpha1.ApplicationSetSpec{
   323  						Generators: []argov1alpha1.ApplicationSetGenerator{
   324  							{
   325  								Matrix: &argov1alpha1.MatrixGenerator{
   326  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   327  										{
   328  											Matrix: &apiextensionsv1.JSON{
   329  												Raw: []byte(
   330  													`{
   331  														"generators": [
   332  														  {
   333  															"list": {
   334  															  "elements": [
   335  																"a",
   336  																"b"
   337  															  ]
   338  															}
   339  														  }
   340  														]
   341  													  }`,
   342  												),
   343  											},
   344  										},
   345  									},
   346  								},
   347  							},
   348  						},
   349  					},
   350  				},
   351  			},
   352  			secret: corev1.Secret{
   353  				ObjectMeta: v1.ObjectMeta{
   354  					Namespace: "argocd",
   355  					Name:      "my-secret",
   356  					Labels: map[string]string{
   357  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   358  					},
   359  				},
   360  			},
   361  			expectedRequests: []reconcile.Request{},
   362  		},
   363  		{
   364  			name: "a merge generator with a cluster generator should produce a request",
   365  			items: []argov1alpha1.ApplicationSet{
   366  				{
   367  					ObjectMeta: v1.ObjectMeta{
   368  						Name:      "my-app-set",
   369  						Namespace: "argocd",
   370  					},
   371  					Spec: argov1alpha1.ApplicationSetSpec{
   372  						Generators: []argov1alpha1.ApplicationSetGenerator{
   373  							{
   374  								Merge: &argov1alpha1.MergeGenerator{
   375  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   376  										{
   377  											Clusters: &argov1alpha1.ClusterGenerator{},
   378  										},
   379  									},
   380  								},
   381  							},
   382  						},
   383  					},
   384  				},
   385  			},
   386  			secret: corev1.Secret{
   387  				ObjectMeta: v1.ObjectMeta{
   388  					Namespace: "argocd",
   389  					Name:      "my-secret",
   390  					Labels: map[string]string{
   391  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   392  					},
   393  				},
   394  			},
   395  			expectedRequests: []reconcile.Request{{
   396  				NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
   397  			}},
   398  		},
   399  		{
   400  			name: "a matrix generator with non cluster generator should not match",
   401  			items: []argov1alpha1.ApplicationSet{
   402  				{
   403  					ObjectMeta: v1.ObjectMeta{
   404  						Name:      "my-app-set",
   405  						Namespace: "argocd",
   406  					},
   407  					Spec: argov1alpha1.ApplicationSetSpec{
   408  						Generators: []argov1alpha1.ApplicationSetGenerator{
   409  							{
   410  								Merge: &argov1alpha1.MergeGenerator{
   411  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   412  										{
   413  											List: &argov1alpha1.ListGenerator{},
   414  										},
   415  									},
   416  								},
   417  							},
   418  						},
   419  					},
   420  				},
   421  			},
   422  			secret: corev1.Secret{
   423  				ObjectMeta: v1.ObjectMeta{
   424  					Namespace: "argocd",
   425  					Name:      "my-secret",
   426  					Labels: map[string]string{
   427  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   428  					},
   429  				},
   430  			},
   431  			expectedRequests: []reconcile.Request{},
   432  		},
   433  		{
   434  			name: "a merge generator with a nested merge generator containing a cluster generator should produce a request",
   435  			items: []argov1alpha1.ApplicationSet{
   436  				{
   437  					ObjectMeta: v1.ObjectMeta{
   438  						Name:      "my-app-set",
   439  						Namespace: "argocd",
   440  					},
   441  					Spec: argov1alpha1.ApplicationSetSpec{
   442  						Generators: []argov1alpha1.ApplicationSetGenerator{
   443  							{
   444  								Merge: &argov1alpha1.MergeGenerator{
   445  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   446  										{
   447  											Merge: &apiextensionsv1.JSON{
   448  												Raw: []byte(
   449  													`{
   450  														"generators": [
   451  														  {
   452  															"clusters": {
   453  															  "selector": {
   454  																"matchLabels": {
   455  																  "argocd.argoproj.io/secret-type": "cluster"
   456  																}
   457  															  }
   458  															}
   459  														  }
   460  														]
   461  													  }`,
   462  												),
   463  											},
   464  										},
   465  									},
   466  								},
   467  							},
   468  						},
   469  					},
   470  				},
   471  			},
   472  			secret: corev1.Secret{
   473  				ObjectMeta: v1.ObjectMeta{
   474  					Namespace: "argocd",
   475  					Name:      "my-secret",
   476  					Labels: map[string]string{
   477  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   478  					},
   479  				},
   480  			},
   481  			expectedRequests: []reconcile.Request{{
   482  				NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"},
   483  			}},
   484  		},
   485  		{
   486  			name: "a merge generator with a nested merge generator containing non cluster generator should not match",
   487  			items: []argov1alpha1.ApplicationSet{
   488  				{
   489  					ObjectMeta: v1.ObjectMeta{
   490  						Name:      "my-app-set",
   491  						Namespace: "argocd",
   492  					},
   493  					Spec: argov1alpha1.ApplicationSetSpec{
   494  						Generators: []argov1alpha1.ApplicationSetGenerator{
   495  							{
   496  								Merge: &argov1alpha1.MergeGenerator{
   497  									Generators: []argov1alpha1.ApplicationSetNestedGenerator{
   498  										{
   499  											Merge: &apiextensionsv1.JSON{
   500  												Raw: []byte(
   501  													`{
   502  														"generators": [
   503  														  {
   504  															"list": {
   505  															  "elements": [
   506  																"a",
   507  																"b"
   508  															  ]
   509  															}
   510  														  }
   511  														]
   512  													  }`,
   513  												),
   514  											},
   515  										},
   516  									},
   517  								},
   518  							},
   519  						},
   520  					},
   521  				},
   522  			},
   523  			secret: corev1.Secret{
   524  				ObjectMeta: v1.ObjectMeta{
   525  					Namespace: "argocd",
   526  					Name:      "my-secret",
   527  					Labels: map[string]string{
   528  						generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster,
   529  					},
   530  				},
   531  			},
   532  			expectedRequests: []reconcile.Request{},
   533  		},
   534  	}
   535  
   536  	for _, test := range tests {
   537  
   538  		t.Run(test.name, func(t *testing.T) {
   539  
   540  			appSetList := argov1alpha1.ApplicationSetList{
   541  				Items: test.items,
   542  			}
   543  
   544  			fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(&appSetList).Build()
   545  
   546  			handler := &clusterSecretEventHandler{
   547  				Client: fakeClient,
   548  				Log:    log.WithField("type", "createSecretEventHandler"),
   549  			}
   550  
   551  			mockAddRateLimitingInterface := mockAddRateLimitingInterface{}
   552  
   553  			handler.queueRelatedAppGenerators(&mockAddRateLimitingInterface, &test.secret)
   554  
   555  			assert.False(t, mockAddRateLimitingInterface.errorOccurred)
   556  			assert.ElementsMatch(t, mockAddRateLimitingInterface.addedItems, test.expectedRequests)
   557  
   558  		})
   559  	}
   560  
   561  }
   562  
   563  // Add checks the type, and adds it to the internal list of received additions
   564  func (obj *mockAddRateLimitingInterface) Add(item interface{}) {
   565  	if req, ok := item.(ctrl.Request); ok {
   566  		obj.addedItems = append(obj.addedItems, req)
   567  	} else {
   568  		obj.errorOccurred = true
   569  	}
   570  }
   571  
   572  type mockAddRateLimitingInterface struct {
   573  	errorOccurred bool
   574  	addedItems    []ctrl.Request
   575  }
   576  
   577  func TestNestedGeneratorHasClusterGenerator_NestedClusterGenerator(t *testing.T) {
   578  	nested := argov1alpha1.ApplicationSetNestedGenerator{
   579  		Clusters: &argov1alpha1.ClusterGenerator{},
   580  	}
   581  
   582  	hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested)
   583  
   584  	assert.Nil(t, err)
   585  	assert.True(t, hasClusterGenerator)
   586  }
   587  
   588  func TestNestedGeneratorHasClusterGenerator_NestedMergeGenerator(t *testing.T) {
   589  	nested := argov1alpha1.ApplicationSetNestedGenerator{
   590  		Merge: &apiextensionsv1.JSON{
   591  			Raw: []byte(
   592  				`{
   593  					"generators": [
   594  					  {
   595  						"clusters": {
   596  						  "selector": {
   597  							"matchLabels": {
   598  							  "argocd.argoproj.io/secret-type": "cluster"
   599  							}
   600  						  }
   601  						}
   602  					  }
   603  					]
   604  				  }`,
   605  			),
   606  		},
   607  	}
   608  
   609  	hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested)
   610  
   611  	assert.Nil(t, err)
   612  	assert.True(t, hasClusterGenerator)
   613  }
   614  
   615  func TestNestedGeneratorHasClusterGenerator_NestedMergeGeneratorWithInvalidJSON(t *testing.T) {
   616  	nested := argov1alpha1.ApplicationSetNestedGenerator{
   617  		Merge: &apiextensionsv1.JSON{
   618  			Raw: []byte(
   619  				`{
   620  					"generators": [
   621  					  {
   622  						"clusters": {
   623  						  "selector": {
   624  							"matchLabels": {
   625  							  "argocd.argoproj.io/secret-type": "cluster"
   626  							}
   627  						  }
   628  						}
   629  					  }
   630  					]
   631  				  `,
   632  			),
   633  		},
   634  	}
   635  
   636  	hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested)
   637  
   638  	assert.NotNil(t, err)
   639  	assert.False(t, hasClusterGenerator)
   640  }