github.com/argoproj/argo-cd/v3@v3.2.1/util/db/cluster_test.go (about)

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  	"google.golang.org/grpc/codes"
    11  	"google.golang.org/grpc/status"
    12  	corev1 "k8s.io/api/core/v1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/client-go/kubernetes/fake"
    15  
    16  	"github.com/argoproj/argo-cd/v3/common"
    17  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    18  	"github.com/argoproj/argo-cd/v3/util/settings"
    19  )
    20  
    21  const (
    22  	fakeNamespace = "fake-ns"
    23  )
    24  
    25  func Test_URIToSecretName(t *testing.T) {
    26  	name, err := URIToSecretName("cluster", "http://foo")
    27  	require.NoError(t, err)
    28  	assert.Equal(t, "cluster-foo-752281925", name)
    29  
    30  	name, err = URIToSecretName("cluster", "http://thelongestdomainnameintheworld.argocd-project.com:3000")
    31  	require.NoError(t, err)
    32  	assert.Equal(t, "cluster-thelongestdomainnameintheworld.argocd-project.com-2721640553", name)
    33  
    34  	name, err = URIToSecretName("cluster", "http://[fe80::1ff:fe23:4567:890a]")
    35  	require.NoError(t, err)
    36  	assert.Equal(t, "cluster-fe80--1ff-fe23-4567-890a-3877258831", name)
    37  
    38  	name, err = URIToSecretName("cluster", "http://[fe80::1ff:fe23:4567:890a]:8000")
    39  	require.NoError(t, err)
    40  	assert.Equal(t, "cluster-fe80--1ff-fe23-4567-890a-664858999", name)
    41  
    42  	name, err = URIToSecretName("cluster", "http://[FE80::1FF:FE23:4567:890A]:8000")
    43  	require.NoError(t, err)
    44  	assert.Equal(t, "cluster-fe80--1ff-fe23-4567-890a-682802007", name)
    45  
    46  	name, err = URIToSecretName("cluster", "http://:/abc")
    47  	require.NoError(t, err)
    48  	assert.Equal(t, "cluster--1969338796", name)
    49  }
    50  
    51  func Test_secretToCluster(t *testing.T) {
    52  	labels := map[string]string{"key1": "val1"}
    53  	annotations := map[string]string{"key2": "val2"}
    54  	secret := &corev1.Secret{
    55  		ObjectMeta: metav1.ObjectMeta{
    56  			Name:        "mycluster",
    57  			Namespace:   fakeNamespace,
    58  			Labels:      labels,
    59  			Annotations: annotations,
    60  		},
    61  		Data: map[string][]byte{
    62  			"name":   []byte("test"),
    63  			"server": []byte("http://mycluster"),
    64  			"config": []byte("{\"username\":\"foo\"}"),
    65  		},
    66  	}
    67  	cluster, err := SecretToCluster(secret)
    68  	require.NoError(t, err)
    69  	assert.Equal(t, v1alpha1.Cluster{
    70  		Name:   "test",
    71  		Server: "http://mycluster",
    72  		Config: v1alpha1.ClusterConfig{
    73  			Username: "foo",
    74  		},
    75  		Labels:      labels,
    76  		Annotations: annotations,
    77  	}, *cluster)
    78  }
    79  
    80  func Test_secretToCluster_LastAppliedConfigurationDropped(t *testing.T) {
    81  	secret := &corev1.Secret{
    82  		ObjectMeta: metav1.ObjectMeta{
    83  			Name:        "mycluster",
    84  			Namespace:   fakeNamespace,
    85  			Annotations: map[string]string{corev1.LastAppliedConfigAnnotation: "val2"},
    86  		},
    87  		Data: map[string][]byte{
    88  			"name":   []byte("test"),
    89  			"server": []byte("http://mycluster"),
    90  			"config": []byte("{\"username\":\"foo\"}"),
    91  		},
    92  	}
    93  	cluster, err := SecretToCluster(secret)
    94  	require.NoError(t, err)
    95  	assert.Empty(t, cluster.Annotations)
    96  }
    97  
    98  func TestClusterToSecret(t *testing.T) {
    99  	cluster := &v1alpha1.Cluster{
   100  		Server:      "server",
   101  		Labels:      map[string]string{"test": "label"},
   102  		Annotations: map[string]string{"test": "annotation"},
   103  		Name:        "test",
   104  		Config:      v1alpha1.ClusterConfig{},
   105  		Project:     "project",
   106  		Namespaces:  []string{"default"},
   107  	}
   108  	s := &corev1.Secret{}
   109  	err := clusterToSecret(cluster, s)
   110  	require.NoError(t, err)
   111  
   112  	assert.Equal(t, []byte(cluster.Server), s.Data["server"])
   113  	assert.Equal(t, []byte(cluster.Name), s.Data["name"])
   114  	assert.Equal(t, []byte(cluster.Project), s.Data["project"])
   115  	assert.Equal(t, []byte("default"), s.Data["namespaces"])
   116  	assert.Equal(t, cluster.Annotations, s.Annotations)
   117  	assert.Equal(t, cluster.Labels, s.Labels)
   118  }
   119  
   120  func TestClusterToSecret_LastAppliedConfigurationRejected(t *testing.T) {
   121  	cluster := &v1alpha1.Cluster{
   122  		Server:      "server",
   123  		Annotations: map[string]string{corev1.LastAppliedConfigAnnotation: "val2"},
   124  		Name:        "test",
   125  		Config:      v1alpha1.ClusterConfig{},
   126  		Project:     "project",
   127  		Namespaces:  []string{"default"},
   128  	}
   129  	s := &corev1.Secret{}
   130  	err := clusterToSecret(cluster, s)
   131  	require.Error(t, err)
   132  	require.Equal(t, codes.InvalidArgument, status.Code(err))
   133  }
   134  
   135  func Test_secretToCluster_NoConfig(t *testing.T) {
   136  	secret := &corev1.Secret{
   137  		ObjectMeta: metav1.ObjectMeta{
   138  			Name:      "mycluster",
   139  			Namespace: fakeNamespace,
   140  		},
   141  		Data: map[string][]byte{
   142  			"name":   []byte("test"),
   143  			"server": []byte("http://mycluster"),
   144  		},
   145  	}
   146  	cluster, err := SecretToCluster(secret)
   147  	require.NoError(t, err)
   148  	assert.Equal(t, v1alpha1.Cluster{
   149  		Name:        "test",
   150  		Server:      "http://mycluster",
   151  		Labels:      map[string]string{},
   152  		Annotations: map[string]string{},
   153  	}, *cluster)
   154  }
   155  
   156  func Test_secretToCluster_InvalidConfig(t *testing.T) {
   157  	secret := &corev1.Secret{
   158  		ObjectMeta: metav1.ObjectMeta{
   159  			Name:      "mycluster",
   160  			Namespace: fakeNamespace,
   161  		},
   162  		Data: map[string][]byte{
   163  			"name":   []byte("test"),
   164  			"server": []byte("http://mycluster"),
   165  			"config": []byte("{'tlsClientConfig':{'insecure':false}}"),
   166  		},
   167  	}
   168  	cluster, err := SecretToCluster(secret)
   169  	require.Error(t, err)
   170  	assert.Nil(t, cluster)
   171  }
   172  
   173  func TestUpdateCluster(t *testing.T) {
   174  	kubeclientset := fake.NewClientset(&corev1.Secret{
   175  		ObjectMeta: metav1.ObjectMeta{
   176  			Name:      "mycluster",
   177  			Namespace: fakeNamespace,
   178  			Labels: map[string]string{
   179  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   180  			},
   181  		},
   182  		Data: map[string][]byte{
   183  			"server": []byte("http://mycluster"),
   184  			"config": []byte("{}"),
   185  		},
   186  	})
   187  	settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   188  	db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   189  	requestedAt := metav1.Now()
   190  	_, err := db.UpdateCluster(t.Context(), &v1alpha1.Cluster{
   191  		Name:               "test",
   192  		Server:             "http://mycluster",
   193  		RefreshRequestedAt: &requestedAt,
   194  	})
   195  	require.NoError(t, err)
   196  
   197  	secret, err := kubeclientset.CoreV1().Secrets(fakeNamespace).Get(t.Context(), "mycluster", metav1.GetOptions{})
   198  	require.NoError(t, err)
   199  
   200  	assert.Equal(t, secret.Annotations[v1alpha1.AnnotationKeyRefresh], requestedAt.Format(time.RFC3339))
   201  }
   202  
   203  func TestDeleteUnknownCluster(t *testing.T) {
   204  	kubeclientset := fake.NewClientset(&corev1.Secret{
   205  		ObjectMeta: metav1.ObjectMeta{
   206  			Name:      "mycluster",
   207  			Namespace: fakeNamespace,
   208  			Labels: map[string]string{
   209  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   210  			},
   211  		},
   212  		Data: map[string][]byte{
   213  			"server": []byte("http://mycluster"),
   214  			"name":   []byte("mycluster"),
   215  		},
   216  	})
   217  	settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   218  	db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   219  	assert.EqualError(t, db.DeleteCluster(t.Context(), "http://unknown"), `rpc error: code = NotFound desc = cluster "http://unknown" not found`)
   220  }
   221  
   222  func TestRejectCreationForInClusterWhenDisabled(t *testing.T) {
   223  	argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{
   224  		ObjectMeta: metav1.ObjectMeta{
   225  			Name:      common.ArgoCDConfigMapName,
   226  			Namespace: fakeNamespace,
   227  			Labels: map[string]string{
   228  				"app.kubernetes.io/part-of": "argocd",
   229  			},
   230  		},
   231  		Data: map[string]string{"cluster.inClusterEnabled": "false"},
   232  	}
   233  	argoCDSecret := &corev1.Secret{
   234  		ObjectMeta: metav1.ObjectMeta{
   235  			Name:      common.ArgoCDSecretName,
   236  			Namespace: fakeNamespace,
   237  			Labels: map[string]string{
   238  				"app.kubernetes.io/part-of": "argocd",
   239  			},
   240  		},
   241  		Data: map[string][]byte{
   242  			"admin.password":   nil,
   243  			"server.secretkey": nil,
   244  		},
   245  	}
   246  	kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret)
   247  	settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   248  	db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   249  	_, err := db.CreateCluster(t.Context(), &v1alpha1.Cluster{
   250  		Server: v1alpha1.KubernetesInternalAPIServerAddr,
   251  		Name:   "incluster-name",
   252  	})
   253  	require.Error(t, err)
   254  }
   255  
   256  func runWatchTest(t *testing.T, db ArgoDB, actions []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster)) (completed bool) {
   257  	t.Helper()
   258  	ctx, cancel := context.WithCancel(t.Context())
   259  	defer cancel()
   260  
   261  	timeout := time.Second * 5
   262  
   263  	allDone := make(chan bool, 1)
   264  
   265  	doNext := func(old *v1alpha1.Cluster, new *v1alpha1.Cluster) {
   266  		if len(actions) == 0 {
   267  			assert.Fail(t, "Unexpected event")
   268  		}
   269  		next := actions[0]
   270  		next(old, new)
   271  		if t.Failed() {
   272  			allDone <- true
   273  		}
   274  		if len(actions) == 1 {
   275  			allDone <- true
   276  		} else {
   277  			actions = actions[1:]
   278  		}
   279  	}
   280  
   281  	go func() {
   282  		assert.NoError(t, db.WatchClusters(ctx, func(cluster *v1alpha1.Cluster) {
   283  			doNext(nil, cluster)
   284  		}, func(oldCluster *v1alpha1.Cluster, newCluster *v1alpha1.Cluster) {
   285  			doNext(oldCluster, newCluster)
   286  		}, func(clusterServer string) {
   287  			doNext(&v1alpha1.Cluster{Server: clusterServer}, nil)
   288  		}))
   289  	}()
   290  
   291  	select {
   292  	case <-allDone:
   293  		return true
   294  	case <-time.After(timeout):
   295  		return false
   296  	}
   297  }
   298  
   299  func TestGetCluster(t *testing.T) {
   300  	emptyArgoCDConfigMap := &corev1.ConfigMap{
   301  		ObjectMeta: metav1.ObjectMeta{
   302  			Name:      common.ArgoCDConfigMapName,
   303  			Namespace: fakeNamespace,
   304  			Labels: map[string]string{
   305  				"app.kubernetes.io/part-of": "argocd",
   306  			},
   307  		},
   308  		Data: map[string]string{},
   309  	}
   310  	argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{
   311  		ObjectMeta: metav1.ObjectMeta{
   312  			Name:      common.ArgoCDConfigMapName,
   313  			Namespace: fakeNamespace,
   314  			Labels: map[string]string{
   315  				"app.kubernetes.io/part-of": "argocd",
   316  			},
   317  		},
   318  		Data: map[string]string{"cluster.inClusterEnabled": "false"},
   319  	}
   320  	argoCDSecret := &corev1.Secret{
   321  		ObjectMeta: metav1.ObjectMeta{
   322  			Name:      common.ArgoCDSecretName,
   323  			Namespace: fakeNamespace,
   324  			Labels: map[string]string{
   325  				"app.kubernetes.io/part-of": "argocd",
   326  			},
   327  		},
   328  		Data: map[string][]byte{
   329  			"admin.password":   nil,
   330  			"server.secretkey": nil,
   331  		},
   332  	}
   333  	secretForServerWithInClusterAddr := &corev1.Secret{
   334  		ObjectMeta: metav1.ObjectMeta{
   335  			Name:      "mycluster1",
   336  			Namespace: fakeNamespace,
   337  			Labels: map[string]string{
   338  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   339  			},
   340  		},
   341  		Data: map[string][]byte{
   342  			"server": []byte(v1alpha1.KubernetesInternalAPIServerAddr),
   343  			"name":   []byte("in-cluster-renamed"),
   344  		},
   345  	}
   346  
   347  	secretForServerWithExternalClusterAddr := &corev1.Secret{
   348  		ObjectMeta: metav1.ObjectMeta{
   349  			Name:      "mycluster2",
   350  			Namespace: fakeNamespace,
   351  			Labels: map[string]string{
   352  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   353  			},
   354  		},
   355  		Data: map[string][]byte{
   356  			"server": []byte("http://mycluster2"),
   357  			"name":   []byte("mycluster2"),
   358  		},
   359  	}
   360  
   361  	t.Run("Valid external cluster", func(t *testing.T) {
   362  		kubeclientset := fake.NewClientset(secretForServerWithExternalClusterAddr, emptyArgoCDConfigMap, argoCDSecret)
   363  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   364  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   365  
   366  		cluster, err := db.GetCluster(t.Context(), string(secretForServerWithExternalClusterAddr.Data["server"]))
   367  		require.NoError(t, err)
   368  		assert.Equal(t, string(secretForServerWithExternalClusterAddr.Data["server"]), cluster.Server)
   369  		assert.Equal(t, string(secretForServerWithExternalClusterAddr.Data["name"]), cluster.Name)
   370  	})
   371  
   372  	t.Run("invalid cluster", func(t *testing.T) {
   373  		kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret)
   374  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   375  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   376  
   377  		_, err := db.GetCluster(t.Context(), "https://mycluster-does-not-exist")
   378  		require.Error(t, err)
   379  		status, ok := status.FromError(err)
   380  		assert.True(t, ok)
   381  		assert.Equal(t, codes.NotFound, status.Code())
   382  	})
   383  
   384  	t.Run("in-cluster not configured", func(t *testing.T) {
   385  		kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret)
   386  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   387  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   388  
   389  		cluster, err := db.GetCluster(t.Context(), v1alpha1.KubernetesInternalAPIServerAddr)
   390  		require.NoError(t, err)
   391  		assert.Equal(t, v1alpha1.KubernetesInternalAPIServerAddr, cluster.Server)
   392  		assert.Equal(t, "in-cluster", cluster.Name)
   393  	})
   394  
   395  	t.Run("in-cluster disabled", func(t *testing.T) {
   396  		kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret)
   397  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   398  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   399  
   400  		_, err := db.GetCluster(t.Context(), v1alpha1.KubernetesInternalAPIServerAddr)
   401  		require.Error(t, err)
   402  		status, ok := status.FromError(err)
   403  		assert.True(t, ok)
   404  		assert.Equal(t, codes.NotFound, status.Code())
   405  	})
   406  
   407  	t.Run("in-cluster configured", func(t *testing.T) {
   408  		kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, emptyArgoCDConfigMap, argoCDSecret)
   409  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   410  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   411  
   412  		cluster, err := db.GetCluster(t.Context(), v1alpha1.KubernetesInternalAPIServerAddr)
   413  		require.NoError(t, err)
   414  		assert.Equal(t, v1alpha1.KubernetesInternalAPIServerAddr, cluster.Server)
   415  		assert.Equal(t, "in-cluster-renamed", cluster.Name)
   416  	})
   417  
   418  	t.Run("in-cluster configured and disabled", func(t *testing.T) {
   419  		kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret)
   420  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   421  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   422  
   423  		_, err := db.GetCluster(t.Context(), v1alpha1.KubernetesInternalAPIServerAddr)
   424  		require.Error(t, err)
   425  		status, ok := status.FromError(err)
   426  		assert.True(t, ok)
   427  		assert.Equal(t, codes.NotFound, status.Code())
   428  	})
   429  }
   430  
   431  func TestListClusters(t *testing.T) {
   432  	emptyArgoCDConfigMap := &corev1.ConfigMap{
   433  		ObjectMeta: metav1.ObjectMeta{
   434  			Name:      common.ArgoCDConfigMapName,
   435  			Namespace: fakeNamespace,
   436  			Labels: map[string]string{
   437  				"app.kubernetes.io/part-of": "argocd",
   438  			},
   439  		},
   440  		Data: map[string]string{},
   441  	}
   442  	argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{
   443  		ObjectMeta: metav1.ObjectMeta{
   444  			Name:      common.ArgoCDConfigMapName,
   445  			Namespace: fakeNamespace,
   446  			Labels: map[string]string{
   447  				"app.kubernetes.io/part-of": "argocd",
   448  			},
   449  		},
   450  		Data: map[string]string{"cluster.inClusterEnabled": "false"},
   451  	}
   452  	argoCDSecret := &corev1.Secret{
   453  		ObjectMeta: metav1.ObjectMeta{
   454  			Name:      common.ArgoCDSecretName,
   455  			Namespace: fakeNamespace,
   456  			Labels: map[string]string{
   457  				"app.kubernetes.io/part-of": "argocd",
   458  			},
   459  		},
   460  		Data: map[string][]byte{
   461  			"admin.password":   nil,
   462  			"server.secretkey": nil,
   463  		},
   464  	}
   465  	secretForServerWithInClusterAddr := &corev1.Secret{
   466  		ObjectMeta: metav1.ObjectMeta{
   467  			Name:      "mycluster1",
   468  			Namespace: fakeNamespace,
   469  			Labels: map[string]string{
   470  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   471  			},
   472  		},
   473  		Data: map[string][]byte{
   474  			"server": []byte(v1alpha1.KubernetesInternalAPIServerAddr),
   475  			"name":   []byte("in-cluster"),
   476  		},
   477  	}
   478  
   479  	secretForServerWithExternalClusterAddr := &corev1.Secret{
   480  		ObjectMeta: metav1.ObjectMeta{
   481  			Name:      "mycluster2",
   482  			Namespace: fakeNamespace,
   483  			Labels: map[string]string{
   484  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   485  			},
   486  		},
   487  		Data: map[string][]byte{
   488  			"server": []byte("http://mycluster2"),
   489  			"name":   []byte("mycluster2"),
   490  		},
   491  	}
   492  
   493  	invalidSecret := &corev1.Secret{
   494  		ObjectMeta: metav1.ObjectMeta{
   495  			Name:      "mycluster3",
   496  			Namespace: fakeNamespace,
   497  		},
   498  		Data: map[string][]byte{
   499  			"name":   []byte("test"),
   500  			"server": []byte("http://mycluster3"),
   501  			"config": []byte("{'tlsClientConfig':{'insecure':false}}"),
   502  		},
   503  	}
   504  
   505  	t.Run("Valid clusters", func(t *testing.T) {
   506  		kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, secretForServerWithExternalClusterAddr, emptyArgoCDConfigMap, argoCDSecret)
   507  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   508  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   509  
   510  		clusters, err := db.ListClusters(t.Context())
   511  		require.NoError(t, err)
   512  		assert.Len(t, clusters.Items, 2)
   513  	})
   514  
   515  	t.Run("Cluster list with invalid cluster", func(t *testing.T) {
   516  		kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, secretForServerWithExternalClusterAddr, invalidSecret, emptyArgoCDConfigMap, argoCDSecret)
   517  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   518  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   519  
   520  		clusters, err := db.ListClusters(t.Context())
   521  		require.NoError(t, err)
   522  		assert.Len(t, clusters.Items, 2)
   523  	})
   524  
   525  	t.Run("Implicit in-cluster secret", func(t *testing.T) {
   526  		kubeclientset := fake.NewClientset(secretForServerWithExternalClusterAddr, emptyArgoCDConfigMap, argoCDSecret)
   527  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   528  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   529  
   530  		clusters, err := db.ListClusters(t.Context())
   531  		require.NoError(t, err)
   532  		// ListClusters() should have added an implicit in-cluster secret to the list
   533  		assert.Len(t, clusters.Items, 2)
   534  	})
   535  
   536  	t.Run("ListClusters() should not add the cluster with in-cluster server address since in-cluster is disabled", func(t *testing.T) {
   537  		kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret)
   538  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   539  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   540  
   541  		clusters, err := db.ListClusters(t.Context())
   542  		require.NoError(t, err)
   543  		assert.Empty(t, clusters.Items)
   544  	})
   545  
   546  	t.Run("ListClusters() should add this cluster since it does not contain in-cluster server address even though in-cluster is disabled", func(t *testing.T) {
   547  		kubeclientset := fake.NewClientset(secretForServerWithExternalClusterAddr, argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret)
   548  		settingsManager := settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace)
   549  		db := NewDB(fakeNamespace, settingsManager, kubeclientset)
   550  
   551  		clusters, err := db.ListClusters(t.Context())
   552  		require.NoError(t, err)
   553  		assert.Len(t, clusters.Items, 1)
   554  	})
   555  }
   556  
   557  func TestGetClusterServersByName(t *testing.T) {
   558  	emptyArgoCDConfigMap := &corev1.ConfigMap{
   559  		ObjectMeta: metav1.ObjectMeta{
   560  			Name:      common.ArgoCDConfigMapName,
   561  			Namespace: fakeNamespace,
   562  			Labels: map[string]string{
   563  				"app.kubernetes.io/part-of": "argocd",
   564  			},
   565  		},
   566  		Data: map[string]string{},
   567  	}
   568  	argoCDSecret := &corev1.Secret{
   569  		ObjectMeta: metav1.ObjectMeta{
   570  			Name:      common.ArgoCDSecretName,
   571  			Namespace: fakeNamespace,
   572  			Labels: map[string]string{
   573  				"app.kubernetes.io/part-of": "argocd",
   574  			},
   575  		},
   576  		Data: map[string][]byte{
   577  			"admin.password":   nil,
   578  			"server.secretkey": nil,
   579  		},
   580  	}
   581  	argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{
   582  		ObjectMeta: metav1.ObjectMeta{
   583  			Name:      common.ArgoCDConfigMapName,
   584  			Namespace: fakeNamespace,
   585  			Labels: map[string]string{
   586  				"app.kubernetes.io/part-of": "argocd",
   587  			},
   588  		},
   589  		Data: map[string]string{"cluster.inClusterEnabled": "false"},
   590  	}
   591  	argoCDSecretInClusterConfigured := &corev1.Secret{
   592  		ObjectMeta: metav1.ObjectMeta{
   593  			Name:      "my-cluster-secret",
   594  			Namespace: fakeNamespace,
   595  			Labels: map[string]string{
   596  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   597  			},
   598  			Annotations: map[string]string{
   599  				common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD,
   600  			},
   601  		},
   602  		Data: map[string][]byte{
   603  			"name":   []byte("in-cluster-renamed"),
   604  			"server": []byte(v1alpha1.KubernetesInternalAPIServerAddr),
   605  			"config": []byte("{}"),
   606  		},
   607  	}
   608  
   609  	t.Run("returns the server name", func(t *testing.T) {
   610  		argoCDClusterSecret := &corev1.Secret{
   611  			ObjectMeta: metav1.ObjectMeta{
   612  				Name:      "my-cluster-secret",
   613  				Namespace: fakeNamespace,
   614  				Labels: map[string]string{
   615  					common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   616  				},
   617  				Annotations: map[string]string{
   618  					common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD,
   619  				},
   620  			},
   621  			Data: map[string][]byte{
   622  				"name":   []byte("my-cluster-name"),
   623  				"server": []byte("https://my-cluster-server"),
   624  				"config": []byte("{}"),
   625  			},
   626  		}
   627  
   628  		kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDClusterSecret, argoCDSecret)
   629  		db := NewDB(fakeNamespace, settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace), kubeclientset)
   630  		servers, err := db.GetClusterServersByName(t.Context(), "my-cluster-name")
   631  		require.NoError(t, err)
   632  		assert.ElementsMatch(t, []string{"https://my-cluster-server"}, servers)
   633  	})
   634  	t.Run("returns in-cluster", func(t *testing.T) {
   635  		kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret)
   636  		db := NewDB(fakeNamespace, settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace), kubeclientset)
   637  		servers, err := db.GetClusterServersByName(t.Context(), "in-cluster")
   638  		require.NoError(t, err)
   639  		assert.ElementsMatch(t, []string{v1alpha1.KubernetesInternalAPIServerAddr}, servers)
   640  	})
   641  	t.Run("does not return in-cluster when disabled", func(t *testing.T) {
   642  		kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret)
   643  		db := NewDB(fakeNamespace, settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace), kubeclientset)
   644  		servers, err := db.GetClusterServersByName(t.Context(), "in-cluster")
   645  		require.NoError(t, err)
   646  		assert.Empty(t, servers)
   647  	})
   648  	t.Run("returns in-cluster when configured", func(t *testing.T) {
   649  		kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecretInClusterConfigured, argoCDSecret)
   650  		db := NewDB(fakeNamespace, settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace), kubeclientset)
   651  		servers, err := db.GetClusterServersByName(t.Context(), "in-cluster-renamed")
   652  		require.NoError(t, err)
   653  		assert.ElementsMatch(t, []string{v1alpha1.KubernetesInternalAPIServerAddr}, servers)
   654  	})
   655  	t.Run("does not return in-cluster when configured and disabled", func(t *testing.T) {
   656  		kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecretInClusterConfigured, argoCDSecret)
   657  		db := NewDB(fakeNamespace, settings.NewSettingsManager(t.Context(), kubeclientset, fakeNamespace), kubeclientset)
   658  		servers, err := db.GetClusterServersByName(t.Context(), "in-cluster-renamed")
   659  		require.NoError(t, err)
   660  		assert.Empty(t, servers)
   661  	})
   662  }
   663  
   664  // TestClusterRaceConditionClusterSecrets reproduces a race condition
   665  // on the cluster secrets. The test isn't asserting anything because
   666  // before the fix it would cause a panic from concurrent map iteration and map write
   667  func TestClusterRaceConditionClusterSecrets(t *testing.T) {
   668  	clusterSecret := &corev1.Secret{
   669  		ObjectMeta: metav1.ObjectMeta{
   670  			Name:      "mycluster",
   671  			Namespace: "default",
   672  			Labels: map[string]string{
   673  				common.LabelKeySecretType: common.LabelValueSecretTypeCluster,
   674  			},
   675  		},
   676  		Data: map[string][]byte{
   677  			"server": []byte("http://mycluster"),
   678  			"config": []byte("{}"),
   679  		},
   680  	}
   681  	kubeClient := fake.NewClientset(
   682  		&corev1.ConfigMap{
   683  			ObjectMeta: metav1.ObjectMeta{
   684  				Name:      common.ArgoCDConfigMapName,
   685  				Namespace: "default",
   686  				Labels: map[string]string{
   687  					"app.kubernetes.io/part-of": "argocd",
   688  				},
   689  			},
   690  			Data: map[string]string{},
   691  		},
   692  		&corev1.Secret{
   693  			ObjectMeta: metav1.ObjectMeta{
   694  				Name:      common.ArgoCDSecretName,
   695  				Namespace: "default",
   696  				Labels: map[string]string{
   697  					"app.kubernetes.io/part-of": "argocd",
   698  				},
   699  			},
   700  			Data: map[string][]byte{
   701  				"admin.password":   nil,
   702  				"server.secretkey": nil,
   703  			},
   704  		},
   705  		clusterSecret,
   706  	)
   707  	ctx := t.Context()
   708  	settingsManager := settings.NewSettingsManager(ctx, kubeClient, "default")
   709  	db := NewDB("default", settingsManager, kubeClient)
   710  	cluster, _ := SecretToCluster(clusterSecret)
   711  	go func() {
   712  		for {
   713  			// create a copy so we dont act on the same argo cluster
   714  			clusterCopy := cluster.DeepCopy()
   715  			_, _ = db.UpdateCluster(ctx, clusterCopy)
   716  		}
   717  	}()
   718  	// yes, we will take 15 seconds to run this test
   719  	// but it reliably triggered the race condition
   720  	for i := 0; i < 30; i++ {
   721  		// create a copy so we dont act on the same argo cluster
   722  		clusterCopy := cluster.DeepCopy()
   723  		_, _ = db.UpdateCluster(ctx, clusterCopy)
   724  		time.Sleep(time.Millisecond * 500)
   725  	}
   726  }