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  }