github.com/verrazzano/verrazzano@v1.7.0/cluster-operator/controllers/vmc/argocd_test.go (about)

     1  // Copyright (c) 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package vmc
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"io"
    10  	"net/http"
    11  	"os"
    12  	"testing"
    13  	"time"
    14  
    15  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    16  	"k8s.io/apimachinery/pkg/runtime"
    17  	"k8s.io/apimachinery/pkg/runtime/schema"
    18  
    19  	"github.com/Jeffail/gabs/v2"
    20  	"github.com/golang/mock/gomock"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    23  	"github.com/verrazzano/verrazzano/pkg/constants"
    24  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    25  	"github.com/verrazzano/verrazzano/pkg/rancherutil"
    26  	"github.com/verrazzano/verrazzano/pkg/test/mockmatchers"
    27  	"github.com/verrazzano/verrazzano/platform-operator/mocks"
    28  	corev1 "k8s.io/api/core/v1"
    29  	networkv1 "k8s.io/api/networking/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/util/wait"
    32  	"sigs.k8s.io/controller-runtime/pkg/client"
    33  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    34  )
    35  
    36  const (
    37  	tokensPath = "/v3/tokens"
    38  	clusterID  = "cluster-id"
    39  	rancherURL = "https://rancher-url"
    40  )
    41  
    42  // TestMutateArgoCDClusterSecretWithoutRefresh tests no POST call to obtain new token when we are within 3/4 lifespan of the token
    43  // GIVEN a call to mutateArgCDClusterSecret
    44  //
    45  //	WHEN the secret annotation createTimestamp/expiresAtTimestamp is x(s) and x+4(s) respectively
    46  //	and mutateArgoCDClusterSecret is called immediately
    47  //	THEN we skip obtaining new token
    48  func TestMutateArgoCDClusterSecretWithoutRefresh(t *testing.T) {
    49  	// clear any cached user auth tokens when the test completes
    50  	defer rancherutil.DeleteStoredTokens()
    51  
    52  	cli := generateClientObject()
    53  	log := vzlog.DefaultLogger()
    54  
    55  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
    56  	defer func() {
    57  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
    58  	}()
    59  
    60  	savedRetry := rancherutil.DefaultRetry
    61  	defer func() {
    62  		rancherutil.DefaultRetry = savedRetry
    63  	}()
    64  	rancherutil.DefaultRetry = wait.Backoff{
    65  		Steps:    1,
    66  		Duration: 1 * time.Millisecond,
    67  		Factor:   1.0,
    68  		Jitter:   0.1,
    69  	}
    70  
    71  	vmc := &v1alpha1.VerrazzanoManagedCluster{
    72  		ObjectMeta: metav1.ObjectMeta{
    73  			Namespace: constants.VerrazzanoMultiClusterNamespace,
    74  			Name:      "cluster",
    75  		},
    76  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
    77  			RancherRegistration: v1alpha1.RancherRegistration{
    78  				ClusterID: clusterID,
    79  			},
    80  		},
    81  	}
    82  	r := &VerrazzanoManagedClusterReconciler{
    83  		Client: cli,
    84  		log:    vzlog.DefaultLogger(),
    85  	}
    86  	secret := &corev1.Secret{
    87  		ObjectMeta: metav1.ObjectMeta{
    88  			Name:        "demo" + "-" + clusterSecretName,
    89  			Namespace:   constants.ArgoCDNamespace,
    90  			Annotations: map[string]string{createTimestamp: time.Now().Format(time.RFC3339), expiresAtTimestamp: time.Now().Add(10 * time.Hour).Format(time.RFC3339)},
    91  		},
    92  		Data: map[string][]byte{
    93  			"password": []byte("foobar"),
    94  		},
    95  	}
    96  
    97  	mocker := gomock.NewController(t)
    98  	httpMock := mocks.NewMockRequestSender(mocker)
    99  	// Expect an HTTP request to fetch the token from Rancher only
   100  	expectHTTPLoginRequests(httpMock)
   101  	rancherutil.RancherHTTPClient = httpMock
   102  
   103  	caData := []byte("ca")
   104  
   105  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   106  	assert.NoError(t, err)
   107  
   108  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterID, rancherURL, caData)
   109  	assert.NoError(t, err)
   110  
   111  	var rancherConfig ArgoCDRancherConfig
   112  	err = json.Unmarshal([]byte(secret.StringData["config"]), &rancherConfig)
   113  	if err != nil {
   114  		assert.Equal(t, &rancherConfig.BearerToken, "unit-test-token")
   115  	}
   116  }
   117  
   118  // TestMutateArgoCDClusterSecretWithRefresh tests POST/GET calls to obtain new token and attrs when we breach 3/4 lifespan of the token
   119  // GIVEN a call to mutateArgoCDClusterSecret
   120  //
   121  //	WHEN the secret annotation createTimestamp/expiresAtTimestamp is x(s) and x+4(s) respectively
   122  //	and we sleep for 4(s)
   123  //	THEN we obtain new token and the annotation createTimestamp/expiresAtTimestamp are updated accordingly
   124  func TestMutateArgoCDClusterSecretWithRefresh(t *testing.T) {
   125  	// clear any cached user auth tokens when the test completes
   126  	defer rancherutil.DeleteStoredTokens()
   127  
   128  	cli := generateClientObject()
   129  	log := vzlog.DefaultLogger()
   130  
   131  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   132  	defer func() {
   133  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   134  	}()
   135  
   136  	savedRetry := rancherutil.DefaultRetry
   137  	defer func() {
   138  		rancherutil.DefaultRetry = savedRetry
   139  	}()
   140  	rancherutil.DefaultRetry = wait.Backoff{
   141  		Steps:    1,
   142  		Duration: 1 * time.Millisecond,
   143  		Factor:   1.0,
   144  		Jitter:   0.1,
   145  	}
   146  
   147  	vmc := &v1alpha1.VerrazzanoManagedCluster{
   148  		ObjectMeta: metav1.ObjectMeta{
   149  			Namespace: constants.VerrazzanoMultiClusterNamespace,
   150  			Name:      "cluster",
   151  		},
   152  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
   153  			RancherRegistration: v1alpha1.RancherRegistration{
   154  				ClusterID: clusterID,
   155  			},
   156  		},
   157  	}
   158  	r := &VerrazzanoManagedClusterReconciler{
   159  		Client: cli,
   160  		log:    vzlog.DefaultLogger(),
   161  	}
   162  
   163  	secret := &corev1.Secret{
   164  		ObjectMeta: metav1.ObjectMeta{
   165  			Name:        "demo" + "-" + clusterSecretName,
   166  			Namespace:   constants.ArgoCDNamespace,
   167  			Annotations: map[string]string{createTimestamp: time.Now().Add(-10 * time.Hour).Format(time.RFC3339), expiresAtTimestamp: time.Now().Format(time.RFC3339)},
   168  		},
   169  		Data: map[string][]byte{
   170  			"password": []byte("foobar"),
   171  		},
   172  	}
   173  
   174  	mocker := gomock.NewController(t)
   175  	httpMock := mocks.NewMockRequestSender(mocker)
   176  	httpMock = expectHTTPRequests(httpMock)
   177  	rancherutil.RancherHTTPClient = httpMock
   178  
   179  	caData := []byte("ca")
   180  
   181  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   182  	assert.NoError(t, err)
   183  
   184  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterID, rancherURL, caData)
   185  	assert.NoError(t, err)
   186  }
   187  
   188  // TestMutateArgoCDClusterSecretNoTokenMatch tests a call to the reconciler when a token has a create timestamp annotation, but not an expired annotation and assures that a new token is created
   189  // Given a call to TestMutateArgoCDClusterSecretNoTokenMatch
   190  // When a secret annotation has a create timestamp annotation and not an existing timestamp annotation
   191  // Then a new token is created without any error
   192  func TestMutateArgoCDClusterSecretNoTokenMatch(t *testing.T) {
   193  	// clear any cached user auth tokens when the test completes
   194  	defer rancherutil.DeleteStoredTokens()
   195  
   196  	cli := generateClientObject()
   197  	log := vzlog.DefaultLogger()
   198  
   199  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   200  	defer func() {
   201  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   202  	}()
   203  
   204  	savedRetry := rancherutil.DefaultRetry
   205  	defer func() {
   206  		rancherutil.DefaultRetry = savedRetry
   207  	}()
   208  	rancherutil.DefaultRetry = wait.Backoff{
   209  		Steps:    1,
   210  		Duration: 1 * time.Millisecond,
   211  		Factor:   1.0,
   212  		Jitter:   0.1,
   213  	}
   214  
   215  	loginURIPath := loginURLParts[0]
   216  	testBodyForTokens, _ := os.Open("testdata/bodyfortokentest.json")
   217  	arrayBytes, _ := io.ReadAll(testBodyForTokens)
   218  	clusterIDForTest := "clusteridfortest"
   219  
   220  	mocker := gomock.NewController(t)
   221  	httpMock := mocks.NewMockRequestSender(mocker)
   222  	httpMock.EXPECT().
   223  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
   224  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   225  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
   226  			resp := &http.Response{
   227  				StatusCode: http.StatusCreated,
   228  				Body:       r,
   229  				Request:    &http.Request{Method: http.MethodPost},
   230  			}
   231  			return resp, nil
   232  		}).Times(1)
   233  
   234  	// This is the request to get tokens for the cluster and the user
   235  	httpMock.EXPECT().
   236  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodGet, tokensPath)).
   237  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   238  			var resp *http.Response
   239  			r := io.NopCloser(bytes.NewReader([]byte(arrayBytes)))
   240  			resp = &http.Response{
   241  				StatusCode: http.StatusOK,
   242  				Body:       r,
   243  			}
   244  			return resp, nil
   245  		}).Times(1)
   246  	// This is the request to create a new token
   247  	httpMock.EXPECT().
   248  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodPost, tokensPath)).
   249  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   250  			body, err := io.ReadAll(req.Body)
   251  			assert.NoError(t, err)
   252  			jsonString, err := gabs.ParseJSON(body)
   253  			assert.NoError(t, err)
   254  			_, ok := jsonString.Path("clusterID").Data().(string)
   255  			assert.True(t, ok)
   256  			_, ok = jsonString.Path("ttl").Data().(float64)
   257  			assert.True(t, ok)
   258  			var resp *http.Response
   259  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"testoken", "Created": "2023-08-13T15:32:38Z"}`)))
   260  			resp = &http.Response{
   261  				StatusCode: http.StatusCreated,
   262  				Body:       r,
   263  			}
   264  			return resp, nil
   265  		}).Times(1)
   266  
   267  	vmc := &v1alpha1.VerrazzanoManagedCluster{
   268  		ObjectMeta: metav1.ObjectMeta{
   269  			Namespace: constants.VerrazzanoMultiClusterNamespace,
   270  			Name:      "cluster",
   271  		},
   272  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
   273  			RancherRegistration: v1alpha1.RancherRegistration{
   274  				ClusterID: clusterID,
   275  			},
   276  		},
   277  	}
   278  	r := &VerrazzanoManagedClusterReconciler{
   279  		Client: cli,
   280  		log:    vzlog.DefaultLogger(),
   281  	}
   282  
   283  	secret := &corev1.Secret{
   284  		ObjectMeta: metav1.ObjectMeta{
   285  			Name:        "demo" + "-" + clusterSecretName,
   286  			Namespace:   constants.ArgoCDNamespace,
   287  			Annotations: map[string]string{createTimestamp: time.Now().Add(-10 * time.Hour).Format(time.RFC3339)},
   288  		},
   289  		Data: map[string][]byte{
   290  			"password": []byte("foobar"),
   291  		},
   292  	}
   293  	rancherutil.RancherHTTPClient = httpMock
   294  
   295  	caData := []byte("ca")
   296  
   297  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   298  	assert.NoError(t, err)
   299  	initalTimestamp := secret.Annotations[createTimestamp]
   300  
   301  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterIDForTest, rancherURL, caData)
   302  	newTimestamp := secret.Annotations[createTimestamp]
   303  	assert.NoError(t, err)
   304  	assert.NotEqual(t, newTimestamp, initalTimestamp)
   305  	assert.Empty(t, secret.Annotations[expiresAtTimestamp])
   306  }
   307  
   308  func expectHTTPLoginRequests(httpMock *mocks.MockRequestSender) *mocks.MockRequestSender {
   309  	httpMock.EXPECT().
   310  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
   311  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   312  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
   313  			resp := &http.Response{
   314  				StatusCode: http.StatusCreated,
   315  				Body:       r,
   316  				Request:    &http.Request{Method: http.MethodPost},
   317  			}
   318  			return resp, nil
   319  		})
   320  	return httpMock
   321  }
   322  
   323  func expectHTTPClusterRoleTemplateUpdateRequests(httpMock *mocks.MockRequestSender) *mocks.MockRequestSender {
   324  	httpMock.EXPECT().
   325  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodPost, clusterroletemplatebindingsPath)).
   326  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   327  			r := io.NopCloser(bytes.NewReader([]byte(`{}`)))
   328  			resp := &http.Response{
   329  				StatusCode: http.StatusCreated,
   330  				Body:       r,
   331  				Request:    &http.Request{Method: http.MethodPost},
   332  			}
   333  			return resp, nil
   334  		})
   335  	httpMock.EXPECT().
   336  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodGet, clusterroletemplatebindingsPath)).
   337  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   338  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[]}`)))
   339  			resp := &http.Response{
   340  				StatusCode: http.StatusOK,
   341  				Body:       r,
   342  				Request:    &http.Request{Method: http.MethodGet},
   343  			}
   344  			return resp, nil
   345  		})
   346  	return httpMock
   347  }
   348  
   349  func expectHTTPRequests(httpMock *mocks.MockRequestSender) *mocks.MockRequestSender {
   350  	// Expect an HTTP request to obtain a new token
   351  	httpMock.EXPECT().
   352  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(tokensPath)).
   353  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   354  			var resp *http.Response
   355  			r := io.NopCloser(bytes.NewReader([]byte(`{"token": "xxx", "name": "testToken"}`)))
   356  			resp = &http.Response{
   357  				StatusCode: http.StatusCreated,
   358  				Body:       r,
   359  				Request:    &http.Request{Method: http.MethodPost},
   360  			}
   361  			return resp, nil
   362  		})
   363  
   364  	// Expect an HTTP request to fetch the token from Rancher
   365  	expectHTTPLoginRequests(httpMock)
   366  	return httpMock
   367  }
   368  
   369  func generateClientObject(objs ...runtime.Object) client.WithWatch {
   370  	user := unstructured.Unstructured{}
   371  	user.SetUnstructuredContent(map[string]interface{}{UserUsernameAttribute: constants.ArgoCDClusterRancherUsername})
   372  	user.SetGroupVersionKind(schema.GroupVersionKind{
   373  		Group:   APIGroupRancherManagement,
   374  		Version: APIGroupVersionRancherManagement,
   375  		Kind:    UserKind,
   376  	})
   377  
   378  	totalObjects := []runtime.Object{
   379  		&corev1.Secret{
   380  			ObjectMeta: metav1.ObjectMeta{
   381  				Name:      constants.ArgoCDClusterRancherSecretName,
   382  				Namespace: constants.VerrazzanoMultiClusterNamespace,
   383  			},
   384  			Data: map[string][]byte{
   385  				"password": []byte("foobar"),
   386  			},
   387  		},
   388  		&corev1.Secret{
   389  			ObjectMeta: metav1.ObjectMeta{
   390  				Namespace: "cattle-system",
   391  				Name:      "rancher-admin-secret",
   392  			},
   393  			Data: map[string][]byte{
   394  				"password": []byte(""),
   395  			},
   396  		},
   397  		&networkv1.Ingress{
   398  			ObjectMeta: metav1.ObjectMeta{
   399  				Namespace: rancherNamespace,
   400  				Name:      rancherIngressName,
   401  			},
   402  			Spec: networkv1.IngressSpec{
   403  				Rules: []networkv1.IngressRule{
   404  					{
   405  						Host: "test-rancher.com",
   406  					},
   407  				},
   408  			},
   409  		},
   410  		user.DeepCopyObject(),
   411  	}
   412  	totalObjects = append(totalObjects, objs...)
   413  	return fake.NewClientBuilder().WithRuntimeObjects(totalObjects...).Build()
   414  }
   415  
   416  // TestUpdateArgoCDClusterRoleBindingTemplate tests the update of cluster role for 'vz-argocd-reg' user
   417  // GIVEN a call to update argocd cluster role binding
   418  //
   419  //	THEN the template binding is created/updated via API with no error
   420  func TestUpdateArgoCDClusterRoleBindingTemplate(t *testing.T) {
   421  	a := assert.New(t)
   422  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   423  	defer func() {
   424  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   425  	}()
   426  
   427  	savedRetry := rancherutil.DefaultRetry
   428  	defer func() {
   429  		rancherutil.DefaultRetry = savedRetry
   430  	}()
   431  	rancherutil.DefaultRetry = wait.Backoff{
   432  		Steps:    1,
   433  		Duration: 1 * time.Millisecond,
   434  		Factor:   1.0,
   435  		Jitter:   0.1,
   436  	}
   437  
   438  	mocker := gomock.NewController(t)
   439  	httpMock := mocks.NewMockRequestSender(mocker)
   440  	httpMock = expectHTTPLoginRequests(httpMock)
   441  	httpMock = expectHTTPClusterRoleTemplateUpdateRequests(httpMock)
   442  	rancherutil.RancherHTTPClient = httpMock
   443  
   444  	vmcID := &v1alpha1.VerrazzanoManagedCluster{}
   445  
   446  	clusterID := "testID"
   447  	vmcID.Status.RancherRegistration.ClusterID = clusterID
   448  
   449  	clusterUserData := &unstructured.Unstructured{}
   450  	clusterUserData.SetGroupVersionKind(schema.GroupVersionKind{
   451  		Group:   APIGroupRancherManagement,
   452  		Version: APIGroupVersionRancherManagement,
   453  		Kind:    UserKind,
   454  	})
   455  	clusterUserData.SetName(constants.ArgoCDClusterRancherUsername)
   456  	data := clusterUserData.UnstructuredContent()
   457  	data[UserUsernameAttribute] = constants.ArgoCDClusterRancherUsername
   458  
   459  	tests := []struct {
   460  		name string
   461  		vmc  *v1alpha1.VerrazzanoManagedCluster
   462  		user *unstructured.Unstructured
   463  	}{
   464  		{
   465  			name: "test vmc with cluster id",
   466  			vmc:  vmcID,
   467  			user: clusterUserData,
   468  		},
   469  	}
   470  	for _, tt := range tests {
   471  		t.Run(tt.name, func(t *testing.T) {
   472  			cli := generateClientObject(clusterUserData)
   473  
   474  			r := &VerrazzanoManagedClusterReconciler{
   475  				Client: cli,
   476  				log:    vzlog.DefaultLogger(),
   477  			}
   478  			rc, err := rancherutil.NewAdminRancherConfig(cli, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
   479  			assert.NoError(t, err)
   480  
   481  			err = r.updateArgoCDClusterRoleBindingTemplate(rc, tt.vmc)
   482  			a.NoError(err)
   483  		})
   484  	}
   485  }
   486  
   487  // TestMutateArgoCDSecretThatExistingLabelDoesNotGetRemovedandClusterSecretLabelIsAdded tests the update of the ArgoCD Cluster Secret for a user when an existing label is present, but the cluster label is not present
   488  // GIVEN a call to update the ArgoCD Cluster Secret when the secret has a user provided label, but does not have the ArgoCD provided cluster label
   489  //
   490  //	THEN the ArgoCD cluster secret is created/updated via API with no error and the existing label remains, but the ArgoCD cluster label is added
   491  func TestMutateArgoCDClusterSecretThatExistingLabelDoesNotGetRemovedandClusterSecretLabelIsAdded(t *testing.T) {
   492  	// clear any cached user auth tokens when the test completes
   493  	defer rancherutil.DeleteStoredTokens()
   494  
   495  	cli := generateClientObject()
   496  	log := vzlog.DefaultLogger()
   497  
   498  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   499  	defer func() {
   500  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   501  	}()
   502  
   503  	savedRetry := rancherutil.DefaultRetry
   504  	defer func() {
   505  		rancherutil.DefaultRetry = savedRetry
   506  	}()
   507  	rancherutil.DefaultRetry = wait.Backoff{
   508  		Steps:    1,
   509  		Duration: 1 * time.Millisecond,
   510  		Factor:   1.0,
   511  		Jitter:   0.1,
   512  	}
   513  
   514  	vmc := &v1alpha1.VerrazzanoManagedCluster{
   515  		ObjectMeta: metav1.ObjectMeta{
   516  			Namespace: constants.VerrazzanoMultiClusterNamespace,
   517  			Name:      "cluster",
   518  		},
   519  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
   520  			RancherRegistration: v1alpha1.RancherRegistration{
   521  				ClusterID: clusterID,
   522  			},
   523  		},
   524  	}
   525  	r := &VerrazzanoManagedClusterReconciler{
   526  		Client: cli,
   527  		log:    vzlog.DefaultLogger(),
   528  	}
   529  
   530  	secret := &corev1.Secret{
   531  		ObjectMeta: metav1.ObjectMeta{
   532  			Name:        "demo" + "-" + clusterSecretName,
   533  			Namespace:   constants.ArgoCDNamespace,
   534  			Annotations: map[string]string{createTimestamp: time.Now().Add(-10 * time.Hour).Format(time.RFC3339), expiresAtTimestamp: time.Now().Format(time.RFC3339)},
   535  			Labels:      map[string]string{"testlabel": "shouldnotbedeleted"},
   536  		},
   537  		Data: map[string][]byte{
   538  			"password": []byte("foobar"),
   539  		},
   540  	}
   541  
   542  	mocker := gomock.NewController(t)
   543  	httpMock := mocks.NewMockRequestSender(mocker)
   544  	httpMock = expectHTTPRequests(httpMock)
   545  	rancherutil.RancherHTTPClient = httpMock
   546  
   547  	caData := []byte("ca")
   548  
   549  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   550  	assert.NoError(t, err)
   551  
   552  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterID, rancherURL, caData)
   553  	assert.NoError(t, err)
   554  	assert.Equal(t, secret.Labels, map[string]string{"testlabel": "shouldnotbedeleted", "argocd.argoproj.io/secret-type": "cluster"})
   555  }
   556  
   557  // TestMutateArgoCDClusterSecretThatClusterSecretLabelIsAdded tests the update of the ArgoCD Cluster Secret for a user when there are no labels present in the cluster secret
   558  // GIVEN a call to update the ArgoCD Cluster Secret when the secret does not have the ArgoCD provided cluster label/a label at all
   559  //
   560  //	THEN the ArgoCD cluster secret is created/updated via API with no error and the ArgoCD cluster label is added
   561  func TestMutateArgoCDClusterSecretThatClusterSecretLabelIsAdded(t *testing.T) {
   562  	// clear any cached user auth tokens when the test completes
   563  	defer rancherutil.DeleteStoredTokens()
   564  
   565  	cli := generateClientObject()
   566  	log := vzlog.DefaultLogger()
   567  
   568  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   569  	defer func() {
   570  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   571  	}()
   572  
   573  	savedRetry := rancherutil.DefaultRetry
   574  	defer func() {
   575  		rancherutil.DefaultRetry = savedRetry
   576  	}()
   577  	rancherutil.DefaultRetry = wait.Backoff{
   578  		Steps:    1,
   579  		Duration: 1 * time.Millisecond,
   580  		Factor:   1.0,
   581  		Jitter:   0.1,
   582  	}
   583  
   584  	vmc := &v1alpha1.VerrazzanoManagedCluster{
   585  		ObjectMeta: metav1.ObjectMeta{
   586  			Namespace: constants.VerrazzanoMultiClusterNamespace,
   587  			Name:      "cluster",
   588  		},
   589  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
   590  			RancherRegistration: v1alpha1.RancherRegistration{
   591  				ClusterID: clusterID,
   592  			},
   593  		},
   594  	}
   595  	r := &VerrazzanoManagedClusterReconciler{
   596  		Client: cli,
   597  		log:    vzlog.DefaultLogger(),
   598  	}
   599  
   600  	secret := &corev1.Secret{
   601  		ObjectMeta: metav1.ObjectMeta{
   602  			Name:        "demo" + "-" + clusterSecretName,
   603  			Namespace:   constants.ArgoCDNamespace,
   604  			Annotations: map[string]string{createTimestamp: time.Now().Add(-10 * time.Hour).Format(time.RFC3339), expiresAtTimestamp: time.Now().Format(time.RFC3339)},
   605  		},
   606  		Data: map[string][]byte{
   607  			"password": []byte("foobar"),
   608  		},
   609  	}
   610  
   611  	mocker := gomock.NewController(t)
   612  	httpMock := mocks.NewMockRequestSender(mocker)
   613  	httpMock = expectHTTPRequests(httpMock)
   614  	rancherutil.RancherHTTPClient = httpMock
   615  
   616  	caData := []byte("ca")
   617  
   618  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   619  	assert.NoError(t, err)
   620  
   621  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterID, rancherURL, caData)
   622  	assert.NoError(t, err)
   623  	assert.Equal(t, secret.Labels, map[string]string{"argocd.argoproj.io/secret-type": "cluster"})
   624  }
   625  
   626  // TestMutateArgoCDClusterSecretThatExistingLabelRemainsAndClusterSecretLabelRemains tests the update of the ArgoCD Cluster Secret for a user when there is the user-provided labels and the ArgoCD cluster label
   627  // GIVEN a call to update the ArgoCD Cluster Secret when the secret has both a user-provided label and an ArgoCD Cluster label
   628  //
   629  //	THEN the ArgoCD cluster secret is created/updated via API with no error and both labels should remain
   630  func TestMutateArgoCDClusterSecretThatExistingLabelRemainsAndClusterSecretLabelRemains(t *testing.T) {
   631  	// clear any cached user auth tokens when the test completes
   632  	defer rancherutil.DeleteStoredTokens()
   633  
   634  	cli := generateClientObject()
   635  	log := vzlog.DefaultLogger()
   636  
   637  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   638  	defer func() {
   639  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   640  	}()
   641  
   642  	savedRetry := rancherutil.DefaultRetry
   643  	defer func() {
   644  		rancherutil.DefaultRetry = savedRetry
   645  	}()
   646  	rancherutil.DefaultRetry = wait.Backoff{
   647  		Steps:    1,
   648  		Duration: 1 * time.Millisecond,
   649  		Factor:   1.0,
   650  		Jitter:   0.1,
   651  	}
   652  
   653  	vmc := &v1alpha1.VerrazzanoManagedCluster{
   654  		ObjectMeta: metav1.ObjectMeta{
   655  			Namespace: constants.VerrazzanoMultiClusterNamespace,
   656  			Name:      "cluster",
   657  		},
   658  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
   659  			RancherRegistration: v1alpha1.RancherRegistration{
   660  				ClusterID: clusterID,
   661  			},
   662  		},
   663  	}
   664  	r := &VerrazzanoManagedClusterReconciler{
   665  		Client: cli,
   666  		log:    vzlog.DefaultLogger(),
   667  	}
   668  
   669  	secret := &corev1.Secret{
   670  		ObjectMeta: metav1.ObjectMeta{
   671  			Name:        "demo" + "-" + clusterSecretName,
   672  			Namespace:   constants.ArgoCDNamespace,
   673  			Annotations: map[string]string{createTimestamp: time.Now().Add(-10 * time.Hour).Format(time.RFC3339), expiresAtTimestamp: time.Now().Format(time.RFC3339)},
   674  			Labels:      map[string]string{"testlabel": "shouldnotbedeleted", "argocd.argoproj.io/secret-type": "cluster"},
   675  		},
   676  		Data: map[string][]byte{
   677  			"password": []byte("foobar"),
   678  		},
   679  	}
   680  
   681  	mocker := gomock.NewController(t)
   682  	httpMock := mocks.NewMockRequestSender(mocker)
   683  	httpMock = expectHTTPRequests(httpMock)
   684  	rancherutil.RancherHTTPClient = httpMock
   685  
   686  	caData := []byte("ca")
   687  
   688  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   689  	assert.NoError(t, err)
   690  
   691  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterID, rancherURL, caData)
   692  	assert.NoError(t, err)
   693  	assert.Equal(t, secret.Labels, map[string]string{"testlabel": "shouldnotbedeleted", "argocd.argoproj.io/secret-type": "cluster"})
   694  }
   695  
   696  // TestMutateArgoCDClusterSecretThatClusterSecretLabelRemains tests the update of the ArgoCD Cluster Secret for a user when there is the ArgoCD cluster label
   697  // GIVEN a call to update the ArgoCD Cluster Secret when the secret has an ArgoCD Cluster label
   698  //
   699  //	THEN the ArgoCD cluster secret is created/updated via API with no error and the ArgoCD Cluster label should remain
   700  func TestMutateArgoCDClusterSecretThatClusterSecretLabelRemains(t *testing.T) {
   701  	// clear any cached user auth tokens when the test completes
   702  	defer rancherutil.DeleteStoredTokens()
   703  
   704  	cli := generateClientObject()
   705  	log := vzlog.DefaultLogger()
   706  
   707  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   708  	defer func() {
   709  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   710  	}()
   711  
   712  	savedRetry := rancherutil.DefaultRetry
   713  	defer func() {
   714  		rancherutil.DefaultRetry = savedRetry
   715  	}()
   716  	rancherutil.DefaultRetry = wait.Backoff{
   717  		Steps:    1,
   718  		Duration: 1 * time.Millisecond,
   719  		Factor:   1.0,
   720  		Jitter:   0.1,
   721  	}
   722  
   723  	vmc := &v1alpha1.VerrazzanoManagedCluster{
   724  		ObjectMeta: metav1.ObjectMeta{
   725  			Namespace: constants.VerrazzanoMultiClusterNamespace,
   726  			Name:      "cluster",
   727  		},
   728  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
   729  			RancherRegistration: v1alpha1.RancherRegistration{
   730  				ClusterID: clusterID,
   731  			},
   732  		},
   733  	}
   734  	r := &VerrazzanoManagedClusterReconciler{
   735  		Client: cli,
   736  		log:    vzlog.DefaultLogger(),
   737  	}
   738  
   739  	secret := &corev1.Secret{
   740  		ObjectMeta: metav1.ObjectMeta{
   741  			Name:        "demo" + "-" + clusterSecretName,
   742  			Namespace:   constants.ArgoCDNamespace,
   743  			Annotations: map[string]string{createTimestamp: time.Now().Add(-10 * time.Hour).Format(time.RFC3339), expiresAtTimestamp: time.Now().Format(time.RFC3339)},
   744  			Labels:      map[string]string{"argocd.argoproj.io/secret-type": "cluster"},
   745  		},
   746  		Data: map[string][]byte{
   747  			"password": []byte("foobar"),
   748  		},
   749  	}
   750  
   751  	mocker := gomock.NewController(t)
   752  	httpMock := mocks.NewMockRequestSender(mocker)
   753  	httpMock = expectHTTPRequests(httpMock)
   754  	rancherutil.RancherHTTPClient = httpMock
   755  
   756  	caData := []byte("ca")
   757  
   758  	rc, err := rancherutil.NewRancherConfigForUser(cli, constants.ArgoCDClusterRancherUsername, "foobar", rancherutil.RancherIngressServiceHost(), log)
   759  	assert.NoError(t, err)
   760  
   761  	err = r.mutateArgoCDClusterSecret(secret, rc, vmc.Name, clusterID, rancherURL, caData)
   762  	assert.NoError(t, err)
   763  	assert.Equal(t, secret.Labels, map[string]string{"argocd.argoproj.io/secret-type": "cluster"})
   764  }