github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/deployment_test.go (about) 1 package argocd 2 3 import ( 4 "context" 5 "reflect" 6 "strings" 7 "testing" 8 9 appsv1 "k8s.io/api/apps/v1" 10 corev1 "k8s.io/api/core/v1" 11 apierrors "k8s.io/apimachinery/pkg/api/errors" 12 resourcev1 "k8s.io/apimachinery/pkg/api/resource" 13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 "k8s.io/apimachinery/pkg/runtime" 15 "k8s.io/apimachinery/pkg/types" 16 "k8s.io/apimachinery/pkg/util/intstr" 17 "sigs.k8s.io/controller-runtime/pkg/client" 18 logf "sigs.k8s.io/controller-runtime/pkg/log" 19 20 "github.com/argoproj-labs/argocd-operator/common" 21 "github.com/argoproj-labs/argocd-operator/controllers/argoutil" 22 23 "github.com/google/go-cmp/cmp" 24 "github.com/stretchr/testify/assert" 25 26 argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" 27 ) 28 29 const ( 30 testHTTPProxy = "example.com:8888" 31 testHTTPSProxy = "example.com:8443" 32 testNoProxy = ".example.com" 33 ) 34 35 var ( 36 deploymentNames = []string{ 37 "argocd-repo-server", 38 "argocd-dex-server", 39 "argocd-redis", 40 "argocd-server"} 41 ) 42 43 func TestReconcileArgoCD_reconcileRepoDeployment_replicas(t *testing.T) { 44 logf.SetLogger(ZapLogger(true)) 45 46 tests := []struct { 47 name string 48 replicas int32 49 expectedNil bool 50 expectedValue int32 51 }{ 52 { 53 name: "replicas field in the spec should reflect the number of replicas on the cluster", 54 replicas: 5, 55 expectedNil: false, 56 expectedValue: 5, 57 }, 58 } 59 60 for _, test := range tests { 61 t.Run(test.name, func(t *testing.T) { 62 63 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 64 a.Spec.Repo.Replicas = &test.replicas 65 }) 66 67 resObjs := []client.Object{a} 68 subresObjs := []client.Object{a} 69 runtimeObjs := []runtime.Object{} 70 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 71 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 72 r := makeTestReconciler(cl, sch) 73 74 err := r.reconcileRepoDeployment(a, false) 75 assert.NoError(t, err) 76 77 deployment := &appsv1.Deployment{} 78 err = r.Client.Get(context.TODO(), types.NamespacedName{ 79 Name: "argocd-repo-server", 80 Namespace: testNamespace, 81 }, deployment) 82 assert.NoError(t, err) 83 assert.Equal(t, test.expectedNil, deployment.Spec.Replicas == nil) 84 if deployment.Spec.Replicas != nil { 85 assert.Equal(t, test.expectedValue, *deployment.Spec.Replicas) 86 } 87 }) 88 } 89 } 90 91 func TestReconcileArgoCD_reconcile_ServerDeployment_replicas(t *testing.T) { 92 logf.SetLogger(ZapLogger(true)) 93 94 var ( 95 initalReplicas int32 = 4 96 updatedReplicas int32 = 5 97 ) 98 99 tests := []struct { 100 name string 101 initialReplicas *int32 102 updatedReplicas *int32 103 autoscale bool 104 wantFinalReplicas *int32 105 }{ 106 { 107 name: "deployment spec replicas initially nil, updated by operator, no autoscale", 108 initialReplicas: nil, 109 updatedReplicas: &updatedReplicas, 110 autoscale: false, 111 wantFinalReplicas: &updatedReplicas, 112 }, 113 { 114 name: "deployment spec replicas initially not nil, updated by operator, no autoscale", 115 initialReplicas: &initalReplicas, 116 updatedReplicas: &updatedReplicas, 117 autoscale: false, 118 wantFinalReplicas: &updatedReplicas, 119 }, 120 { 121 name: "deployment spec replicas initially nil, ignored by operator with autoscale", 122 initialReplicas: nil, 123 updatedReplicas: &updatedReplicas, 124 autoscale: true, 125 wantFinalReplicas: nil, 126 }, 127 } 128 129 for _, test := range tests { 130 t.Run(test.name, func(t *testing.T) { 131 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 132 a.Spec.Server.Replicas = test.initialReplicas 133 a.Spec.Server.Autoscale.Enabled = test.autoscale 134 }) 135 136 resObjs := []client.Object{a} 137 subresObjs := []client.Object{a} 138 runtimeObjs := []runtime.Object{} 139 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 140 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 141 r := makeTestReconciler(cl, sch) 142 143 err := r.reconcileServerDeployment(a, false) 144 assert.NoError(t, err) 145 146 deployment := &appsv1.Deployment{} 147 err = r.Client.Get(context.TODO(), types.NamespacedName{ 148 Name: "argocd-server", 149 Namespace: testNamespace, 150 }, deployment) 151 assert.NoError(t, err) 152 assert.Equal(t, test.initialReplicas, deployment.Spec.Replicas) 153 154 a.Spec.Server.Replicas = test.updatedReplicas 155 err = r.reconcileServerDeployment(a, false) 156 assert.NoError(t, err) 157 158 deployment = &appsv1.Deployment{} 159 err = r.Client.Get(context.TODO(), types.NamespacedName{ 160 Name: "argocd-server", 161 Namespace: testNamespace, 162 }, deployment) 163 assert.NoError(t, err) 164 assert.Equal(t, test.wantFinalReplicas, deployment.Spec.Replicas) 165 166 }) 167 } 168 } 169 170 func TestReconcileArgoCD_reconcileRepoDeployment_loglevel(t *testing.T) { 171 logf.SetLogger(ZapLogger(true)) 172 173 repoDeps := []*argoproj.ArgoCD{ 174 makeTestArgoCD(func(a *argoproj.ArgoCD) { 175 a.Spec.Repo.LogLevel = "warn" 176 }), 177 makeTestArgoCD(func(a *argoproj.ArgoCD) { 178 a.Spec.Repo.LogLevel = "error" 179 }), 180 makeTestArgoCD(), 181 } 182 183 for _, lglv := range repoDeps { 184 185 var ll string 186 if lglv.Spec.Repo.LogLevel == "" { 187 ll = "info" 188 } else { 189 ll = lglv.Spec.Repo.LogLevel 190 } 191 192 resObjs := []client.Object{lglv} 193 subresObjs := []client.Object{lglv} 194 runtimeObjs := []runtime.Object{} 195 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 196 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 197 r := makeTestReconciler(cl, sch) 198 199 err := r.reconcileRepoDeployment(lglv, false) 200 assert.NoError(t, err) 201 deployment := &appsv1.Deployment{} 202 err = r.Client.Get(context.TODO(), types.NamespacedName{ 203 Name: "argocd-repo-server", 204 Namespace: testNamespace, 205 }, deployment) 206 assert.NoError(t, err) 207 208 for _, con := range deployment.Spec.Template.Spec.Containers { 209 if con.Name == "argocd-repo-server" { 210 for cmdKey, cmd := range con.Command { 211 if cmd == "--loglevel" { 212 if diff := cmp.Diff(ll, con.Command[cmdKey+1]); diff != "" { 213 t.Fatalf("reconcileRepoDeployment failed:\n%s", diff) 214 } 215 } 216 } 217 } 218 } 219 } 220 } 221 222 // TODO: This needs more testing for the rest of the RepoDeployment container 223 // fields. 224 225 // reconcileRepoDeployment creates a Deployment with the correct volumes for the 226 // repo-server. 227 func TestReconcileArgoCD_reconcileRepoDeployment_volumes(t *testing.T) { 228 t.Run("create default volumes", func(t *testing.T) { 229 logf.SetLogger(ZapLogger(true)) 230 a := makeTestArgoCD() 231 232 resObjs := []client.Object{a} 233 subresObjs := []client.Object{a} 234 runtimeObjs := []runtime.Object{} 235 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 236 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 237 r := makeTestReconciler(cl, sch) 238 239 err := r.reconcileRepoDeployment(a, false) 240 assert.NoError(t, err) 241 deployment := &appsv1.Deployment{} 242 err = r.Client.Get(context.TODO(), types.NamespacedName{ 243 Name: "argocd-repo-server", 244 Namespace: testNamespace, 245 }, deployment) 246 assert.NoError(t, err) 247 assert.Equal(t, repoServerDefaultVolumes(), deployment.Spec.Template.Spec.Volumes) 248 }) 249 250 t.Run("create extra volumes", func(t *testing.T) { 251 customVolume := corev1.Volume{ 252 Name: "custom-volume", 253 VolumeSource: corev1.VolumeSource{ 254 EmptyDir: &corev1.EmptyDirVolumeSource{}, 255 }, 256 } 257 258 logf.SetLogger(ZapLogger(true)) 259 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 260 a.Spec.Repo.Volumes = []corev1.Volume{customVolume} 261 }) 262 263 resObjs := []client.Object{a} 264 subresObjs := []client.Object{a} 265 runtimeObjs := []runtime.Object{} 266 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 267 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 268 r := makeTestReconciler(cl, sch) 269 270 err := r.reconcileRepoDeployment(a, false) 271 assert.NoError(t, err) 272 deployment := &appsv1.Deployment{} 273 err = r.Client.Get(context.TODO(), types.NamespacedName{ 274 Name: "argocd-repo-server", 275 Namespace: testNamespace, 276 }, deployment) 277 assert.NoError(t, err) 278 assert.Contains(t, deployment.Spec.Template.Spec.Volumes, customVolume) 279 }) 280 } 281 282 func TestReconcileArgoCD_reconcile_ServerDeployment_env(t *testing.T) { 283 t.Run("Test some env set in argocd-server", func(t *testing.T) { 284 logf.SetLogger(ZapLogger(true)) 285 a := makeTestArgoCD() 286 a.Spec.Server.Env = []corev1.EnvVar{ 287 { 288 Name: "FOO", 289 Value: "BAR", 290 }, 291 { 292 Name: "BAR", 293 Value: "FOO", 294 }, 295 } 296 timeout := 600 297 a.Spec.Repo.ExecTimeout = &timeout 298 299 resObjs := []client.Object{a} 300 subresObjs := []client.Object{a} 301 runtimeObjs := []runtime.Object{} 302 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 303 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 304 r := makeTestReconciler(cl, sch) 305 306 err := r.reconcileServerDeployment(a, false) 307 assert.NoError(t, err) 308 deployment := &appsv1.Deployment{} 309 err = r.Client.Get(context.TODO(), types.NamespacedName{ 310 Name: "argocd-server", 311 Namespace: testNamespace, 312 }, deployment) 313 assert.NoError(t, err) 314 315 assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 2) 316 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "FOO", Value: "BAR"}) 317 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "BAR", Value: "FOO"}) 318 }) 319 320 } 321 322 func TestReconcileArgoCD_reconcileRepoDeployment_env(t *testing.T) { 323 t.Run("Test some env set in argocd-repo-server", func(t *testing.T) { 324 logf.SetLogger(ZapLogger(true)) 325 a := makeTestArgoCD() 326 a.Spec.Repo.Env = []corev1.EnvVar{ 327 { 328 Name: "FOO", 329 Value: "BAR", 330 }, 331 { 332 Name: "BAR", 333 Value: "FOO", 334 }, 335 } 336 timeout := 600 337 a.Spec.Repo.ExecTimeout = &timeout 338 339 resObjs := []client.Object{a} 340 subresObjs := []client.Object{a} 341 runtimeObjs := []runtime.Object{} 342 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 343 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 344 r := makeTestReconciler(cl, sch) 345 346 err := r.reconcileRepoDeployment(a, false) 347 assert.NoError(t, err) 348 deployment := &appsv1.Deployment{} 349 err = r.Client.Get(context.TODO(), types.NamespacedName{ 350 Name: "argocd-repo-server", 351 Namespace: testNamespace, 352 }, deployment) 353 assert.NoError(t, err) 354 355 assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 3) 356 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "FOO", Value: "BAR"}) 357 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "BAR", Value: "FOO"}) 358 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "ARGOCD_EXEC_TIMEOUT", Value: "600s"}) 359 }) 360 361 t.Run("ExecTimeout set", func(t *testing.T) { 362 logf.SetLogger(ZapLogger(true)) 363 a := makeTestArgoCD() 364 timeout := 600 365 a.Spec.Repo.ExecTimeout = &timeout 366 367 resObjs := []client.Object{a} 368 subresObjs := []client.Object{a} 369 runtimeObjs := []runtime.Object{} 370 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 371 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 372 r := makeTestReconciler(cl, sch) 373 374 err := r.reconcileRepoDeployment(a, false) 375 assert.NoError(t, err) 376 deployment := &appsv1.Deployment{} 377 err = r.Client.Get(context.TODO(), types.NamespacedName{ 378 Name: "argocd-repo-server", 379 Namespace: testNamespace, 380 }, deployment) 381 assert.NoError(t, err) 382 383 assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 1) 384 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "ARGOCD_EXEC_TIMEOUT", Value: "600s"}) 385 }) 386 387 t.Run("ExecTimeout set with env set explicitly", func(t *testing.T) { 388 logf.SetLogger(ZapLogger(true)) 389 a := makeTestArgoCD() 390 timeout := 600 391 a.Spec.Repo.ExecTimeout = &timeout 392 a.Spec.Repo.Env = []corev1.EnvVar{ 393 { 394 Name: "ARGOCD_EXEC_TIMEOUT", 395 Value: "20s", 396 }, 397 } 398 399 resObjs := []client.Object{a} 400 subresObjs := []client.Object{a} 401 runtimeObjs := []runtime.Object{} 402 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 403 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 404 r := makeTestReconciler(cl, sch) 405 406 err := r.reconcileRepoDeployment(a, false) 407 assert.NoError(t, err) 408 deployment := &appsv1.Deployment{} 409 err = r.Client.Get(context.TODO(), types.NamespacedName{ 410 Name: "argocd-repo-server", 411 Namespace: testNamespace, 412 }, deployment) 413 assert.NoError(t, err) 414 415 assert.Len(t, deployment.Spec.Template.Spec.Containers[0].Env, 1) 416 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{Name: "ARGOCD_EXEC_TIMEOUT", Value: "600s"}) 417 }) 418 t.Run("ExecTimeout not set", func(t *testing.T) { 419 logf.SetLogger(ZapLogger(true)) 420 a := makeTestArgoCD() 421 422 resObjs := []client.Object{a} 423 subresObjs := []client.Object{a} 424 runtimeObjs := []runtime.Object{} 425 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 426 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 427 r := makeTestReconciler(cl, sch) 428 429 err := r.reconcileRepoDeployment(a, false) 430 assert.NoError(t, err) 431 deployment := &appsv1.Deployment{} 432 err = r.Client.Get(context.TODO(), types.NamespacedName{ 433 Name: "argocd-repo-server", 434 Namespace: testNamespace, 435 }, deployment) 436 assert.NoError(t, err) 437 assert.Empty(t, deployment.Spec.Template.Spec.Containers[0].Env) 438 }) 439 } 440 441 // reconcileRepoDeployment creates a Deployment with the correct mounts for the 442 // repo-server. 443 func TestReconcileArgoCD_reconcileRepoDeployment_mounts(t *testing.T) { 444 t.Run("Create default mounts", func(t *testing.T) { 445 logf.SetLogger(ZapLogger(true)) 446 a := makeTestArgoCD() 447 448 resObjs := []client.Object{a} 449 subresObjs := []client.Object{a} 450 runtimeObjs := []runtime.Object{} 451 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 452 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 453 r := makeTestReconciler(cl, sch) 454 455 err := r.reconcileRepoDeployment(a, false) 456 assert.NoError(t, err) 457 458 deployment := &appsv1.Deployment{} 459 err = r.Client.Get(context.TODO(), types.NamespacedName{ 460 Name: "argocd-repo-server", 461 Namespace: testNamespace, 462 }, deployment) 463 assert.NoError(t, err) 464 assert.Equal(t, repoServerDefaultVolumeMounts(), deployment.Spec.Template.Spec.Containers[0].VolumeMounts) 465 }) 466 467 t.Run("Add extra mounts", func(t *testing.T) { 468 testMount := corev1.VolumeMount{ 469 Name: "test-mount", 470 MountPath: "/test-mount", 471 } 472 473 logf.SetLogger(ZapLogger(true)) 474 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 475 a.Spec.Repo.VolumeMounts = []corev1.VolumeMount{testMount} 476 }) 477 478 resObjs := []client.Object{a} 479 subresObjs := []client.Object{a} 480 runtimeObjs := []runtime.Object{} 481 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 482 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 483 r := makeTestReconciler(cl, sch) 484 485 err := r.reconcileRepoDeployment(a, false) 486 assert.NoError(t, err) 487 488 deployment := &appsv1.Deployment{} 489 err = r.Client.Get(context.TODO(), types.NamespacedName{ 490 Name: "argocd-repo-server", 491 Namespace: testNamespace, 492 }, deployment) 493 assert.NoError(t, err) 494 assert.Contains(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, testMount) 495 }) 496 } 497 498 func TestReconcileArgoCD_reconcileRepoDeployment_initContainers(t *testing.T) { 499 logf.SetLogger(ZapLogger(true)) 500 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 501 ic := corev1.Container{ 502 Name: "test-init-container", 503 Image: "test-image", 504 } 505 a.Spec.Repo.InitContainers = []corev1.Container{ic} 506 }) 507 508 resObjs := []client.Object{a} 509 subresObjs := []client.Object{a} 510 runtimeObjs := []runtime.Object{} 511 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 512 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 513 r := makeTestReconciler(cl, sch) 514 515 err := r.reconcileRepoDeployment(a, false) 516 assert.NoError(t, err) 517 518 deployment := &appsv1.Deployment{} 519 err = r.Client.Get(context.TODO(), types.NamespacedName{ 520 Name: "argocd-repo-server", 521 Namespace: testNamespace, 522 }, deployment) 523 assert.NoError(t, err) 524 assert.Equal(t, deployment.Spec.Template.Spec.InitContainers[1].Name, "test-init-container") 525 } 526 527 func TestReconcileArgoCD_reconcileRepoDeployment_missingInitContainers(t *testing.T) { 528 logf.SetLogger(ZapLogger(true)) 529 a := makeTestArgoCD() 530 d := &appsv1.Deployment{ 531 ObjectMeta: metav1.ObjectMeta{ 532 Name: "argocd-repo-server", 533 Namespace: testNamespace, 534 }, 535 Spec: appsv1.DeploymentSpec{ 536 Template: corev1.PodTemplateSpec{ 537 Spec: corev1.PodSpec{ 538 Containers: []corev1.Container{ 539 { 540 Command: []string{"testing"}, 541 Image: "test-image", 542 }, 543 }, 544 InitContainers: []corev1.Container{}, 545 }, 546 }, 547 }, 548 } 549 550 resObjs := []client.Object{a, d} 551 subresObjs := []client.Object{a, d} 552 runtimeObjs := []runtime.Object{} 553 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 554 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 555 r := makeTestReconciler(cl, sch) 556 557 err := r.reconcileRepoDeployment(a, false) 558 assert.NoError(t, err) 559 deployment := &appsv1.Deployment{} 560 err = r.Client.Get(context.TODO(), types.NamespacedName{ 561 Name: "argocd-repo-server", 562 Namespace: testNamespace, 563 }, deployment) 564 assert.NoError(t, err) 565 assert.Len(t, deployment.Spec.Template.Spec.InitContainers, 1) 566 assert.Equal(t, deployment.Spec.Template.Spec.InitContainers[0].Name, "copyutil") 567 } 568 func TestReconcileArgoCD_reconcileRepoDeployment_unexpectedInitContainer(t *testing.T) { 569 logf.SetLogger(ZapLogger(true)) 570 a := makeTestArgoCD() 571 d := &appsv1.Deployment{ 572 ObjectMeta: metav1.ObjectMeta{ 573 Name: "argocd-repo-server", 574 Namespace: testNamespace, 575 }, 576 Spec: appsv1.DeploymentSpec{ 577 Template: corev1.PodTemplateSpec{ 578 Spec: corev1.PodSpec{ 579 Containers: []corev1.Container{ 580 { 581 Command: []string{"testing"}, 582 Image: "test-image", 583 }, 584 }, 585 InitContainers: []corev1.Container{ 586 { 587 Name: "unknown", 588 Command: []string{"testing-ic"}, 589 Image: "test-image-ic", 590 }, 591 }, 592 }, 593 }, 594 }, 595 } 596 597 resObjs := []client.Object{a, d} 598 subresObjs := []client.Object{a, d} 599 runtimeObjs := []runtime.Object{} 600 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 601 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 602 r := makeTestReconciler(cl, sch) 603 604 err := r.reconcileRepoDeployment(a, false) 605 assert.NoError(t, err) 606 deployment := &appsv1.Deployment{} 607 err = r.Client.Get(context.TODO(), types.NamespacedName{ 608 Name: "argocd-repo-server", 609 Namespace: testNamespace, 610 }, deployment) 611 assert.NoError(t, err) 612 assert.Len(t, deployment.Spec.Template.Spec.InitContainers, 1) 613 assert.Equal(t, deployment.Spec.Template.Spec.InitContainers[0].Name, "copyutil") 614 } 615 616 func TestReconcileArgoCD_reconcileRepoDeployment_command(t *testing.T) { 617 logf.SetLogger(ZapLogger(true)) 618 a := makeTestArgoCD() 619 620 resObjs := []client.Object{a} 621 subresObjs := []client.Object{a} 622 runtimeObjs := []runtime.Object{} 623 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 624 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 625 r := makeTestReconciler(cl, sch) 626 627 err := r.reconcileRepoDeployment(a, false) 628 assert.NoError(t, err) 629 630 deployment := &appsv1.Deployment{} 631 err = r.Client.Get(context.TODO(), types.NamespacedName{ 632 Name: "argocd-repo-server", 633 Namespace: testNamespace, 634 }, deployment) 635 assert.NoError(t, err) 636 637 deployment.Spec.Template.Spec.Containers[0].Command[6] = "debug" 638 err = r.reconcileRepoDeployment(a, false) 639 assert.NoError(t, err) 640 641 assert.Equal(t, "debug", deployment.Spec.Template.Spec.Containers[0].Command[6]) 642 } 643 644 // reconcileRepoDeployments creates a Deployment with the proxy settings from the 645 // environment propagated. 646 func TestReconcileArgoCD_reconcileDeployments_proxy(t *testing.T) { 647 648 t.Setenv("HTTP_PROXY", testHTTPProxy) 649 t.Setenv("HTTPS_PROXY", testHTTPSProxy) 650 t.Setenv("no_proxy", testNoProxy) 651 652 logf.SetLogger(ZapLogger(true)) 653 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 654 a.Spec.Grafana.Enabled = true 655 a.Spec.SSO = &argoproj.ArgoCDSSOSpec{ 656 Provider: argoproj.SSOProviderTypeDex, 657 Dex: &argoproj.ArgoCDDexSpec{ 658 Config: "test", 659 }, 660 } 661 }) 662 663 resObjs := []client.Object{a} 664 subresObjs := []client.Object{a} 665 runtimeObjs := []runtime.Object{} 666 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 667 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 668 r := makeTestReconciler(cl, sch) 669 670 err := r.reconcileDeployments(a, false) 671 assert.NoError(t, err) 672 err = r.reconcileDexDeployment(a) 673 assert.NoError(t, err) 674 675 for _, v := range deploymentNames { 676 assertDeploymentHasProxyVars(t, r.Client, v) 677 } 678 } 679 680 // reconcileRepoDeployments creates a Deployment with the proxy settings from the 681 // environment propagated. 682 // 683 // If the deployments already exist, they should be updated to reflect the new 684 // environment variables. 685 func TestReconcileArgoCD_reconcileDeployments_proxy_update_existing(t *testing.T) { 686 logf.SetLogger(ZapLogger(true)) 687 688 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 689 a.Spec.SSO = &argoproj.ArgoCDSSOSpec{ 690 Provider: argoproj.SSOProviderTypeDex, 691 Dex: &argoproj.ArgoCDDexSpec{ 692 Config: "test", 693 }, 694 } 695 }) 696 697 resObjs := []client.Object{a} 698 subresObjs := []client.Object{a} 699 runtimeObjs := []runtime.Object{} 700 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 701 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 702 r := makeTestReconciler(cl, sch) 703 704 err := r.reconcileDeployments(a, false) 705 assert.NoError(t, err) 706 707 err = r.reconcileDexDeployment(a) 708 assert.NoError(t, err) 709 710 for _, v := range deploymentNames { 711 refuteDeploymentHasProxyVars(t, r.Client, v) 712 } 713 714 t.Setenv("HTTP_PROXY", testHTTPProxy) 715 t.Setenv("HTTPS_PROXY", testHTTPSProxy) 716 t.Setenv("no_proxy", testNoProxy) 717 718 logf.SetLogger(ZapLogger(true)) 719 720 err = r.reconcileDeployments(a, false) 721 assert.NoError(t, err) 722 err = r.reconcileDexDeployment(a) 723 assert.NoError(t, err) 724 725 for _, v := range deploymentNames { 726 assertDeploymentHasProxyVars(t, r.Client, v) 727 } 728 } 729 730 // TODO: This should be subsumed into testing of the HA setup. 731 func TestReconcileArgoCD_reconcileDeployments_HA_proxy(t *testing.T) { 732 t.Setenv("HTTP_PROXY", testHTTPProxy) 733 t.Setenv("HTTPS_PROXY", testHTTPSProxy) 734 t.Setenv("no_proxy", testNoProxy) 735 736 logf.SetLogger(ZapLogger(true)) 737 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 738 a.Spec.HA.Enabled = true 739 }) 740 741 resObjs := []client.Object{a} 742 subresObjs := []client.Object{a} 743 runtimeObjs := []runtime.Object{} 744 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 745 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 746 r := makeTestReconciler(cl, sch) 747 748 err := r.reconcileDeployments(a, false) 749 assert.NoError(t, err) 750 751 assertDeploymentHasProxyVars(t, r.Client, "argocd-redis-ha-haproxy") 752 } 753 754 func TestReconcileArgoCD_reconcileDeployments_HA_proxy_with_resources(t *testing.T) { 755 t.Setenv("HTTP_PROXY", testHTTPProxy) 756 t.Setenv("HTTPS_PROXY", testHTTPSProxy) 757 t.Setenv("no_proxy", testNoProxy) 758 759 logf.SetLogger(ZapLogger(true)) 760 a := makeTestArgoCDWithResources(func(a *argoproj.ArgoCD) { 761 a.Spec.HA.Enabled = true 762 }) 763 764 resObjs := []client.Object{a} 765 subresObjs := []client.Object{a} 766 runtimeObjs := []runtime.Object{} 767 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 768 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 769 r := makeTestReconciler(cl, sch) 770 771 // test resource is Created on reconciliation 772 assert.NoError(t, r.reconcileRedisHAProxyDeployment(a)) 773 774 deployment := &appsv1.Deployment{} 775 assert.NoError(t, r.Client.Get( 776 context.TODO(), 777 types.NamespacedName{ 778 Name: a.Name + "-redis-ha-haproxy", 779 Namespace: a.Namespace, 780 }, 781 deployment)) 782 783 testResources := corev1.ResourceRequirements{ 784 Requests: corev1.ResourceList{ 785 corev1.ResourceMemory: resourcev1.MustParse("128Mi"), 786 corev1.ResourceCPU: resourcev1.MustParse("250m"), 787 }, 788 Limits: corev1.ResourceList{ 789 corev1.ResourceMemory: resourcev1.MustParse("256Mi"), 790 corev1.ResourceCPU: resourcev1.MustParse("500m"), 791 }, 792 } 793 assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources, testResources) 794 assert.Equal(t, deployment.Spec.Template.Spec.InitContainers[0].Resources, testResources) 795 796 // test resource is Updated on reconciliation 797 newResources := corev1.ResourceRequirements{ 798 Requests: corev1.ResourceList{ 799 corev1.ResourceMemory: resourcev1.MustParse("256Mi"), 800 corev1.ResourceCPU: resourcev1.MustParse("500m"), 801 }, 802 Limits: corev1.ResourceList{ 803 corev1.ResourceMemory: resourcev1.MustParse("512Mi"), 804 corev1.ResourceCPU: resourcev1.MustParse("1"), 805 }, 806 } 807 a.Spec.HA.Resources = &newResources 808 assert.NoError(t, r.reconcileRedisHAProxyDeployment(a)) 809 810 assert.NoError(t, r.Client.Get( 811 context.TODO(), 812 types.NamespacedName{ 813 Name: a.Name + "-redis-ha-haproxy", 814 Namespace: a.Namespace, 815 }, 816 deployment)) 817 818 assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].Resources, newResources) 819 assert.Equal(t, deployment.Spec.Template.Spec.InitContainers[0].Resources, newResources) 820 } 821 822 func TestReconcileArgoCD_reconcileRepoDeployment_updatesVolumeMounts(t *testing.T) { 823 logf.SetLogger(ZapLogger(true)) 824 a := makeTestArgoCD() 825 d := &appsv1.Deployment{ 826 ObjectMeta: metav1.ObjectMeta{ 827 Name: "argocd-repo-server", 828 Namespace: testNamespace, 829 }, 830 Spec: appsv1.DeploymentSpec{ 831 Template: corev1.PodTemplateSpec{ 832 Spec: corev1.PodSpec{ 833 Containers: []corev1.Container{ 834 { 835 Command: []string{"testing"}, 836 Image: "test-image", 837 }, 838 }, 839 InitContainers: []corev1.Container{ 840 { 841 Command: []string{"testing"}, 842 Image: "test-image", 843 }, 844 }, 845 }, 846 }, 847 }, 848 } 849 850 resObjs := []client.Object{a, d} 851 subresObjs := []client.Object{a, d} 852 runtimeObjs := []runtime.Object{} 853 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 854 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 855 r := makeTestReconciler(cl, sch) 856 857 err := r.reconcileRepoDeployment(a, false) 858 assert.NoError(t, err) 859 860 deployment := &appsv1.Deployment{} 861 err = r.Client.Get(context.TODO(), types.NamespacedName{ 862 Name: "argocd-repo-server", 863 Namespace: testNamespace, 864 }, deployment) 865 assert.NoError(t, err) 866 867 assert.Len(t, deployment.Spec.Template.Spec.Volumes, 9) 868 assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 8) 869 } 870 871 func Test_proxyEnvVars(t *testing.T) { 872 t.Setenv("HTTP_PROXY", testHTTPProxy) 873 t.Setenv("HTTPS_PROXY", testHTTPSProxy) 874 t.Setenv("no_proxy", testNoProxy) 875 envTests := []struct { 876 vars []corev1.EnvVar 877 want []corev1.EnvVar 878 }{ 879 { 880 vars: []corev1.EnvVar{}, 881 want: []corev1.EnvVar{ 882 {Name: "HTTP_PROXY", Value: "example.com:8888"}, 883 {Name: "HTTPS_PROXY", Value: "example.com:8443"}, 884 {Name: "no_proxy", Value: ".example.com"}, 885 }, 886 }, 887 { 888 vars: []corev1.EnvVar{ 889 {Name: "TEST_VAR", Value: "testing"}, 890 }, 891 want: []corev1.EnvVar{ 892 {Name: "TEST_VAR", Value: "testing"}, 893 {Name: "HTTP_PROXY", Value: "example.com:8888"}, 894 {Name: "HTTPS_PROXY", Value: "example.com:8443"}, 895 {Name: "no_proxy", Value: ".example.com"}, 896 }, 897 }, 898 } 899 900 for _, tt := range envTests { 901 e := proxyEnvVars(tt.vars...) 902 assert.Equal(t, tt.want, e) 903 } 904 } 905 906 func TestReconcileArgoCD_reconcileDeployment_nodePlacement(t *testing.T) { 907 logf.SetLogger(ZapLogger(true)) 908 a := makeTestArgoCD((func(a *argoproj.ArgoCD) { 909 a.Spec.NodePlacement = &argoproj.ArgoCDNodePlacementSpec{ 910 NodeSelector: deploymentDefaultNodeSelector(), 911 Tolerations: deploymentDefaultTolerations(), 912 } 913 })) 914 915 resObjs := []client.Object{a} 916 subresObjs := []client.Object{a} 917 runtimeObjs := []runtime.Object{} 918 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 919 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 920 r := makeTestReconciler(cl, sch) 921 922 err := r.reconcileRepoDeployment(a, false) //can use other deployments as well 923 assert.NoError(t, err) 924 deployment := &appsv1.Deployment{} 925 err = r.Client.Get(context.TODO(), types.NamespacedName{ 926 Name: "argocd-repo-server", 927 Namespace: testNamespace, 928 }, deployment) 929 assert.NoError(t, err) 930 931 nSelectors := deploymentDefaultNodeSelector() 932 nSelectors = argoutil.AppendStringMap(nSelectors, common.DefaultNodeSelector()) 933 934 if diff := cmp.Diff(nSelectors, deployment.Spec.Template.Spec.NodeSelector); diff != "" { 935 t.Fatalf("reconcileDeployment failed:\n%s", diff) 936 } 937 if diff := cmp.Diff(deploymentDefaultTolerations(), deployment.Spec.Template.Spec.Tolerations); diff != "" { 938 t.Fatalf("reconcileDeployment failed:\n%s", diff) 939 } 940 } 941 942 func deploymentDefaultNodeSelector() map[string]string { 943 nodeSelector := map[string]string{ 944 "test_key1": "test_value1", 945 "test_key2": "test_value2", 946 } 947 return nodeSelector 948 } 949 func deploymentDefaultTolerations() []corev1.Toleration { 950 toleration := []corev1.Toleration{ 951 { 952 Key: "test_key1", 953 Value: "test_value1", 954 Effect: corev1.TaintEffectNoSchedule, 955 }, 956 { 957 Key: "test_key2", 958 Value: "test_value2", 959 Operator: corev1.TolerationOpExists, 960 Effect: corev1.TaintEffectNoSchedule, 961 }, 962 } 963 return toleration 964 } 965 966 func TestReconcileArgocd_reconcileRepoServerRedisTLS(t *testing.T) { 967 t.Run("with DisableTLSVerification = false (the default)", func(t *testing.T) { 968 logf.SetLogger(ZapLogger(true)) 969 a := makeTestArgoCD() 970 971 resObjs := []client.Object{a} 972 subresObjs := []client.Object{a} 973 runtimeObjs := []runtime.Object{} 974 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 975 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 976 r := makeTestReconciler(cl, sch) 977 978 assert.NoError(t, r.reconcileRepoDeployment(a, true)) 979 980 deployment := &appsv1.Deployment{} 981 assert.NoError(t, r.Client.Get( 982 context.TODO(), 983 types.NamespacedName{ 984 Name: "argocd-repo-server", 985 Namespace: a.Namespace, 986 }, 987 deployment)) 988 989 wantCmd := []string{ 990 "uid_entrypoint.sh", 991 "argocd-repo-server", 992 "--redis", "argocd-redis.argocd.svc.cluster.local:6379", 993 "--redis-use-tls", 994 "--redis-ca-certificate", "/app/config/reposerver/tls/redis/tls.crt", 995 "--loglevel", "info", 996 "--logformat", "text", 997 } 998 assert.Equal(t, wantCmd, deployment.Spec.Template.Spec.Containers[0].Command) 999 }) 1000 1001 t.Run("with DisableTLSVerification = true", func(t *testing.T) { 1002 logf.SetLogger(ZapLogger(true)) 1003 a := makeTestArgoCD(func(cd *argoproj.ArgoCD) { 1004 cd.Spec.Redis.DisableTLSVerification = true 1005 }) 1006 1007 resObjs := []client.Object{a} 1008 subresObjs := []client.Object{a} 1009 runtimeObjs := []runtime.Object{} 1010 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1011 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1012 r := makeTestReconciler(cl, sch) 1013 1014 assert.NoError(t, r.reconcileRepoDeployment(a, true)) 1015 1016 deployment := &appsv1.Deployment{} 1017 assert.NoError(t, r.Client.Get( 1018 context.TODO(), 1019 types.NamespacedName{ 1020 Name: "argocd-repo-server", 1021 Namespace: a.Namespace, 1022 }, 1023 deployment)) 1024 1025 wantCmd := []string{ 1026 "uid_entrypoint.sh", 1027 "argocd-repo-server", 1028 "--redis", "argocd-redis.argocd.svc.cluster.local:6379", 1029 "--redis-use-tls", 1030 "--redis-insecure-skip-tls-verify", 1031 "--loglevel", "info", 1032 "--logformat", "text", 1033 } 1034 assert.Equal(t, wantCmd, deployment.Spec.Template.Spec.Containers[0].Command) 1035 }) 1036 } 1037 1038 func TestReconcileArgoCD_reconcileServerDeployment(t *testing.T) { 1039 logf.SetLogger(ZapLogger(true)) 1040 a := makeTestArgoCD() 1041 1042 resObjs := []client.Object{a} 1043 subresObjs := []client.Object{a} 1044 runtimeObjs := []runtime.Object{} 1045 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1046 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1047 r := makeTestReconciler(cl, sch) 1048 1049 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1050 1051 deployment := &appsv1.Deployment{} 1052 assert.NoError(t, r.Client.Get( 1053 context.TODO(), 1054 types.NamespacedName{ 1055 Name: "argocd-server", 1056 Namespace: a.Namespace, 1057 }, 1058 deployment)) 1059 want := corev1.PodSpec{ 1060 Containers: []corev1.Container{ 1061 { 1062 Name: "argocd-server", 1063 Image: getArgoContainerImage(a), 1064 ImagePullPolicy: corev1.PullAlways, 1065 Command: []string{ 1066 "argocd-server", 1067 "--staticassets", 1068 "/shared/app", 1069 "--dex-server", 1070 "https://argocd-dex-server.argocd.svc.cluster.local:5556", 1071 "--repo-server", 1072 "argocd-repo-server.argocd.svc.cluster.local:8081", 1073 "--redis", 1074 "argocd-redis.argocd.svc.cluster.local:6379", 1075 "--loglevel", 1076 "info", 1077 "--logformat", 1078 "text", 1079 }, 1080 Ports: []corev1.ContainerPort{ 1081 {ContainerPort: 8080}, 1082 {ContainerPort: 8083}, 1083 }, 1084 LivenessProbe: &corev1.Probe{ 1085 ProbeHandler: corev1.ProbeHandler{ 1086 HTTPGet: &corev1.HTTPGetAction{ 1087 Path: "/healthz", 1088 Port: intstr.FromInt(8080), 1089 }, 1090 }, 1091 InitialDelaySeconds: 3, 1092 PeriodSeconds: 30, 1093 }, 1094 ReadinessProbe: &corev1.Probe{ 1095 ProbeHandler: corev1.ProbeHandler{ 1096 HTTPGet: &corev1.HTTPGetAction{ 1097 Path: "/healthz", 1098 Port: intstr.FromInt(8080), 1099 }, 1100 }, 1101 InitialDelaySeconds: 3, 1102 PeriodSeconds: 30, 1103 }, 1104 SecurityContext: &corev1.SecurityContext{ 1105 AllowPrivilegeEscalation: boolPtr(false), 1106 Capabilities: &corev1.Capabilities{ 1107 Drop: []corev1.Capability{ 1108 "ALL", 1109 }, 1110 }, 1111 RunAsNonRoot: boolPtr(true), 1112 }, 1113 VolumeMounts: serverDefaultVolumeMounts(), 1114 }, 1115 }, 1116 Volumes: serverDefaultVolumes(), 1117 ServiceAccountName: "argocd-argocd-server", 1118 NodeSelector: common.DefaultNodeSelector(), 1119 } 1120 1121 assert.Equal(t, want, deployment.Spec.Template.Spec) 1122 1123 assert.NoError(t, r.reconcileServerDeployment(a, true)) 1124 deployment = &appsv1.Deployment{} 1125 assert.NoError(t, r.Client.Get( 1126 context.TODO(), 1127 types.NamespacedName{ 1128 Name: "argocd-server", 1129 Namespace: a.Namespace, 1130 }, 1131 deployment)) 1132 wantCmd := []string{ 1133 "argocd-server", 1134 "--staticassets", 1135 "/shared/app", 1136 "--dex-server", 1137 "https://argocd-dex-server.argocd.svc.cluster.local:5556", 1138 "--repo-server", 1139 "argocd-repo-server.argocd.svc.cluster.local:8081", 1140 "--redis", 1141 "argocd-redis.argocd.svc.cluster.local:6379", 1142 "--redis-use-tls", 1143 "--redis-ca-certificate", 1144 "/app/config/server/tls/redis/tls.crt", 1145 "--loglevel", 1146 "info", 1147 "--logformat", 1148 "text", 1149 } 1150 assert.Equal(t, wantCmd, deployment.Spec.Template.Spec.Containers[0].Command) 1151 } 1152 1153 func TestArgoCDServerDeploymentCommand(t *testing.T) { 1154 a := makeTestArgoCD() 1155 1156 resObjs := []client.Object{a} 1157 subresObjs := []client.Object{a} 1158 runtimeObjs := []runtime.Object{} 1159 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1160 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1161 r := makeTestReconciler(cl, sch) 1162 1163 baseCommand := []string{ 1164 "argocd-server", 1165 "--staticassets", 1166 "/shared/app", 1167 "--dex-server", 1168 "https://argocd-dex-server.argocd.svc.cluster.local:5556", 1169 "--repo-server", 1170 "argocd-repo-server.argocd.svc.cluster.local:8081", 1171 "--redis", 1172 "argocd-redis.argocd.svc.cluster.local:6379", 1173 "--loglevel", 1174 "info", 1175 "--logformat", 1176 "text", 1177 } 1178 1179 // When a single command argument is passed 1180 a.Spec.Server.ExtraCommandArgs = []string{ 1181 "--rootpath", 1182 "/argocd", 1183 } 1184 1185 deployment := &appsv1.Deployment{} 1186 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1187 1188 assert.NoError(t, r.Client.Get( 1189 context.TODO(), 1190 types.NamespacedName{ 1191 Name: "argocd-server", 1192 Namespace: a.Namespace, 1193 }, 1194 deployment)) 1195 1196 cmd := append(baseCommand, "--rootpath", "/argocd") 1197 assert.Equal(t, cmd, deployment.Spec.Template.Spec.Containers[0].Command) 1198 1199 // When multiple command arguments are passed 1200 a.Spec.Server.ExtraCommandArgs = []string{ 1201 "--rootpath", 1202 "/argocd", 1203 "--foo", 1204 "bar", 1205 "test", 1206 } 1207 1208 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1209 assert.NoError(t, r.Client.Get( 1210 context.TODO(), 1211 types.NamespacedName{ 1212 Name: "argocd-server", 1213 Namespace: a.Namespace, 1214 }, 1215 deployment)) 1216 1217 cmd = append(cmd, "--foo", "bar", "test") 1218 assert.Equal(t, cmd, deployment.Spec.Template.Spec.Containers[0].Command) 1219 1220 // When one of the ExtraCommandArgs already exists in cmd with same or different value 1221 a.Spec.Server.ExtraCommandArgs = []string{ 1222 "--redis", 1223 "foo.scv.cluster.local:6379", 1224 } 1225 1226 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1227 assert.NoError(t, r.Client.Get( 1228 context.TODO(), 1229 types.NamespacedName{ 1230 Name: "argocd-server", 1231 Namespace: a.Namespace, 1232 }, 1233 deployment)) 1234 1235 assert.Equal(t, baseCommand, deployment.Spec.Template.Spec.Containers[0].Command) 1236 1237 // Remove all the command arguments that were added. 1238 a.Spec.Server.ExtraCommandArgs = []string{} 1239 1240 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1241 assert.NoError(t, r.Client.Get( 1242 context.TODO(), 1243 types.NamespacedName{ 1244 Name: "argocd-server", 1245 Namespace: a.Namespace, 1246 }, 1247 deployment)) 1248 1249 assert.Equal(t, baseCommand, deployment.Spec.Template.Spec.Containers[0].Command) 1250 } 1251 1252 func TestArgoCDServerCommand_isMergable(t *testing.T) { 1253 cmd := []string{"--server", "foo.svc.cluster.local", "--path", "/bar"} 1254 extraCMDArgs := []string{"--extra-path", "/"} 1255 assert.NoError(t, isMergable(extraCMDArgs, cmd)) 1256 1257 cmd = []string{"--server", "foo.svc.cluster.local", "--path", "/bar"} 1258 extraCMDArgs = []string{"--server", "bar.com"} 1259 assert.Error(t, isMergable(extraCMDArgs, cmd)) 1260 } 1261 1262 func TestReconcileArgoCD_reconcileServerDeploymentWithInsecure(t *testing.T) { 1263 logf.SetLogger(ZapLogger(true)) 1264 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 1265 a.Spec.Server.Insecure = true 1266 }) 1267 1268 resObjs := []client.Object{a} 1269 subresObjs := []client.Object{a} 1270 runtimeObjs := []runtime.Object{} 1271 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1272 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1273 r := makeTestReconciler(cl, sch) 1274 1275 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1276 1277 deployment := &appsv1.Deployment{} 1278 assert.NoError(t, r.Client.Get( 1279 context.TODO(), 1280 types.NamespacedName{ 1281 Name: "argocd-server", 1282 Namespace: a.Namespace, 1283 }, 1284 deployment)) 1285 want := corev1.PodSpec{ 1286 Containers: []corev1.Container{ 1287 { 1288 Name: "argocd-server", 1289 Image: getArgoContainerImage(a), 1290 ImagePullPolicy: corev1.PullAlways, 1291 Command: []string{ 1292 "argocd-server", 1293 "--insecure", 1294 "--staticassets", 1295 "/shared/app", 1296 "--dex-server", 1297 "https://argocd-dex-server.argocd.svc.cluster.local:5556", 1298 "--repo-server", 1299 "argocd-repo-server.argocd.svc.cluster.local:8081", 1300 "--redis", 1301 "argocd-redis.argocd.svc.cluster.local:6379", 1302 "--loglevel", 1303 "info", 1304 "--logformat", 1305 "text", 1306 }, 1307 Ports: []corev1.ContainerPort{ 1308 {ContainerPort: 8080}, 1309 {ContainerPort: 8083}, 1310 }, 1311 LivenessProbe: &corev1.Probe{ 1312 ProbeHandler: corev1.ProbeHandler{ 1313 HTTPGet: &corev1.HTTPGetAction{ 1314 Path: "/healthz", 1315 Port: intstr.FromInt(8080), 1316 }, 1317 }, 1318 InitialDelaySeconds: 3, 1319 PeriodSeconds: 30, 1320 }, 1321 ReadinessProbe: &corev1.Probe{ 1322 ProbeHandler: corev1.ProbeHandler{ 1323 HTTPGet: &corev1.HTTPGetAction{ 1324 Path: "/healthz", 1325 Port: intstr.FromInt(8080), 1326 }, 1327 }, 1328 InitialDelaySeconds: 3, 1329 PeriodSeconds: 30, 1330 }, 1331 SecurityContext: &corev1.SecurityContext{ 1332 AllowPrivilegeEscalation: boolPtr(false), 1333 Capabilities: &corev1.Capabilities{ 1334 Drop: []corev1.Capability{ 1335 "ALL", 1336 }, 1337 }, 1338 RunAsNonRoot: boolPtr(true), 1339 }, 1340 VolumeMounts: serverDefaultVolumeMounts(), 1341 }, 1342 }, 1343 Volumes: serverDefaultVolumes(), 1344 ServiceAccountName: "argocd-argocd-server", 1345 NodeSelector: common.DefaultNodeSelector(), 1346 } 1347 1348 assert.Equal(t, want, deployment.Spec.Template.Spec) 1349 } 1350 1351 func TestReconcileArgoCD_reconcileServerDeploymentChangedToInsecure(t *testing.T) { 1352 logf.SetLogger(ZapLogger(true)) 1353 a := makeTestArgoCD() 1354 1355 resObjs := []client.Object{a} 1356 subresObjs := []client.Object{a} 1357 runtimeObjs := []runtime.Object{} 1358 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1359 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1360 r := makeTestReconciler(cl, sch) 1361 1362 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1363 1364 a = makeTestArgoCD(func(a *argoproj.ArgoCD) { 1365 a.Spec.Server.Insecure = true 1366 }) 1367 assert.NoError(t, r.reconcileServerDeployment(a, false)) 1368 1369 deployment := &appsv1.Deployment{} 1370 assert.NoError(t, r.Client.Get( 1371 context.TODO(), 1372 types.NamespacedName{ 1373 Name: "argocd-server", 1374 Namespace: a.Namespace, 1375 }, 1376 deployment)) 1377 want := corev1.PodSpec{ 1378 Containers: []corev1.Container{ 1379 { 1380 Name: "argocd-server", 1381 Image: getArgoContainerImage(a), 1382 ImagePullPolicy: corev1.PullAlways, 1383 Command: []string{ 1384 "argocd-server", 1385 "--insecure", 1386 "--staticassets", 1387 "/shared/app", 1388 "--dex-server", 1389 "https://argocd-dex-server.argocd.svc.cluster.local:5556", 1390 "--repo-server", 1391 "argocd-repo-server.argocd.svc.cluster.local:8081", 1392 "--redis", 1393 "argocd-redis.argocd.svc.cluster.local:6379", 1394 "--loglevel", 1395 "info", 1396 "--logformat", 1397 "text", 1398 }, 1399 Ports: []corev1.ContainerPort{ 1400 {ContainerPort: 8080}, 1401 {ContainerPort: 8083}, 1402 }, 1403 LivenessProbe: &corev1.Probe{ 1404 ProbeHandler: corev1.ProbeHandler{ 1405 HTTPGet: &corev1.HTTPGetAction{ 1406 Path: "/healthz", 1407 Port: intstr.FromInt(8080), 1408 }, 1409 }, 1410 InitialDelaySeconds: 3, 1411 PeriodSeconds: 30, 1412 }, 1413 ReadinessProbe: &corev1.Probe{ 1414 ProbeHandler: corev1.ProbeHandler{ 1415 HTTPGet: &corev1.HTTPGetAction{ 1416 Path: "/healthz", 1417 Port: intstr.FromInt(8080), 1418 }, 1419 }, 1420 InitialDelaySeconds: 3, 1421 PeriodSeconds: 30, 1422 }, 1423 SecurityContext: &corev1.SecurityContext{ 1424 AllowPrivilegeEscalation: boolPtr(false), 1425 Capabilities: &corev1.Capabilities{ 1426 Drop: []corev1.Capability{ 1427 "ALL", 1428 }, 1429 }, 1430 RunAsNonRoot: boolPtr(true), 1431 }, 1432 VolumeMounts: serverDefaultVolumeMounts(), 1433 }, 1434 }, 1435 Volumes: serverDefaultVolumes(), 1436 ServiceAccountName: "argocd-argocd-server", 1437 NodeSelector: common.DefaultNodeSelector(), 1438 } 1439 1440 assert.Equal(t, want, deployment.Spec.Template.Spec) 1441 } 1442 1443 func TestReconcileArgoCD_reconcileRedisDeploymentWithoutTLS(t *testing.T) { 1444 cr := makeTestArgoCD() 1445 1446 resObjs := []client.Object{cr} 1447 subresObjs := []client.Object{cr} 1448 runtimeObjs := []runtime.Object{} 1449 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1450 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1451 r := makeTestReconciler(cl, sch) 1452 1453 want := []string{ 1454 "--save", 1455 "", 1456 "--appendonly", "no", 1457 } 1458 1459 assert.NoError(t, r.reconcileRedisDeployment(cr, false)) 1460 d := &appsv1.Deployment{} 1461 assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-redis", Namespace: cr.Namespace}, d)) 1462 got := d.Spec.Template.Spec.Containers[0].Args 1463 if !reflect.DeepEqual(got, want) { 1464 t.Errorf("Reconciliation unsucessful: got: %v, want: %v", got, want) 1465 } 1466 } 1467 1468 func TestReconcileArgoCD_reconcileRedisDeploymentWithTLS(t *testing.T) { 1469 cr := makeTestArgoCD() 1470 1471 resObjs := []client.Object{cr} 1472 subresObjs := []client.Object{cr} 1473 runtimeObjs := []runtime.Object{} 1474 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1475 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1476 r := makeTestReconciler(cl, sch) 1477 1478 want := []string{ 1479 "--save", "", 1480 "--appendonly", "no", 1481 "--tls-port", "6379", 1482 "--port", "0", 1483 "--tls-cert-file", "/app/config/redis/tls/tls.crt", 1484 "--tls-key-file", "/app/config/redis/tls/tls.key", 1485 "--tls-auth-clients", "no", 1486 } 1487 1488 assert.NoError(t, r.reconcileRedisDeployment(cr, true)) 1489 d := &appsv1.Deployment{} 1490 assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-redis", Namespace: cr.Namespace}, d)) 1491 got := d.Spec.Template.Spec.Containers[0].Args 1492 if !reflect.DeepEqual(got, want) { 1493 t.Errorf("Reconciliation unsucessful: got: %v, want: %v", got, want) 1494 } 1495 } 1496 1497 func TestReconcileArgoCD_reconcileRedisDeployment(t *testing.T) { 1498 // tests reconciler hook for redis deployment 1499 cr := makeTestArgoCD() 1500 1501 resObjs := []client.Object{cr} 1502 subresObjs := []client.Object{cr} 1503 runtimeObjs := []runtime.Object{} 1504 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1505 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1506 r := makeTestReconciler(cl, sch) 1507 1508 defer resetHooks()() 1509 Register(testDeploymentHook) 1510 1511 assert.NoError(t, r.reconcileRedisDeployment(cr, false)) 1512 d := &appsv1.Deployment{} 1513 assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-redis", Namespace: cr.Namespace}, d)) 1514 assert.Equal(t, int32(3), *d.Spec.Replicas) 1515 } 1516 1517 func TestReconcileArgoCD_reconcileRedisDeployment_testImageUpgrade(t *testing.T) { 1518 // tests reconciler hook for redis deployment 1519 cr := makeTestArgoCD() 1520 1521 resObjs := []client.Object{cr} 1522 subresObjs := []client.Object{cr} 1523 runtimeObjs := []runtime.Object{} 1524 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1525 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1526 r := makeTestReconciler(cl, sch) 1527 1528 defer resetHooks()() 1529 Register(testDeploymentHook) 1530 1531 // Verify redis deployment 1532 assert.NoError(t, r.reconcileRedisDeployment(cr, false)) 1533 existing := &appsv1.Deployment{} 1534 assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-redis", Namespace: cr.Namespace}, existing)) 1535 1536 // Verify Image upgrade 1537 t.Setenv("ARGOCD_REDIS_IMAGE", "docker.io/redis/redis:latest") 1538 assert.NoError(t, r.reconcileRedisDeployment(cr, false)) 1539 1540 newRedis := &appsv1.Deployment{} 1541 assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: cr.Name + "-redis", Namespace: cr.Namespace}, newRedis)) 1542 assert.Equal(t, newRedis.Spec.Template.Spec.Containers[0].Image, "docker.io/redis/redis:latest") 1543 } 1544 1545 func TestReconcileArgoCD_reconcileRedisDeployment_with_error(t *testing.T) { 1546 // tests reconciler hook for redis deployment 1547 cr := makeTestArgoCD() 1548 1549 resObjs := []client.Object{cr} 1550 subresObjs := []client.Object{cr} 1551 runtimeObjs := []runtime.Object{} 1552 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1553 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1554 r := makeTestReconciler(cl, sch) 1555 1556 defer resetHooks()() 1557 Register(testErrorHook) 1558 1559 assert.Error(t, r.reconcileRedisDeployment(cr, false), "this is a test error") 1560 } 1561 1562 func operationProcessors(n int32) argoCDOpt { 1563 return func(a *argoproj.ArgoCD) { 1564 a.Spec.Controller.Processors.Operation = n 1565 } 1566 } 1567 1568 func Test_UpdateNodePlacement(t *testing.T) { 1569 1570 deployment := &appsv1.Deployment{ 1571 ObjectMeta: metav1.ObjectMeta{ 1572 Name: "argocd-sample-server", 1573 Namespace: testNamespace, 1574 }, 1575 Spec: appsv1.DeploymentSpec{ 1576 Template: corev1.PodTemplateSpec{ 1577 Spec: corev1.PodSpec{ 1578 NodeSelector: map[string]string{ 1579 "test_key1": "test_value1", 1580 "test_key2": "test_value2", 1581 }, 1582 Tolerations: []corev1.Toleration{ 1583 { 1584 Key: "test_key1", 1585 Value: "test_value1", 1586 Effect: corev1.TaintEffectNoSchedule, 1587 }, 1588 }, 1589 }, 1590 }, 1591 }, 1592 } 1593 deployment2 := &appsv1.Deployment{ 1594 ObjectMeta: metav1.ObjectMeta{ 1595 Name: "argocd-sample-server", 1596 Namespace: testNamespace, 1597 }, 1598 Spec: appsv1.DeploymentSpec{ 1599 Template: corev1.PodTemplateSpec{ 1600 Spec: corev1.PodSpec{ 1601 NodeSelector: map[string]string{ 1602 "test_key1": "test_value1", 1603 }, 1604 Tolerations: []corev1.Toleration{ 1605 { 1606 Key: "test_key1", 1607 Value: "test_value1", 1608 Effect: corev1.TaintEffectNoExecute, 1609 }, 1610 }, 1611 }, 1612 }, 1613 }, 1614 } 1615 expectedChange := false 1616 actualChange := false 1617 updateNodePlacement(deployment, deployment, &actualChange) 1618 if actualChange != expectedChange { 1619 t.Fatalf("updateNodePlacement failed, value of changed: %t", actualChange) 1620 } 1621 updateNodePlacement(deployment, deployment2, &actualChange) 1622 if actualChange == expectedChange { 1623 t.Fatalf("updateNodePlacement failed, value of changed: %t", actualChange) 1624 } 1625 } 1626 1627 func assertDeploymentHasProxyVars(t *testing.T, c client.Client, name string) { 1628 t.Helper() 1629 deployment := &appsv1.Deployment{} 1630 err := c.Get(context.TODO(), types.NamespacedName{ 1631 Name: name, 1632 Namespace: testNamespace, 1633 }, deployment) 1634 assert.NoError(t, err) 1635 1636 want := []corev1.EnvVar{ 1637 {Name: "HTTP_PROXY", Value: testHTTPProxy}, 1638 {Name: "HTTPS_PROXY", Value: testHTTPSProxy}, 1639 {Name: "no_proxy", Value: testNoProxy}, 1640 } 1641 for _, c := range deployment.Spec.Template.Spec.Containers { 1642 assert.Len(t, c.Env, len(want)) 1643 for _, w := range want { 1644 assert.Contains(t, c.Env, w) 1645 } 1646 } 1647 for _, c := range deployment.Spec.Template.Spec.InitContainers { 1648 assert.Len(t, c.Env, len(want)) 1649 for _, w := range want { 1650 assert.Contains(t, c.Env, w) 1651 } 1652 } 1653 } 1654 1655 func refuteDeploymentHasProxyVars(t *testing.T, c client.Client, name string) { 1656 t.Helper() 1657 deployment := &appsv1.Deployment{} 1658 err := c.Get(context.TODO(), types.NamespacedName{ 1659 Name: name, 1660 Namespace: testNamespace, 1661 }, deployment) 1662 assert.NoError(t, err) 1663 1664 names := []string{"http_proxy", "https_proxy", "no_proxy"} 1665 for _, name := range names { 1666 for _, c := range deployment.Spec.Template.Spec.Containers { 1667 for _, envVar := range c.Env { 1668 assert.NotEqual(t, strings.ToLower(envVar.Name), name) 1669 } 1670 } 1671 for _, c := range deployment.Spec.Template.Spec.InitContainers { 1672 for _, envVar := range c.Env { 1673 assert.NotEqual(t, strings.ToLower(envVar.Name), name) 1674 } 1675 } 1676 } 1677 } 1678 1679 func assertNotFound(t *testing.T, err error) { 1680 t.Helper() 1681 assert.True(t, apierrors.IsNotFound(err)) 1682 } 1683 1684 func controllerProcessors(n int32) argoCDOpt { 1685 return func(a *argoproj.ArgoCD) { 1686 a.Spec.Controller.Processors.Status = n 1687 } 1688 } 1689 1690 // repoServerVolumes returns the list of expected default volumes for the repo server 1691 func repoServerDefaultVolumes() []corev1.Volume { 1692 volumes := []corev1.Volume{ 1693 { 1694 Name: "ssh-known-hosts", 1695 VolumeSource: corev1.VolumeSource{ 1696 ConfigMap: &corev1.ConfigMapVolumeSource{ 1697 LocalObjectReference: corev1.LocalObjectReference{ 1698 Name: common.ArgoCDKnownHostsConfigMapName, 1699 }, 1700 }, 1701 }, 1702 }, 1703 { 1704 Name: "tls-certs", 1705 VolumeSource: corev1.VolumeSource{ 1706 ConfigMap: &corev1.ConfigMapVolumeSource{ 1707 LocalObjectReference: corev1.LocalObjectReference{ 1708 Name: common.ArgoCDTLSCertsConfigMapName, 1709 }, 1710 }, 1711 }, 1712 }, 1713 { 1714 Name: "gpg-keys", 1715 VolumeSource: corev1.VolumeSource{ 1716 ConfigMap: &corev1.ConfigMapVolumeSource{ 1717 LocalObjectReference: corev1.LocalObjectReference{ 1718 Name: common.ArgoCDGPGKeysConfigMapName, 1719 }, 1720 }, 1721 }, 1722 }, 1723 { 1724 Name: "gpg-keyring", 1725 VolumeSource: corev1.VolumeSource{ 1726 EmptyDir: &corev1.EmptyDirVolumeSource{}, 1727 }, 1728 }, 1729 { 1730 Name: "tmp", 1731 VolumeSource: corev1.VolumeSource{ 1732 EmptyDir: &corev1.EmptyDirVolumeSource{}, 1733 }, 1734 }, 1735 { 1736 Name: "argocd-repo-server-tls", 1737 VolumeSource: corev1.VolumeSource{ 1738 Secret: &corev1.SecretVolumeSource{ 1739 SecretName: common.ArgoCDRepoServerTLSSecretName, 1740 Optional: boolPtr(true), 1741 }, 1742 }, 1743 }, 1744 { 1745 Name: common.ArgoCDRedisServerTLSSecretName, 1746 VolumeSource: corev1.VolumeSource{ 1747 Secret: &corev1.SecretVolumeSource{ 1748 SecretName: common.ArgoCDRedisServerTLSSecretName, 1749 Optional: boolPtr(true), 1750 }, 1751 }, 1752 }, 1753 { 1754 Name: "var-files", 1755 VolumeSource: corev1.VolumeSource{ 1756 EmptyDir: &corev1.EmptyDirVolumeSource{}, 1757 }, 1758 }, 1759 { 1760 Name: "plugins", 1761 VolumeSource: corev1.VolumeSource{ 1762 EmptyDir: &corev1.EmptyDirVolumeSource{}, 1763 }, 1764 }, 1765 } 1766 return volumes 1767 } 1768 1769 // repoServerDefaultVolumeMounts return the default volume mounts for the repo server 1770 func repoServerDefaultVolumeMounts() []corev1.VolumeMount { 1771 mounts := []corev1.VolumeMount{ 1772 {Name: "ssh-known-hosts", MountPath: "/app/config/ssh"}, 1773 {Name: "tls-certs", MountPath: "/app/config/tls"}, 1774 {Name: "gpg-keys", MountPath: "/app/config/gpg/source"}, 1775 {Name: "gpg-keyring", MountPath: "/app/config/gpg/keys"}, 1776 {Name: "tmp", MountPath: "/tmp"}, 1777 {Name: "argocd-repo-server-tls", MountPath: "/app/config/reposerver/tls"}, 1778 {Name: common.ArgoCDRedisServerTLSSecretName, MountPath: "/app/config/reposerver/tls/redis"}, 1779 {Name: "plugins", MountPath: "/home/argocd/cmp-server/plugins"}, 1780 } 1781 return mounts 1782 } 1783 1784 func serverDefaultVolumes() []corev1.Volume { 1785 volumes := []corev1.Volume{ 1786 { 1787 Name: "ssh-known-hosts", 1788 VolumeSource: corev1.VolumeSource{ 1789 ConfigMap: &corev1.ConfigMapVolumeSource{ 1790 LocalObjectReference: corev1.LocalObjectReference{ 1791 Name: common.ArgoCDKnownHostsConfigMapName, 1792 }, 1793 }, 1794 }, 1795 }, 1796 { 1797 Name: "tls-certs", 1798 VolumeSource: corev1.VolumeSource{ 1799 ConfigMap: &corev1.ConfigMapVolumeSource{ 1800 LocalObjectReference: corev1.LocalObjectReference{ 1801 Name: common.ArgoCDTLSCertsConfigMapName, 1802 }, 1803 }, 1804 }, 1805 }, 1806 { 1807 Name: "argocd-repo-server-tls", 1808 VolumeSource: corev1.VolumeSource{ 1809 Secret: &corev1.SecretVolumeSource{ 1810 SecretName: common.ArgoCDRepoServerTLSSecretName, 1811 Optional: boolPtr(true), 1812 }, 1813 }, 1814 }, 1815 { 1816 Name: common.ArgoCDRedisServerTLSSecretName, 1817 VolumeSource: corev1.VolumeSource{ 1818 Secret: &corev1.SecretVolumeSource{ 1819 SecretName: common.ArgoCDRedisServerTLSSecretName, 1820 Optional: boolPtr(true), 1821 }, 1822 }, 1823 }, 1824 } 1825 return volumes 1826 } 1827 1828 func serverDefaultVolumeMounts() []corev1.VolumeMount { 1829 mounts := []corev1.VolumeMount{ 1830 { 1831 Name: "ssh-known-hosts", 1832 MountPath: "/app/config/ssh", 1833 }, { 1834 Name: "tls-certs", 1835 MountPath: "/app/config/tls", 1836 }, { 1837 Name: "argocd-repo-server-tls", 1838 MountPath: "/app/config/server/tls", 1839 }, { 1840 Name: common.ArgoCDRedisServerTLSSecretName, 1841 MountPath: "/app/config/server/tls/redis", 1842 }, 1843 } 1844 return mounts 1845 } 1846 1847 func TestReconcileArgoCD_reconcile_RepoServerChanges(t *testing.T) { 1848 logf.SetLogger(ZapLogger(true)) 1849 1850 tests := []struct { 1851 name string 1852 mountSAToken bool 1853 serviceAccount string 1854 }{ 1855 { 1856 name: "default Deployment", 1857 mountSAToken: false, 1858 serviceAccount: "default", 1859 }, 1860 { 1861 name: "change Service Account and mountSAToken", 1862 mountSAToken: true, 1863 serviceAccount: "argocd-argocd-server", 1864 }, 1865 } 1866 1867 for _, test := range tests { 1868 t.Run(test.name, func(t *testing.T) { 1869 1870 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 1871 a.Spec.Repo.MountSAToken = test.mountSAToken 1872 a.Spec.Repo.ServiceAccount = test.serviceAccount 1873 }) 1874 1875 resObjs := []client.Object{a} 1876 subresObjs := []client.Object{a} 1877 runtimeObjs := []runtime.Object{} 1878 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1879 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1880 r := makeTestReconciler(cl, sch) 1881 1882 sa := &corev1.ServiceAccount{ 1883 ObjectMeta: metav1.ObjectMeta{ 1884 Name: test.serviceAccount, 1885 Namespace: a.Namespace, 1886 Labels: argoutil.LabelsForCluster(a), 1887 }, 1888 } 1889 r.Client.Create(context.TODO(), sa) 1890 err := r.reconcileRepoDeployment(a, false) 1891 assert.NoError(t, err) 1892 1893 deployment := &appsv1.Deployment{} 1894 err = r.Client.Get(context.TODO(), types.NamespacedName{ 1895 Name: "argocd-repo-server", 1896 Namespace: testNamespace, 1897 }, deployment) 1898 assert.NoError(t, err) 1899 assert.Equal(t, &test.mountSAToken, deployment.Spec.Template.Spec.AutomountServiceAccountToken) 1900 assert.Equal(t, test.serviceAccount, deployment.Spec.Template.Spec.ServiceAccountName) 1901 }) 1902 } 1903 } 1904 1905 func TestArgoCDRepoServerDeploymentCommand(t *testing.T) { 1906 a := makeTestArgoCD() 1907 1908 resObjs := []client.Object{a} 1909 subresObjs := []client.Object{a} 1910 runtimeObjs := []runtime.Object{} 1911 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 1912 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 1913 r := makeTestReconciler(cl, sch) 1914 1915 testRedisServerAddress := getRedisServerAddress(a) 1916 1917 baseCommand := []string{ 1918 "uid_entrypoint.sh", 1919 "argocd-repo-server", 1920 "--redis", 1921 testRedisServerAddress, 1922 "--loglevel", 1923 "info", 1924 "--logformat", 1925 "text", 1926 } 1927 1928 // When a single command argument is passed 1929 a.Spec.Repo.ExtraRepoCommandArgs = []string{ 1930 "--reposerver.max.combined.directory.manifests.size", 1931 "10M", 1932 } 1933 1934 deployment := &appsv1.Deployment{} 1935 assert.NoError(t, r.reconcileRepoDeployment(a, false)) 1936 1937 assert.NoError(t, r.Client.Get( 1938 context.TODO(), 1939 types.NamespacedName{ 1940 Name: "argocd-repo-server", 1941 Namespace: a.Namespace, 1942 }, 1943 deployment)) 1944 1945 cmd := append(baseCommand, 1946 "--reposerver.max.combined.directory.manifests.size", "10M") 1947 assert.Equal(t, cmd, deployment.Spec.Template.Spec.Containers[0].Command) 1948 1949 // When multiple command arguments are passed 1950 a.Spec.Repo.ExtraRepoCommandArgs = []string{ 1951 "--reposerver.max.combined.directory.manifests.size", 1952 "10M", 1953 "--foo", 1954 "bar", 1955 "test", 1956 } 1957 1958 assert.NoError(t, r.reconcileRepoDeployment(a, false)) 1959 assert.NoError(t, r.Client.Get( 1960 context.TODO(), 1961 types.NamespacedName{ 1962 Name: "argocd-repo-server", 1963 Namespace: a.Namespace, 1964 }, 1965 deployment)) 1966 1967 cmd = append(cmd, "--foo", "bar", "test") 1968 assert.Equal(t, cmd, deployment.Spec.Template.Spec.Containers[0].Command) 1969 1970 // When one of the ExtraCommandArgs already exists in cmd with same or different value 1971 a.Spec.Repo.ExtraRepoCommandArgs = []string{ 1972 "--redis", 1973 "foo.scv.cluster.local:6379", 1974 } 1975 1976 assert.NoError(t, r.reconcileRepoDeployment(a, false)) 1977 assert.NoError(t, r.Client.Get( 1978 context.TODO(), 1979 types.NamespacedName{ 1980 Name: "argocd-repo-server", 1981 Namespace: a.Namespace, 1982 }, 1983 deployment)) 1984 1985 assert.Equal(t, baseCommand, deployment.Spec.Template.Spec.Containers[0].Command) 1986 1987 // Remove all the command arguments that were added. 1988 a.Spec.Repo.ExtraRepoCommandArgs = []string{} 1989 1990 assert.NoError(t, r.reconcileRepoDeployment(a, false)) 1991 assert.NoError(t, r.Client.Get( 1992 context.TODO(), 1993 types.NamespacedName{ 1994 Name: "argocd-repo-server", 1995 Namespace: a.Namespace, 1996 }, 1997 deployment)) 1998 1999 assert.Equal(t, baseCommand, deployment.Spec.Template.Spec.Containers[0].Command) 2000 } 2001 2002 func TestReconcileArgoCD_reconcileRepoDeployment_serviceAccount(t *testing.T) { 2003 logf.SetLogger(ZapLogger(true)) 2004 2005 tests := []struct { 2006 testName string 2007 serviceAccountName string 2008 expectedServiceAccountName string 2009 isServiceAccountNameChanged bool 2010 newServiceAccountName string 2011 newExpectedServiceAccountName string 2012 }{ 2013 { 2014 testName: "serviceAccountName field in the spec should reflect provided value", 2015 serviceAccountName: "deployer", 2016 expectedServiceAccountName: "deployer", 2017 }, { 2018 testName: "serviceAccountName field in the spec should have updated value", 2019 serviceAccountName: "deployer", 2020 expectedServiceAccountName: "deployer", 2021 isServiceAccountNameChanged: true, 2022 newServiceAccountName: "builder", 2023 newExpectedServiceAccountName: "builder", 2024 }, { 2025 testName: "Empty serviceAccountName field in the spec should have updated value", 2026 serviceAccountName: "", 2027 expectedServiceAccountName: "", 2028 isServiceAccountNameChanged: true, 2029 newServiceAccountName: "builder", 2030 newExpectedServiceAccountName: "builder", 2031 }, { 2032 testName: "serviceAccountName field in the spec should be changed to empty", 2033 serviceAccountName: "builder", 2034 expectedServiceAccountName: "builder", 2035 isServiceAccountNameChanged: true, 2036 newServiceAccountName: "", 2037 newExpectedServiceAccountName: "", 2038 }, 2039 } 2040 2041 for _, test := range tests { 2042 t.Run(test.testName, func(t *testing.T) { 2043 2044 a := makeTestArgoCD(func(a *argoproj.ArgoCD) { 2045 a.Spec.Repo.ServiceAccount = test.serviceAccountName 2046 }) 2047 2048 resObjs := []client.Object{a} 2049 subresObjs := []client.Object{a} 2050 runtimeObjs := []runtime.Object{} 2051 sch := makeTestReconcilerScheme(argoproj.AddToScheme) 2052 cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs) 2053 r := makeTestReconciler(cl, sch) 2054 2055 err := r.reconcileRepoDeployment(a, false) 2056 assert.NoError(t, err) 2057 2058 deployment := &appsv1.Deployment{} 2059 key := types.NamespacedName{ 2060 Name: "argocd-repo-server", 2061 Namespace: testNamespace, 2062 } 2063 2064 err = r.Client.Get(context.TODO(), key, deployment) 2065 2066 assert.NoError(t, err) 2067 assert.Equal(t, test.expectedServiceAccountName, deployment.Spec.Template.Spec.ServiceAccountName) 2068 2069 // check if SA name is changed 2070 if test.isServiceAccountNameChanged { 2071 2072 a.Spec.Repo.ServiceAccount = test.newServiceAccountName 2073 2074 err = r.reconcileRepoDeployment(a, false) 2075 assert.NoError(t, err) 2076 2077 err = r.Client.Get(context.TODO(), key, deployment) 2078 2079 assert.NoError(t, err) 2080 assert.Equal(t, test.newExpectedServiceAccountName, deployment.Spec.Template.Spec.ServiceAccountName) 2081 } 2082 }) 2083 } 2084 }