diff --git a/applicationset/controllers/applicationset_controller_test.go b/applicationset/controllers/applicationset_controller_test.go index 5d33dad908..e79672c7a1 100644 --- a/applicationset/controllers/applicationset_controller_test.go +++ b/applicationset/controllers/applicationset_controller_test.go @@ -41,6 +41,39 @@ import ( "github.com/argoproj/argo-cd/v3/util/settings" ) +// getDefaultTestClientSet creates a Clientset with the default argo objects +// and objects specified in parameters +func getDefaultTestClientSet(obj ...runtime.Object) *kubefake.Clientset { + argoCDSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: argocommon.ArgoCDSecretName, + Namespace: "argocd", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string][]byte{ + "admin.password": nil, + "server.secretkey": nil, + }, + } + + emptyArgoCDConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: argocommon.ArgoCDConfigMapName, + Namespace: "argocd", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{}, + } + + objects := append(obj, emptyArgoCDConfigMap, argoCDSecret) + kubeclientset := kubefake.NewClientset(objects...) + return kubeclientset +} + func TestCreateOrUpdateInCluster(t *testing.T) { scheme := runtime.NewScheme() err := v1alpha1.AddToScheme(scheme) @@ -1317,8 +1350,7 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) { }, } - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) + kubeclientset := getDefaultTestClientSet(secret) metrics := appsetmetrics.NewFakeAppsetMetrics() argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset) @@ -2054,8 +2086,7 @@ func TestValidateGeneratedApplications(t *testing.T) { }, } - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) + kubeclientset := getDefaultTestClientSet(secret) argodb := db.NewDB("argocd", settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd"), kubeclientset) @@ -2117,7 +2148,7 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) { }, } - kubeclientset := kubefake.NewSimpleClientset() + kubeclientset := getDefaultTestClientSet() client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &project).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() metrics := appsetmetrics.NewFakeAppsetMetrics() @@ -2404,8 +2435,7 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp }, } - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) + kubeclientset := getDefaultTestClientSet(secret) client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() metrics := appsetmetrics.NewFakeAppsetMetrics() @@ -2580,8 +2610,7 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp }, } - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) + kubeclientset := getDefaultTestClientSet(secret) client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet, &defaultProject).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() metrics := appsetmetrics.NewFakeAppsetMetrics() @@ -2700,7 +2729,7 @@ func TestPolicies(t *testing.T) { Spec: v1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://kubernetes.default.svc"}}}, } - kubeclientset := kubefake.NewSimpleClientset() + kubeclientset := getDefaultTestClientSet() for _, c := range []struct { name string diff --git a/cmd/argocd/commands/admin/app_test.go b/cmd/argocd/commands/admin/app_test.go index 8d1f4d09c1..672a67a053 100644 --- a/cmd/argocd/commands/admin/app_test.go +++ b/cmd/argocd/commands/admin/app_test.go @@ -16,6 +16,7 @@ import ( kubefake "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/cache" + "github.com/argoproj/argo-cd/v3/common" statecache "github.com/argoproj/argo-cd/v3/controller/cache" cachemocks "github.com/argoproj/argo-cd/v3/controller/cache/mocks" "github.com/argoproj/argo-cd/v3/controller/metrics" @@ -57,15 +58,28 @@ func TestGetReconcileResults(t *testing.T) { func TestGetReconcileResults_Refresh(t *testing.T) { ctx := context.Background() - cm := corev1.ConfigMap{ + argoCM := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: "argocd-cm", + Name: common.ArgoCDConfigMapName, Namespace: "default", Labels: map[string]string{ "app.kubernetes.io/part-of": "argocd", }, }, } + argoCDSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDSecretName, + Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string][]byte{ + "admin.password": nil, + "server.secretkey": nil, + }, + } proj := &v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{ Name: "default", @@ -91,7 +105,7 @@ func TestGetReconcileResults_Refresh(t *testing.T) { appClientset := appfake.NewSimpleClientset(app, proj) deployment := test.NewDeployment() - kubeClientset := kubefake.NewClientset(deployment, &cm) + kubeClientset := kubefake.NewClientset(deployment, argoCM, argoCDSecret) clusterCache := clustermocks.ClusterCache{} clusterCache.On("IsNamespaced", mock.Anything).Return(true, nil) clusterCache.On("GetGVKParser", mock.Anything).Return(nil) diff --git a/docs/operator-manual/upgrading/2.14-3.0.md b/docs/operator-manual/upgrading/2.14-3.0.md index 987625f08a..0c37722842 100644 --- a/docs/operator-manual/upgrading/2.14-3.0.md +++ b/docs/operator-manual/upgrading/2.14-3.0.md @@ -22,3 +22,16 @@ The v2 behavior can be preserved by setting the config value `server.rbac.disabl to `false` in the Argo CD ConfigMap `argocd-cm`. Read the [RBAC documentation](../rbac.md#fine-grained-permissions-for-updatedelete-action) for more detailed inforamtion. + +## Other changes + +### Using `cluster.inClusterEnabled: "false"` + +When `cluster.inClusterEnabled: "false"` is explicitly configured, Applications currently configured to +sync on the in-cluster cluster will now be in an Unknown state, without the possibility to sync resources. + +It will not be possible to create new Applications using the in-cluster cluster. When deleting existing +Application, it will not delete the previously managed resources. + +It is recommended to perform any cleanup or migration to existing in-cluster Application before upgrading +when in-cluster is disabled. To perform cleanup post-migration, the in-cluster will need to be enabled temporarily. diff --git a/test/e2e/app_management_test.go b/test/e2e/app_management_test.go index e4ea9929b4..c6b753d916 100644 --- a/test/e2e/app_management_test.go +++ b/test/e2e/app_management_test.go @@ -732,6 +732,28 @@ func TestComparisonFailsIfDestinationClusterIsInvalid(t *testing.T) { Expect(Condition(ApplicationConditionInvalidSpecError, "there are no clusters with this name")) } +func TestComparisonFailsIfInClusterDisabled(t *testing.T) { + Given(t). + Path(guestbookPath). + DestServer(KubernetesInternalAPIServerAddr). + When(). + CreateApp(). + Refresh(RefreshTypeNormal). + Sync(). + Then(). + Expect(Success("")). + Expect(HealthIs(health.HealthStatusHealthy)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + When(). + SetParamInSettingConfigMap("cluster.inClusterEnabled", "false"). + Refresh(RefreshTypeNormal). + Then(). + Expect(Success("")). + Expect(HealthIs(health.HealthStatusUnknown)). + Expect(SyncStatusIs(SyncStatusCodeUnknown)). + Expect(Condition(ApplicationConditionInvalidSpecError, fmt.Sprintf("cluster %q is disabled", KubernetesInternalAPIServerAddr))) +} + func TestCannotSetInvalidPath(t *testing.T) { Given(t). Path(guestbookPath). @@ -2189,6 +2211,19 @@ func TestCreateAppWithNoNameSpaceWhenRequired2(t *testing.T) { }) } +func TestCreateAppWithInClusterDisabled(t *testing.T) { + Given(t). + Path(guestbookPath). + DestServer(KubernetesInternalAPIServerAddr). + When(). + SetParamInSettingConfigMap("cluster.inClusterEnabled", "false"). + IgnoreErrors(). + CreateApp(). + Then(). + // RPC error messages are quoted: time="2024-12-18T04:13:58Z" level=fatal msg="" + Expect(Error("", fmt.Sprintf(`cluster \"%s\" is disabled`, KubernetesInternalAPIServerAddr))) +} + func TestListResource(t *testing.T) { fixture.SkipOnEnv(t, "OPENSHIFT") Given(t). diff --git a/test/e2e/fixture/app/expectation.go b/test/e2e/fixture/app/expectation.go index 22a5aaa475..6f37e25c3f 100644 --- a/test/e2e/fixture/app/expectation.go +++ b/test/e2e/fixture/app/expectation.go @@ -370,7 +370,7 @@ func Error(message, err string, matchers ...func(string, string) bool) Expectati return failed, fmt.Sprintf("output does not contain '%s'", message) } if !match(c.actions.lastError.Error(), err) { - return failed, fmt.Sprintf("error does not contain '%s'", message) + return failed, fmt.Sprintf("error does not contain '%s'", err) } return succeeded, fmt.Sprintf("error '%s'", message) } diff --git a/util/db/cluster.go b/util/db/cluster.go index 318120a58d..a0259d98ac 100644 --- a/util/db/cluster.go +++ b/util/db/cluster.go @@ -142,11 +142,19 @@ func (db *db) WatchClusters(ctx context.Context, handleModEvent func(oldCluster *appv1.Cluster, newCluster *appv1.Cluster), handleDeleteEvent func(clusterServer string), ) error { - localCls, err := db.GetCluster(ctx, appv1.KubernetesInternalAPIServerAddr) + argoSettings, err := db.settingsMgr.GetSettings() if err != nil { return err } - handleAddEvent(localCls) + + localCls := db.getLocalCluster() + if argoSettings.InClusterEnabled { + localCls, err = db.GetCluster(ctx, appv1.KubernetesInternalAPIServerAddr) + if err != nil { + return fmt.Errorf("could not get local cluster: %w", err) + } + handleAddEvent(localCls) + } db.watchSecrets( ctx, @@ -159,9 +167,11 @@ func (db *db) WatchClusters(ctx context.Context, return } if cluster.Server == appv1.KubernetesInternalAPIServerAddr { - // change local cluster event to modified or deleted, since it cannot be re-added or deleted - handleModEvent(localCls, cluster) - localCls = cluster + if argoSettings.InClusterEnabled { + // change local cluster event to modified, since it cannot be added at runtime + handleModEvent(localCls, cluster) + localCls = cluster + } return } handleAddEvent(cluster) @@ -185,10 +195,11 @@ func (db *db) WatchClusters(ctx context.Context, }, func(secret *corev1.Secret) { - if string(secret.Data["server"]) == appv1.KubernetesInternalAPIServerAddr { - // change local cluster event to modified or deleted, since it cannot be re-added or deleted - handleModEvent(localCls, db.getLocalCluster()) - localCls = db.getLocalCluster() + if string(secret.Data["server"]) == appv1.KubernetesInternalAPIServerAddr && argoSettings.InClusterEnabled { + // change local cluster event to modified, since it cannot be deleted at runtime, unless disabled. + newLocalCls := db.getLocalCluster() + handleModEvent(localCls, newLocalCls) + localCls = newLocalCls } else { handleDeleteEvent(string(secret.Data["server"])) } @@ -214,6 +225,14 @@ func (db *db) getClusterSecret(server string) (*corev1.Secret, error) { // GetCluster returns a cluster from a query func (db *db) GetCluster(_ context.Context, server string) (*appv1.Cluster, error) { + argoSettings, err := db.settingsMgr.GetSettings() + if err != nil { + return nil, err + } + if server == appv1.KubernetesInternalAPIServerAddr && !argoSettings.InClusterEnabled { + return nil, status.Errorf(codes.NotFound, "cluster %q is disabled", server) + } + informer, err := db.settingsMgr.GetSecretsInformer() if err != nil { return nil, err @@ -222,6 +241,7 @@ func (db *db) GetCluster(_ context.Context, server string) (*appv1.Cluster, erro if err != nil { return nil, err } + if len(res) > 0 { return SecretToCluster(res[0].(*corev1.Secret)) } @@ -254,6 +274,10 @@ func (db *db) GetProjectClusters(_ context.Context, project string) ([]*appv1.Cl } func (db *db) GetClusterServersByName(_ context.Context, name string) ([]string, error) { + argoSettings, err := db.settingsMgr.GetSettings() + if err != nil { + return nil, err + } informer, err := db.settingsMgr.GetSecretsInformer() if err != nil { return nil, err @@ -265,7 +289,7 @@ func (db *db) GetClusterServersByName(_ context.Context, name string) ([]string, return nil, err } - if len(localClusterSecrets) == 0 && db.getLocalCluster().Name == name { + if len(localClusterSecrets) == 0 && db.getLocalCluster().Name == name && argoSettings.InClusterEnabled { return []string{appv1.KubernetesInternalAPIServerAddr}, nil } @@ -276,7 +300,11 @@ func (db *db) GetClusterServersByName(_ context.Context, name string) ([]string, var res []string for i := range secrets { s := secrets[i].(*corev1.Secret) - res = append(res, strings.TrimRight(string(s.Data["server"]), "/")) + server := strings.TrimRight(string(s.Data["server"]), "/") + if !argoSettings.InClusterEnabled && server == appv1.KubernetesInternalAPIServerAddr { + continue + } + res = append(res, server) } return res, nil } diff --git a/util/db/cluster_norace_test.go b/util/db/cluster_norace_test.go index 042175921e..14cccf3d39 100644 --- a/util/db/cluster_norace_test.go +++ b/util/db/cluster_norace_test.go @@ -49,7 +49,7 @@ func TestWatchClusters_CreateRemoveCluster(t *testing.T) { kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret) settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) db := NewDB(fakeNamespace, settingsManager, kubeclientset) - runWatchTest(t, db, []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster){ + completed := runWatchTest(t, db, []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster){ func(old *v1alpha1.Cluster, new *v1alpha1.Cluster) { assert.Nil(t, old) assert.Equal(t, v1alpha1.KubernetesInternalAPIServerAddr, new.Server) @@ -72,6 +72,7 @@ func TestWatchClusters_CreateRemoveCluster(t *testing.T) { assert.Equal(t, "https://minikube", old.Server) }, }) + assert.True(t, completed, "Failed due to timeout") } func TestWatchClusters_LocalClusterModifications(t *testing.T) { @@ -104,7 +105,7 @@ func TestWatchClusters_LocalClusterModifications(t *testing.T) { kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret) settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) db := NewDB(fakeNamespace, settingsManager, kubeclientset) - runWatchTest(t, db, []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster){ + completed := runWatchTest(t, db, []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster){ func(old *v1alpha1.Cluster, new *v1alpha1.Cluster) { assert.Nil(t, old) assert.Equal(t, v1alpha1.KubernetesInternalAPIServerAddr, new.Server) @@ -127,4 +128,43 @@ func TestWatchClusters_LocalClusterModifications(t *testing.T) { assert.Equal(t, "in-cluster", new.Name) }, }) + assert.True(t, completed, "Failed due to timeout") +} + +func TestWatchClusters_LocalClusterModificationsWhenDisabled(t *testing.T) { + // !race: + // Intermittent failure when running TestWatchClusters_LocalClusterModifications with -race, likely due to race condition + // https://github.com/argoproj/argo-cd/issues/4755 + argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDConfigMapName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{"cluster.inClusterEnabled": "false"}, + } + argoCDSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDSecretName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string][]byte{ + "admin.password": nil, + "server.secretkey": nil, + }, + } + kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + completed := runWatchTest(t, db, []func(_ *v1alpha1.Cluster, _ *v1alpha1.Cluster){ + func(_ *v1alpha1.Cluster, _ *v1alpha1.Cluster) { + assert.Fail(t, "The in-cluster should not be added when disabled") + }, + }) + assert.False(t, completed, "Expecting the method to never complete because no cluster is ever added") } diff --git a/util/db/cluster_test.go b/util/db/cluster_test.go index 3b448bdeda..7243f3de47 100644 --- a/util/db/cluster_test.go +++ b/util/db/cluster_test.go @@ -253,7 +253,7 @@ func TestRejectCreationForInClusterWhenDisabled(t *testing.T) { require.Error(t, err) } -func runWatchTest(t *testing.T, db ArgoDB, actions []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster)) { +func runWatchTest(t *testing.T, db ArgoDB, actions []func(old *v1alpha1.Cluster, new *v1alpha1.Cluster)) (completed bool) { t.Helper() ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -290,11 +290,144 @@ func runWatchTest(t *testing.T, db ArgoDB, actions []func(old *v1alpha1.Cluster, select { case <-allDone: + return true case <-time.After(timeout): - assert.Fail(t, "Failed due to timeout") + return false } } +func TestGetCluster(t *testing.T) { + emptyArgoCDConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDConfigMapName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{}, + } + argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDConfigMapName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{"cluster.inClusterEnabled": "false"}, + } + argoCDSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDSecretName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string][]byte{ + "admin.password": nil, + "server.secretkey": nil, + }, + } + secretForServerWithInClusterAddr := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mycluster1", + Namespace: fakeNamespace, + Labels: map[string]string{ + common.LabelKeySecretType: common.LabelValueSecretTypeCluster, + }, + }, + Data: map[string][]byte{ + "server": []byte(v1alpha1.KubernetesInternalAPIServerAddr), + "name": []byte("in-cluster-renamed"), + }, + } + + secretForServerWithExternalClusterAddr := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mycluster2", + Namespace: fakeNamespace, + Labels: map[string]string{ + common.LabelKeySecretType: common.LabelValueSecretTypeCluster, + }, + }, + Data: map[string][]byte{ + "server": []byte("http://mycluster2"), + "name": []byte("mycluster2"), + }, + } + + t.Run("Valid external cluster", func(t *testing.T) { + kubeclientset := fake.NewClientset(secretForServerWithExternalClusterAddr, emptyArgoCDConfigMap, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + + cluster, err := db.GetCluster(context.TODO(), string(secretForServerWithExternalClusterAddr.Data["server"])) + require.NoError(t, err) + assert.Equal(t, string(secretForServerWithExternalClusterAddr.Data["server"]), cluster.Server) + assert.Equal(t, string(secretForServerWithExternalClusterAddr.Data["name"]), cluster.Name) + }) + + t.Run("invalid cluster", func(t *testing.T) { + kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + + _, err := db.GetCluster(context.TODO(), "https://mycluster-does-not-exist") + require.Error(t, err) + status, ok := status.FromError(err) + assert.True(t, ok) + assert.Equal(t, codes.NotFound, status.Code()) + }) + + t.Run("in-cluster not configured", func(t *testing.T) { + kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + + cluster, err := db.GetCluster(context.TODO(), v1alpha1.KubernetesInternalAPIServerAddr) + require.NoError(t, err) + assert.Equal(t, v1alpha1.KubernetesInternalAPIServerAddr, cluster.Server) + assert.Equal(t, "in-cluster", cluster.Name) + }) + + t.Run("in-cluster disabled", func(t *testing.T) { + kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + + _, err := db.GetCluster(context.TODO(), v1alpha1.KubernetesInternalAPIServerAddr) + require.Error(t, err) + status, ok := status.FromError(err) + assert.True(t, ok) + assert.Equal(t, codes.NotFound, status.Code()) + }) + + t.Run("in-cluster configured", func(t *testing.T) { + kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, emptyArgoCDConfigMap, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + + cluster, err := db.GetCluster(context.TODO(), v1alpha1.KubernetesInternalAPIServerAddr) + require.NoError(t, err) + assert.Equal(t, v1alpha1.KubernetesInternalAPIServerAddr, cluster.Server) + assert.Equal(t, "in-cluster-renamed", cluster.Name) + }) + + t.Run("in-cluster configured and disabled", func(t *testing.T) { + kubeclientset := fake.NewClientset(secretForServerWithInClusterAddr, argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret) + settingsManager := settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace) + db := NewDB(fakeNamespace, settingsManager, kubeclientset) + + _, err := db.GetCluster(context.TODO(), v1alpha1.KubernetesInternalAPIServerAddr) + require.Error(t, err) + status, ok := status.FromError(err) + assert.True(t, ok) + assert.Equal(t, codes.NotFound, status.Code()) + }) +} + func TestListClusters(t *testing.T) { emptyArgoCDConfigMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -421,6 +554,113 @@ func TestListClusters(t *testing.T) { }) } +func TestGetClusterServersByName(t *testing.T) { + emptyArgoCDConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDConfigMapName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{}, + } + argoCDSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDSecretName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string][]byte{ + "admin.password": nil, + "server.secretkey": nil, + }, + } + argoCDConfigMapWithInClusterServerAddressDisabled := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDConfigMapName, + Namespace: fakeNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{"cluster.inClusterEnabled": "false"}, + } + argoCDSecretInClusterConfigured := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-secret", + Namespace: fakeNamespace, + Labels: map[string]string{ + common.LabelKeySecretType: common.LabelValueSecretTypeCluster, + }, + Annotations: map[string]string{ + common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD, + }, + }, + Data: map[string][]byte{ + "name": []byte("in-cluster-renamed"), + "server": []byte(v1alpha1.KubernetesInternalAPIServerAddr), + "config": []byte("{}"), + }, + } + + t.Run("returns the server name", func(t *testing.T) { + argoCDClusterSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-secret", + Namespace: fakeNamespace, + Labels: map[string]string{ + common.LabelKeySecretType: common.LabelValueSecretTypeCluster, + }, + Annotations: map[string]string{ + common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD, + }, + }, + Data: map[string][]byte{ + "name": []byte("my-cluster-name"), + "server": []byte("https://my-cluster-server"), + "config": []byte("{}"), + }, + } + + kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDClusterSecret, argoCDSecret) + db := NewDB(fakeNamespace, settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace), kubeclientset) + servers, err := db.GetClusterServersByName(context.Background(), "my-cluster-name") + require.NoError(t, err) + assert.ElementsMatch(t, []string{"https://my-cluster-server"}, servers) + }) + t.Run("returns in-cluster", func(t *testing.T) { + kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecret) + db := NewDB(fakeNamespace, settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace), kubeclientset) + servers, err := db.GetClusterServersByName(context.Background(), "in-cluster") + require.NoError(t, err) + assert.ElementsMatch(t, []string{v1alpha1.KubernetesInternalAPIServerAddr}, servers) + }) + t.Run("does not return in-cluster when disabled", func(t *testing.T) { + kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecret) + db := NewDB(fakeNamespace, settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace), kubeclientset) + servers, err := db.GetClusterServersByName(context.Background(), "in-cluster") + require.NoError(t, err) + assert.Empty(t, servers) + }) + t.Run("returns in-cluster when configured", func(t *testing.T) { + kubeclientset := fake.NewClientset(emptyArgoCDConfigMap, argoCDSecretInClusterConfigured, argoCDSecret) + db := NewDB(fakeNamespace, settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace), kubeclientset) + servers, err := db.GetClusterServersByName(context.Background(), "in-cluster-renamed") + require.NoError(t, err) + assert.ElementsMatch(t, []string{v1alpha1.KubernetesInternalAPIServerAddr}, servers) + }) + t.Run("does not return in-cluster when configured and disabled", func(t *testing.T) { + kubeclientset := fake.NewClientset(argoCDConfigMapWithInClusterServerAddressDisabled, argoCDSecretInClusterConfigured, argoCDSecret) + db := NewDB(fakeNamespace, settings.NewSettingsManager(context.Background(), kubeclientset, fakeNamespace), kubeclientset) + servers, err := db.GetClusterServersByName(context.Background(), "in-cluster-renamed") + require.NoError(t, err) + assert.Empty(t, servers) + }) +} + // TestClusterRaceConditionClusterSecrets reproduces a race condition // on the cluster secrets. The test isn't asserting anything because // before the fix it would cause a panic from concurrent map iteration and map write diff --git a/util/db/db_test.go b/util/db/db_test.go index 04853aa871..246a96f555 100644 --- a/util/db/db_test.go +++ b/util/db/db_test.go @@ -502,42 +502,6 @@ func TestRepositorySecretsTrim(t *testing.T) { } } -func TestGetClusterSuccessful(t *testing.T) { - server := "my-cluster" - name := "my-name" - clientset := getClientset(nil, &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Labels: map[string]string{ - common.LabelKeySecretType: common.LabelValueSecretTypeCluster, - }, - }, - Data: map[string][]byte{ - "server": []byte(server), - "name": []byte(name), - "config": []byte("{}"), - }, - }) - - db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) - cluster, err := db.GetCluster(context.Background(), server) - require.NoError(t, err) - assert.Equal(t, server, cluster.Server) - assert.Equal(t, name, cluster.Name) -} - -func TestGetNonExistingCluster(t *testing.T) { - server := "https://mycluster" - clientset := getClientset(nil) - - db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) - _, err := db.GetCluster(context.Background(), server) - require.Error(t, err) - status, ok := status.FromError(err) - assert.True(t, ok) - assert.Equal(t, codes.NotFound, status.Code()) -} - func TestCreateClusterSuccessful(t *testing.T) { server := "https://mycluster" clientset := getClientset(nil) @@ -752,62 +716,6 @@ func TestHelmRepositorySecretsTrim(t *testing.T) { } } -func TestGetClusterServersByName(t *testing.T) { - clientset := getClientset(nil, &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-cluster-secret", - Namespace: testNamespace, - Labels: map[string]string{ - common.LabelKeySecretType: common.LabelValueSecretTypeCluster, - }, - Annotations: map[string]string{ - common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD, - }, - }, - Data: map[string][]byte{ - "name": []byte("my-cluster-name"), - "server": []byte("https://my-cluster-server"), - "config": []byte("{}"), - }, - }) - db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) - servers, err := db.GetClusterServersByName(context.Background(), "my-cluster-name") - require.NoError(t, err) - assert.ElementsMatch(t, []string{"https://my-cluster-server"}, servers) -} - -func TestGetClusterServersByName_InClusterNotConfigured(t *testing.T) { - clientset := getClientset(nil) - db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) - servers, err := db.GetClusterServersByName(context.Background(), "in-cluster") - require.NoError(t, err) - assert.ElementsMatch(t, []string{v1alpha1.KubernetesInternalAPIServerAddr}, servers) -} - -func TestGetClusterServersByName_InClusterConfigured(t *testing.T) { - clientset := getClientset(nil, &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-cluster-secret", - Namespace: testNamespace, - Labels: map[string]string{ - common.LabelKeySecretType: common.LabelValueSecretTypeCluster, - }, - Annotations: map[string]string{ - common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD, - }, - }, - Data: map[string][]byte{ - "name": []byte("in-cluster-renamed"), - "server": []byte(v1alpha1.KubernetesInternalAPIServerAddr), - "config": []byte("{}"), - }, - }) - db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) - servers, err := db.GetClusterServersByName(context.Background(), "in-cluster-renamed") - require.NoError(t, err) - assert.ElementsMatch(t, []string{v1alpha1.KubernetesInternalAPIServerAddr}, servers) -} - func TestGetApplicationControllerReplicas(t *testing.T) { clientset := getClientset(nil) expectedReplicas := int32(2)