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 }