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

     1  // Copyright (c) 2021, 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  	"context"
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/Jeffail/gabs/v2"
    17  	"github.com/golang/mock/gomock"
    18  	"github.com/prometheus/client_golang/prometheus/testutil"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    21  	"github.com/verrazzano/verrazzano/pkg/constants"
    22  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    23  	"github.com/verrazzano/verrazzano/pkg/mcconstants"
    24  	"github.com/verrazzano/verrazzano/pkg/metricsutils"
    25  	"github.com/verrazzano/verrazzano/pkg/rancherutil"
    26  	"github.com/verrazzano/verrazzano/pkg/test/mockmatchers"
    27  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    28  	vpoconstants "github.com/verrazzano/verrazzano/platform-operator/constants"
    29  	"github.com/verrazzano/verrazzano/platform-operator/mocks"
    30  	corev1 "k8s.io/api/core/v1"
    31  	networkingv1 "k8s.io/api/networking/v1"
    32  	rbacv1 "k8s.io/api/rbac/v1"
    33  	apiv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    34  	"k8s.io/apimachinery/pkg/api/errors"
    35  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    36  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    37  	"k8s.io/apimachinery/pkg/runtime"
    38  	"k8s.io/apimachinery/pkg/runtime/schema"
    39  	"k8s.io/apimachinery/pkg/types"
    40  	"k8s.io/apimachinery/pkg/util/wait"
    41  	"k8s.io/client-go/rest"
    42  	ctrl "sigs.k8s.io/controller-runtime"
    43  	"sigs.k8s.io/controller-runtime/pkg/client"
    44  )
    45  
    46  const apiVersion = "clusters.verrazzano.io/v1alpha1"
    47  const kind = "VerrazzanoManagedCluster"
    48  
    49  const (
    50  	token                    = "tokenData"
    51  	testManagedCluster       = "test"
    52  	rancherAgentRegistry     = "ghcr.io"
    53  	rancherAgentImage        = rancherAgentRegistry + "/verrazzano/rancher-agent:v1.0.0"
    54  	rancherAdminSecret       = "rancher-admin-secret"
    55  	unitTestRancherClusterID = "unit-test-rancher-cluster-id"
    56  )
    57  
    58  var (
    59  	loginURLParts    = strings.Split(loginPath, "?")
    60  	loginURIPath     = loginURLParts[0]
    61  	loginQueryString = loginURLParts[1]
    62  )
    63  
    64  const rancherManifestYAML = `
    65  apiVersion: apps/v1
    66  kind: Deployment
    67  metadata:
    68    name: cattle-cluster-agent
    69    namespace: cattle-system
    70  spec:
    71    template:
    72      spec:
    73  	  containers:
    74  	    - name: cluster-register
    75  		  image: ` + rancherAgentImage + `
    76  		  imagePullPolicy: IfNotPresent
    77  `
    78  
    79  type AssertFn func(configMap *corev1.ConfigMap) error
    80  type secretAssertFn func(secret *corev1.Secret) error
    81  
    82  func init() {
    83  	// stub out keycloak client creation for these tests
    84  	createClient = func(r *VerrazzanoManagedClusterReconciler, vmc *v1alpha1.VerrazzanoManagedCluster) error {
    85  		return nil
    86  	}
    87  }
    88  
    89  // TestCreateVMC tests the Reconcile method for the following use case
    90  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
    91  // WHEN a VerrazzanoManagedCluster resource has been applied in a cluster where Rancher is enabled
    92  // THEN ensure all the objects are created correctly
    93  func TestCreateVMCRancherEnabled(t *testing.T) {
    94  	// with feature flag disabled (which triggers different asserts/mocks from enabled)
    95  	doTestCreateVMC(t, true)
    96  }
    97  
    98  // TestCreateVMC tests the Reconcile method for the following use case
    99  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   100  // WHEN a VerrazzanoManagedCluster resource has been applied in a cluster where Rancher is DISABLED
   101  // THEN ensure all the objects are created correctly
   102  func TestCreateVMCRancherDisabled(t *testing.T) {
   103  	doTestCreateVMC(t, false)
   104  }
   105  
   106  func doTestCreateVMC(t *testing.T, rancherEnabled bool) {
   107  	// clear any cached user auth tokens when the test completes
   108  	defer rancherutil.DeleteStoredTokens()
   109  
   110  	namespace := constants.VerrazzanoMultiClusterNamespace
   111  	asserts := assert.New(t)
   112  	mocker := gomock.NewController(t)
   113  	mock := mocks.NewMockClient(mocker)
   114  	mockStatus := mocks.NewMockStatusWriter(mocker)
   115  	asserts.NotNil(mockStatus)
   116  
   117  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   118  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   119  	defer func() {
   120  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   121  	}()
   122  	rancherutil.RancherHTTPClient = mockRequestSender
   123  
   124  	defer setConfigFunc(getConfigFunc)
   125  	setConfigFunc(fakeGetConfig)
   126  
   127  	rancherClusterState := rancherClusterStateInactive
   128  	caSecretExistsInVMC := true
   129  	expectVmcGetAndUpdate(t, mock, testManagedCluster, caSecretExistsInVMC, false)
   130  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   131  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   132  	// Agent secret sync checks depend on whether Rancher is enabled
   133  	expectSyncAgent(t, mock, testManagedCluster, rancherEnabled, false)
   134  	expectMockCallsForListingRancherUsers(mock)
   135  	expectSyncRegistration(t, mock, testManagedCluster, false, true)
   136  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   137  	expectRancherConfigK8sCalls(t, mock, false)
   138  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   139  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, true)
   140  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   141  	// expect status updated with condition Ready=true
   142  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   143  	expectSyncPrometheusScraper(t, mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   144  		asserts.Len(configMap.Data, 2, "no data found")
   145  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   146  		prometheusYaml := configMap.Data["prometheus.yml"]
   147  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   148  
   149  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   150  		if err != nil {
   151  			asserts.Fail("failed due to error %v", err)
   152  		}
   153  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   154  		return nil
   155  	}, func(secret *corev1.Secret) error {
   156  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   157  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   158  		if err != nil {
   159  			asserts.Fail("failed due to error %v", err)
   160  		}
   161  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   162  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   163  		return nil
   164  	}, func(secret *corev1.Secret) error {
   165  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   166  		return nil
   167  	})
   168  
   169  	// Create and make the request
   170  	request := newRequest(namespace, testManagedCluster)
   171  	reconciler := newVMCReconciler(mock)
   172  	result, err := reconciler.Reconcile(context.TODO(), request)
   173  
   174  	// Validate the results
   175  	mocker.Finish()
   176  	asserts.NoError(err)
   177  	asserts.Equal(true, result.Requeue)
   178  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   179  }
   180  
   181  // TestCreateVMC tests the Reconcile method for the following use case
   182  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   183  // WHEN a VerrazzanoManagedCluster resource has been applied on a Verrazzano install configured with external ES
   184  // THEN ensure all the objects are created
   185  func TestCreateVMCWithExternalES(t *testing.T) {
   186  	// clear any cached user auth tokens when the test completes
   187  	defer rancherutil.DeleteStoredTokens()
   188  
   189  	namespace := constants.VerrazzanoMultiClusterNamespace
   190  	asserts := assert.New(t)
   191  	mocker := gomock.NewController(t)
   192  	mock := mocks.NewMockClient(mocker)
   193  	mockStatus := mocks.NewMockStatusWriter(mocker)
   194  	asserts.NotNil(mockStatus)
   195  
   196  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   197  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   198  	defer func() {
   199  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   200  	}()
   201  	rancherutil.RancherHTTPClient = mockRequestSender
   202  
   203  	defer setConfigFunc(getConfigFunc)
   204  	setConfigFunc(fakeGetConfig)
   205  	rancherClusterState := rancherClusterStateInactive
   206  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   207  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   208  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   209  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   210  	expectMockCallsForListingRancherUsers(mock)
   211  	expectSyncRegistration(t, mock, testManagedCluster, true, true)
   212  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   213  	expectRancherConfigK8sCalls(t, mock, false)
   214  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   215  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, true)
   216  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   217  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   218  		asserts.Len(configMap.Data, 2, "no data found")
   219  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   220  		prometheusYaml := configMap.Data["prometheus.yml"]
   221  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   222  
   223  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   224  		if err != nil {
   225  			asserts.Fail("failed due to error %v", err)
   226  		}
   227  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   228  		return nil
   229  	}, func(secret *corev1.Secret) error {
   230  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   231  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   232  		if err != nil {
   233  			asserts.Fail("failed due to error %v", err)
   234  		}
   235  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   236  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   237  		return nil
   238  	}, func(secret *corev1.Secret) error {
   239  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   240  		return nil
   241  	})
   242  
   243  	// expect status updated with condition Ready=true
   244  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   245  
   246  	// Create and make the request
   247  	request := newRequest(namespace, testManagedCluster)
   248  	reconciler := newVMCReconciler(mock)
   249  	result, err := reconciler.Reconcile(context.TODO(), request)
   250  
   251  	// Validate the results
   252  	mocker.Finish()
   253  	asserts.NoError(err)
   254  	asserts.Equal(true, result.Requeue)
   255  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   256  }
   257  
   258  // TestCreateVMC tests the Reconcile method for the following use case
   259  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource for an OCI DNS cluster
   260  // WHEN a VerrazzanoManagedCluster resource has been applied
   261  // THEN ensure all the objects are created
   262  func TestCreateVMCOCIDNS(t *testing.T) {
   263  	// clear any cached user auth tokens when the test completes
   264  	defer rancherutil.DeleteStoredTokens()
   265  
   266  	namespace := "verrazzano-mc"
   267  	asserts := assert.New(t)
   268  	mocker := gomock.NewController(t)
   269  	mock := mocks.NewMockClient(mocker)
   270  	mockStatus := mocks.NewMockStatusWriter(mocker)
   271  	asserts.NotNil(mockStatus)
   272  
   273  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   274  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   275  	defer func() {
   276  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   277  	}()
   278  	rancherutil.RancherHTTPClient = mockRequestSender
   279  
   280  	defer setConfigFunc(getConfigFunc)
   281  	setConfigFunc(fakeGetConfig)
   282  	rancherClusterState := rancherClusterStateInactive
   283  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   284  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   285  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   286  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   287  	expectMockCallsForListingRancherUsers(mock)
   288  	expectSyncRegistration(t, mock, testManagedCluster, false, true)
   289  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   290  	expectRancherConfigK8sCalls(t, mock, false)
   291  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   292  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, true)
   293  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   294  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, "", "", true, "", func(configMap *corev1.ConfigMap) error {
   295  		asserts.Len(configMap.Data, 2, "no data found")
   296  		asserts.Empty(configMap.Data["ca-test"], "Cert entry found")
   297  		prometheusYaml := configMap.Data["prometheus.yml"]
   298  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   299  
   300  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   301  		if err != nil {
   302  			asserts.Fail("failed due to error %v", err)
   303  		}
   304  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, false)
   305  		return nil
   306  	}, func(secret *corev1.Secret) error {
   307  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   308  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   309  		if err != nil {
   310  			asserts.Fail("failed due to error %v", err)
   311  		}
   312  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   313  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, false)
   314  		return nil
   315  	}, func(secret *corev1.Secret) error {
   316  		asserts.Empty(secret.Data["ca-test"])
   317  		return nil
   318  	})
   319  
   320  	// expect status updated with condition Ready=true
   321  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   322  
   323  	// Create and make the request
   324  	request := newRequest(namespace, testManagedCluster)
   325  	reconciler := newVMCReconciler(mock)
   326  	result, err := reconciler.Reconcile(context.TODO(), request)
   327  
   328  	// Validate the results
   329  	mocker.Finish()
   330  	asserts.NoError(err)
   331  	asserts.Equal(true, result.Requeue)
   332  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   333  }
   334  
   335  // TestCreateVMCNoCACert tests the Reconcile method for the following use case
   336  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   337  // WHEN a VerrazzanoManagedCluster resource has been applied with no CA Cert
   338  // THEN ensure all the objects are created
   339  func TestCreateVMCNoCACert(t *testing.T) {
   340  	// clear any cached user auth tokens when the test completes
   341  	defer rancherutil.DeleteStoredTokens()
   342  
   343  	namespace := constants.VerrazzanoMultiClusterNamespace
   344  	asserts := assert.New(t)
   345  	mocker := gomock.NewController(t)
   346  	mock := mocks.NewMockClient(mocker)
   347  	mockStatus := mocks.NewMockStatusWriter(mocker)
   348  	asserts.NotNil(mockStatus)
   349  
   350  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   351  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   352  	defer func() {
   353  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   354  	}()
   355  	rancherutil.RancherHTTPClient = mockRequestSender
   356  
   357  	defer setConfigFunc(getConfigFunc)
   358  	setConfigFunc(fakeGetConfig)
   359  	rancherClusterState := rancherClusterStateActive
   360  	vzNSExists := false
   361  	expectVmcGetAndUpdate(t, mock, testManagedCluster, false, false)
   362  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   363  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   364  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   365  	expectMockCallsForListingRancherUsers(mock)
   366  	expectSyncRegistration(t, mock, testManagedCluster, true, true)
   367  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   368  	expectRancherConfigK8sCalls(t, mock, true)
   369  	expectSyncCACertRancherHTTPCalls(t, mockRequestSender, "", rancherClusterState)
   370  	expectRancherConfigK8sCalls(t, mock, false)
   371  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   372  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, vzNSExists)
   373  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, "", "", false, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   374  		asserts.Len(configMap.Data, 2, "no data found")
   375  		prometheusYaml := configMap.Data["prometheus.yml"]
   376  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   377  
   378  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   379  		if err != nil {
   380  			asserts.Fail("failed due to error %v", err)
   381  		}
   382  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, false)
   383  		return nil
   384  	}, func(secret *corev1.Secret) error {
   385  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   386  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   387  		if err != nil {
   388  			asserts.Fail("failed due to error %v", err)
   389  		}
   390  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   391  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, false)
   392  		return nil
   393  	}, func(secret *corev1.Secret) error {
   394  		asserts.Empty(secret.Data["ca-test"])
   395  		return nil
   396  	})
   397  
   398  	// expect status updated with condition Ready=true and ManagedCARetrieved condition is not set because we don't provide
   399  	// a non-zero length managed ca cert
   400  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   401  
   402  	// Create and make the request
   403  	request := newRequest(namespace, testManagedCluster)
   404  	reconciler := newVMCReconciler(mock)
   405  	result, err := reconciler.Reconcile(context.TODO(), request)
   406  
   407  	// Validate the results
   408  	mocker.Finish()
   409  	asserts.NoError(err)
   410  	asserts.Equal(true, result.Requeue)
   411  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   412  }
   413  
   414  // TestCreateVMCFetchCACertFromManagedCluster tests the Reconcile method for the following use case
   415  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   416  // WHEN a VerrazzanoManagedCluster resource has been applied and the caSecret field is NOT empty
   417  // THEN ensure that we fetch the CA cert secret from the managed cluster and populate the caSecret field
   418  func TestCreateVMCFetchCACertFromManagedCluster(t *testing.T) {
   419  	// clear any cached user auth tokens when the test completes
   420  	defer rancherutil.DeleteStoredTokens()
   421  
   422  	namespace := constants.VerrazzanoMultiClusterNamespace
   423  	asserts := assert.New(t)
   424  	mocker := gomock.NewController(t)
   425  	mock := mocks.NewMockClient(mocker)
   426  	mockStatus := mocks.NewMockStatusWriter(mocker)
   427  	asserts.NotNil(mockStatus)
   428  
   429  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   430  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   431  	defer func() {
   432  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   433  	}()
   434  	rancherutil.RancherHTTPClient = mockRequestSender
   435  
   436  	defer setConfigFunc(getConfigFunc)
   437  	setConfigFunc(fakeGetConfig)
   438  	rancherClusterState := rancherClusterStateActive
   439  	vzNSExists := false
   440  	expectVmcGetAndUpdate(t, mock, testManagedCluster, false, false)
   441  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   442  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   443  	expectSyncAgent(t, mock, testManagedCluster, true, false)
   444  	expectMockCallsForListingRancherUsers(mock)
   445  	expectSyncRegistration(t, mock, testManagedCluster, true, true)
   446  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   447  	expectSyncCACertRancherHTTPCalls(t, mockRequestSender, `{"data":{"ca.crt":"base64-ca-cert"}}`, rancherClusterState)
   448  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, true)
   449  	expectRancherConfigK8sCalls(t, mock, false)
   450  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   451  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, vzNSExists)
   452  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   453  		asserts.Len(configMap.Data, 2, "no data found")
   454  		prometheusYaml := configMap.Data["prometheus.yml"]
   455  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   456  
   457  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   458  		if err != nil {
   459  			asserts.Fail("failed due to error %v", err)
   460  		}
   461  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   462  		return nil
   463  	}, func(secret *corev1.Secret) error {
   464  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   465  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   466  		if err != nil {
   467  			asserts.Fail("failed due to error %v", err)
   468  		}
   469  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   470  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   471  		return nil
   472  	}, func(secret *corev1.Secret) error {
   473  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   474  		return nil
   475  	})
   476  
   477  	// expect status updated with condition Ready=true and ManagedCARetrieved
   478  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", true)
   479  
   480  	// Create and make the request
   481  	request := newRequest(namespace, testManagedCluster)
   482  	reconciler := newVMCReconciler(mock)
   483  	result, err := reconciler.Reconcile(context.TODO(), request)
   484  
   485  	// Validate the results
   486  	mocker.Finish()
   487  	asserts.NoError(err)
   488  	asserts.Equal(true, result.Requeue)
   489  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   490  }
   491  
   492  // TestCreateVMCWithExistingScrapeConfiguration tests the Reconcile method for the following use case
   493  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   494  // WHEN a VerrazzanoManagedCluster resource has been applied and prometheus is already configured with a scrape config for the cluster
   495  // THEN ensure all the objects are created
   496  func TestCreateVMCWithExistingScrapeConfiguration(t *testing.T) {
   497  	// clear any cached user auth tokens when the test completes
   498  	defer rancherutil.DeleteStoredTokens()
   499  
   500  	namespace := "verrazzano-mc"
   501  	jobs := `  - ` + constants.PrometheusJobNameKey + `: cluster1
   502      scrape_interval: 20s
   503      scrape_timeout: 15s
   504      scheme: http`
   505  	prometheusYaml := `global:
   506    scrape_interval: 20s
   507    scrape_timeout: 10s
   508    evaluation_interval: 30s
   509  scrape_configs:
   510  ` + jobs
   511  	asserts := assert.New(t)
   512  	mocker := gomock.NewController(t)
   513  	mock := mocks.NewMockClient(mocker)
   514  	mockStatus := mocks.NewMockStatusWriter(mocker)
   515  	asserts.NotNil(mockStatus)
   516  
   517  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   518  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   519  	defer func() {
   520  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   521  	}()
   522  	rancherutil.RancherHTTPClient = mockRequestSender
   523  
   524  	defer setConfigFunc(getConfigFunc)
   525  	setConfigFunc(fakeGetConfig)
   526  	rancherClusterState := rancherClusterStateInactive
   527  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   528  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   529  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   530  	expectSyncAgent(t, mock, testManagedCluster, false, false)
   531  	expectMockCallsForListingRancherUsers(mock)
   532  	expectSyncRegistration(t, mock, testManagedCluster, false, true)
   533  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   534  	expectRancherConfigK8sCalls(t, mock, false)
   535  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   536  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, true)
   537  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   538  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, prometheusYaml, jobs, true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   539  
   540  		// check for the modified entry
   541  		asserts.Len(configMap.Data, 2, "no data found")
   542  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   543  		prometheusYaml := configMap.Data["prometheus.yml"]
   544  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   545  
   546  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   547  		if err != nil {
   548  			asserts.Fail("failed due to error %v", err)
   549  		}
   550  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   551  		return nil
   552  	}, func(secret *corev1.Secret) error {
   553  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   554  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   555  		if err != nil {
   556  			asserts.Fail("failed due to error %v", err)
   557  		}
   558  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   559  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   560  		return nil
   561  	}, func(secret *corev1.Secret) error {
   562  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   563  		return nil
   564  	})
   565  
   566  	// expect status updated with condition Ready=true
   567  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   568  
   569  	// Create and make the request
   570  	request := newRequest(namespace, testManagedCluster)
   571  	reconciler := newVMCReconciler(mock)
   572  	result, err := reconciler.Reconcile(context.TODO(), request)
   573  
   574  	// Validate the results
   575  	mocker.Finish()
   576  	asserts.NoError(err)
   577  	asserts.Equal(true, result.Requeue)
   578  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   579  }
   580  
   581  // TestReplaceExistingScrapeConfiguration tests the Reconcile method for the following use case
   582  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   583  // WHEN a VerrazzanoManagedCluster resource has been applied and prometheus is already configured with a scrape configuration for the same cluster
   584  // THEN ensure all the objects are created (existing configuration is replaced)
   585  func TestReplaceExistingScrapeConfiguration(t *testing.T) {
   586  	// clear any cached user auth tokens when the test completes
   587  	defer rancherutil.DeleteStoredTokens()
   588  
   589  	namespace := "verrazzano-mc"
   590  	jobs := `  - ` + constants.PrometheusJobNameKey + `: test
   591      scrape_interval: 20s
   592      scrape_timeout: 15s
   593      scheme: http`
   594  	prometheusYaml := `global:
   595    scrape_interval: 20s
   596    scrape_timeout: 10s
   597    evaluation_interval: 30s
   598  scrape_configs:
   599  ` + jobs
   600  	asserts := assert.New(t)
   601  	mocker := gomock.NewController(t)
   602  	mock := mocks.NewMockClient(mocker)
   603  	mockStatus := mocks.NewMockStatusWriter(mocker)
   604  	asserts.NotNil(mockStatus)
   605  
   606  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   607  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   608  	defer func() {
   609  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   610  	}()
   611  	rancherutil.RancherHTTPClient = mockRequestSender
   612  
   613  	defer setConfigFunc(getConfigFunc)
   614  	setConfigFunc(fakeGetConfig)
   615  	rancherClusterState := rancherClusterStateInactive
   616  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   617  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   618  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   619  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   620  	expectMockCallsForListingRancherUsers(mock)
   621  	expectSyncRegistration(t, mock, testManagedCluster, false, true)
   622  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML, true, rancherClusterState)
   623  	expectRancherConfigK8sCalls(t, mock, false)
   624  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   625  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, true)
   626  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   627  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, prometheusYaml, jobs, true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   628  
   629  		asserts.Len(configMap.Data, 2, "no data found")
   630  		asserts.NotNil(configMap.Data["ca-test"], "No cert entry found")
   631  		prometheusYaml := configMap.Data["prometheus.yml"]
   632  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   633  
   634  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   635  		if err != nil {
   636  			asserts.Fail("failed due to error %v", err)
   637  		}
   638  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   639  		return nil
   640  	}, func(secret *corev1.Secret) error {
   641  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   642  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   643  		if err != nil {
   644  			asserts.Fail("failed due to error %v", err)
   645  		}
   646  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   647  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   648  		return nil
   649  	}, func(secret *corev1.Secret) error {
   650  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   651  		return nil
   652  	})
   653  
   654  	// expect status updated with condition Ready=true
   655  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   656  
   657  	// Create and make the request
   658  	request := newRequest(namespace, testManagedCluster)
   659  	reconciler := newVMCReconciler(mock)
   660  	result, err := reconciler.Reconcile(context.TODO(), request)
   661  
   662  	// Validate the results
   663  	mocker.Finish()
   664  	asserts.NoError(err)
   665  	asserts.Equal(true, result.Requeue)
   666  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   667  }
   668  
   669  // TestCreateVMC tests the Reconcile method for the following use case
   670  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   671  // WHEN a VerrazzanoManagedCluster resource has been applied
   672  // AND the cluster has already been registered with Rancher
   673  // THEN ensure all the objects are created
   674  func TestCreateVMCClusterAlreadyRegistered(t *testing.T) {
   675  	// clear any cached user auth tokens when the test completes
   676  	defer rancherutil.DeleteStoredTokens()
   677  
   678  	namespace := constants.VerrazzanoMultiClusterNamespace
   679  	asserts := assert.New(t)
   680  	mocker := gomock.NewController(t)
   681  	mock := mocks.NewMockClient(mocker)
   682  	mockStatus := mocks.NewMockStatusWriter(mocker)
   683  	asserts.NotNil(mockStatus)
   684  
   685  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   686  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   687  	defer func() {
   688  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   689  	}()
   690  	rancherutil.RancherHTTPClient = mockRequestSender
   691  
   692  	defer setConfigFunc(getConfigFunc)
   693  	setConfigFunc(fakeGetConfig)
   694  	rancherClusterState := rancherClusterStateInactive
   695  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, true)
   696  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   697  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   698  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   699  	expectMockCallsForListingRancherUsers(mock)
   700  	expectSyncRegistration(t, mock, testManagedCluster, false, true)
   701  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, true, rancherManifestYAML, true, rancherClusterState)
   702  	expectRancherConfigK8sCalls(t, mock, false)
   703  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   704  	expectPushManifestRequests(t, mockRequestSender, mock, rancherClusterState, true)
   705  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   706  	expectSyncPrometheusScraper(nil, mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   707  		asserts.Len(configMap.Data, 2, "no data found")
   708  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   709  		prometheusYaml := configMap.Data["prometheus.yml"]
   710  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   711  
   712  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   713  		if err != nil {
   714  			asserts.Fail("failed due to error %v", err)
   715  		}
   716  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   717  		return nil
   718  	}, func(secret *corev1.Secret) error {
   719  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   720  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   721  		if err != nil {
   722  			asserts.Fail("failed due to error %v", err)
   723  		}
   724  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   725  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   726  		return nil
   727  	}, func(secret *corev1.Secret) error {
   728  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   729  		return nil
   730  	})
   731  
   732  	// expect status updated with condition Ready=true
   733  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   734  
   735  	// Create and make the request
   736  	request := newRequest(namespace, testManagedCluster)
   737  	reconciler := newVMCReconciler(mock)
   738  	result, err := reconciler.Reconcile(context.TODO(), request)
   739  
   740  	// Validate the results
   741  	mocker.Finish()
   742  	asserts.NoError(err)
   743  	asserts.Equal(true, result.Requeue)
   744  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   745  }
   746  
   747  // TestCreateVMCSyncSvcAccountFailed tests the Reconcile method for the following use case
   748  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   749  // WHEN syncing of service account fails
   750  // THEN ensure that the VMC status is updated to Ready=false with an appropriate message
   751  func TestCreateVMCSyncSvcAccountFailed(t *testing.T) {
   752  	// clear any cached user auth tokens when the test completes
   753  	defer rancherutil.DeleteStoredTokens()
   754  
   755  	namespace := constants.VerrazzanoMultiClusterNamespace
   756  	asserts := assert.New(t)
   757  	mocker := gomock.NewController(t)
   758  	mock := mocks.NewMockClient(mocker)
   759  	mockStatus := mocks.NewMockStatusWriter(mocker)
   760  	asserts.NotNil(mockStatus)
   761  
   762  	defer setConfigFunc(getConfigFunc)
   763  	setConfigFunc(fakeGetConfig)
   764  
   765  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   766  	expectSyncServiceAccount(t, mock, testManagedCluster, false)
   767  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
   768  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
   769  			return nil
   770  		})
   771  
   772  	// expect status updated with condition Ready=true
   773  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionFalse, "failing syncServiceAccount", false)
   774  
   775  	errCount := testutil.ToFloat64(reconcileErrorCount)
   776  
   777  	// Create and make the request
   778  	request := newRequest(namespace, testManagedCluster)
   779  	reconciler := newVMCReconciler(mock)
   780  	result, err := reconciler.Reconcile(context.TODO(), request)
   781  
   782  	// Validate the results - there should have been no error returned for failing to sync svc account, but the reconcile
   783  	// error metric should have been incremented and the request should be requeued
   784  	mocker.Finish()
   785  	asserts.NoError(err)
   786  	asserts.Equal(true, result.Requeue)
   787  	asserts.NotEqual(time.Duration(0), result.RequeueAfter)
   788  	asserts.Equal(errCount+1, testutil.ToFloat64(reconcileErrorCount))
   789  }
   790  
   791  // TestCreateVMCSyncRoleBindingFailed tests the Reconcile method for the following use case
   792  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   793  // WHEN syncing of role binding fails
   794  // THEN ensure that the VMC status is updated to Ready=false with an appropriate message
   795  func TestCreateVMCSyncRoleBindingFailed(t *testing.T) {
   796  	// clear any cached user auth tokens when the test completes
   797  	defer rancherutil.DeleteStoredTokens()
   798  
   799  	namespace := constants.VerrazzanoMultiClusterNamespace
   800  	name := "test"
   801  
   802  	asserts := assert.New(t)
   803  	mocker := gomock.NewController(t)
   804  	mock := mocks.NewMockClient(mocker)
   805  	mockStatus := mocks.NewMockStatusWriter(mocker)
   806  	asserts.NotNil(mockStatus)
   807  
   808  	defer setConfigFunc(getConfigFunc)
   809  	setConfigFunc(fakeGetConfig)
   810  
   811  	expectVmcGetAndUpdate(t, mock, name, true, false)
   812  	expectSyncServiceAccount(t, mock, name, true)
   813  	expectSyncRoleBinding(t, mock, name, false)
   814  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
   815  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
   816  			return nil
   817  		})
   818  
   819  	// expect status updated with condition Ready=true
   820  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionFalse, "failing syncRoleBinding", false)
   821  
   822  	// Create and make the request
   823  	request := newRequest(namespace, name)
   824  	reconciler := newVMCReconciler(mock)
   825  	result, err := reconciler.Reconcile(context.TODO(), request)
   826  
   827  	// Validate the results - there should have been an error returned
   828  	mocker.Finish()
   829  	asserts.Nil(err)
   830  	asserts.Equal(true, result.Requeue)
   831  	asserts.NotEqual(time.Duration(0), result.RequeueAfter)
   832  }
   833  
   834  // TestDeleteVMC tests the Reconcile method for the following use case
   835  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   836  // WHEN a VerrazzanoManagedCluster resource has been deleted
   837  // THEN ensure the object is not processed
   838  func TestDeleteVMC(t *testing.T) {
   839  	// clear any cached user auth tokens when the test completes
   840  	defer rancherutil.DeleteStoredTokens()
   841  
   842  	namespace := "verrazzano-install"
   843  	asserts := assert.New(t)
   844  	mocker := gomock.NewController(t)
   845  	mock := mocks.NewMockClient(mocker)
   846  
   847  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   848  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   849  	defer func() {
   850  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   851  	}()
   852  	rancherutil.RancherHTTPClient = mockRequestSender
   853  
   854  	// Expect all of the calls when deleting a VMC
   855  	expectMockCallsForDelete(t, mock, namespace)
   856  	expectRancherGetAuthTokenHTTPCall(t, mockRequestSender)
   857  	expectThanosDelete(t, mock)
   858  
   859  	// Expect an API call to delete the Rancher cluster
   860  	mockRequestSender.EXPECT().
   861  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod("DELETE", clustersPath+"/"+unitTestRancherClusterID)).
   862  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   863  			r := io.NopCloser(bytes.NewReader([]byte("")))
   864  			resp := &http.Response{
   865  				StatusCode: http.StatusOK,
   866  				Body:       r,
   867  			}
   868  			return resp, nil
   869  		})
   870  
   871  	// Expect a call to update the VerrazzanoManagedCluster finalizer
   872  	mock.EXPECT().
   873  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
   874  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
   875  			asserts.True(len(vmc.ObjectMeta.Finalizers) == 0, "Wrong number of finalizers")
   876  			return nil
   877  		})
   878  
   879  	mock.EXPECT().
   880  		List(gomock.Any(), &v1beta1.VerrazzanoList{}, gomock.Not(gomock.Nil())).
   881  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
   882  			vz := v1beta1.Verrazzano{}
   883  			list.Items = append(list.Items, vz)
   884  			return nil
   885  		})
   886  
   887  	// Create and make the request
   888  	request := newRequest(namespace, testManagedCluster)
   889  	reconciler := newVMCReconciler(mock)
   890  	result, err := reconciler.Reconcile(context.TODO(), request)
   891  
   892  	// Validate the results
   893  	mocker.Finish()
   894  	asserts.NoError(err)
   895  	asserts.Equal(false, result.Requeue)
   896  	asserts.Equal(time.Duration(0), result.RequeueAfter)
   897  }
   898  
   899  // TestDeleteVMCFailedDeletingRancherCluster tests deleting a VMC when there are errors attempting to
   900  // delete the Rancher cluster.
   901  func TestDeleteVMCFailedDeletingRancherCluster(t *testing.T) {
   902  	// clear any cached user auth tokens when the test completes
   903  	defer rancherutil.DeleteStoredTokens()
   904  
   905  	namespace := "verrazzano-install"
   906  	asserts := assert.New(t)
   907  	mocker := gomock.NewController(t)
   908  	mock := mocks.NewMockClient(mocker)
   909  	mockStatus := mocks.NewMockStatusWriter(mocker)
   910  	asserts.NotNil(mockStatus)
   911  
   912  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   913  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   914  	defer func() {
   915  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   916  	}()
   917  	rancherutil.RancherHTTPClient = mockRequestSender
   918  
   919  	// GIVEN a VMC is being deleted
   920  	//  WHEN we fail creating a Rancher API client that will be used to delete the cluster in Rancher
   921  	//  THEN the appropriate status is set on the VMC and the finalizer is not removed
   922  
   923  	// Expect all of the calls when deleting a VMC
   924  	expectMockCallsForDelete(t, mock, namespace)
   925  	expectThanosDelete(t, mock)
   926  
   927  	// Expect an HTTP request to fetch the admin token from Rancher - return an error
   928  	mockRequestSender.EXPECT().
   929  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
   930  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   931  			asserts.Equal(loginQueryString, req.URL.RawQuery)
   932  
   933  			r := io.NopCloser(bytes.NewReader([]byte("")))
   934  			resp := &http.Response{
   935  				StatusCode: http.StatusBadRequest,
   936  				Body:       r,
   937  				Request:    &http.Request{Method: http.MethodDelete},
   938  			}
   939  			return resp, nil
   940  		})
   941  
   942  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
   943  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
   944  			return nil
   945  		})
   946  
   947  	mock.EXPECT().Status().Return(mockStatus)
   948  	mockStatus.EXPECT().
   949  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
   950  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
   951  			asserts.Equal(v1alpha1.DeleteFailed, vmc.Status.RancherRegistration.Status)
   952  			asserts.Equal("Failed to create Rancher API client", vmc.Status.RancherRegistration.Message)
   953  			return nil
   954  		})
   955  
   956  	mock.EXPECT().
   957  		List(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil())).
   958  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
   959  			vz := v1beta1.Verrazzano{}
   960  			list.Items = append(list.Items, vz)
   961  			return nil
   962  		})
   963  
   964  	// Create and make the request
   965  	request := newRequest(namespace, testManagedCluster)
   966  	reconciler := newVMCReconciler(mock)
   967  	result, err := reconciler.Reconcile(context.TODO(), request)
   968  
   969  	// Validate the results
   970  	mocker.Finish()
   971  	asserts.NoError(err)
   972  	asserts.Equal(true, result.Requeue)
   973  
   974  	// GIVEN a VMC is being deleted
   975  	//  WHEN we fail attempting to delete the cluster in Rancher
   976  	//  THEN the appropriate status is set on the VMC and the finalizer is not removed
   977  
   978  	mock = mocks.NewMockClient(mocker)
   979  	mockStatus = mocks.NewMockStatusWriter(mocker)
   980  	mockRequestSender = mocks.NewMockRequestSender(mocker)
   981  	rancherutil.RancherHTTPClient = mockRequestSender
   982  
   983  	// Expect all of the calls when deleting a VMC
   984  	expectMockCallsForDelete(t, mock, namespace)
   985  	expectRancherGetAuthTokenHTTPCall(t, mockRequestSender)
   986  	expectThanosDelete(t, mock)
   987  
   988  	// Expect an API call to delete the Rancher cluster - return an error
   989  	mockRequestSender.EXPECT().
   990  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod("DELETE", clustersPath+"/"+unitTestRancherClusterID)).
   991  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   992  			r := io.NopCloser(bytes.NewReader([]byte("")))
   993  			resp := &http.Response{
   994  				StatusCode: http.StatusConflict,
   995  				Body:       r,
   996  				Request:    &http.Request{Method: http.MethodDelete},
   997  			}
   998  			return resp, nil
   999  		})
  1000  
  1001  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1002  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1003  			return nil
  1004  		})
  1005  
  1006  	mock.EXPECT().Status().Return(mockStatus)
  1007  	mockStatus.EXPECT().
  1008  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1009  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1010  			asserts.Equal(v1alpha1.DeleteFailed, vmc.Status.RancherRegistration.Status)
  1011  			asserts.Equal("Failed deleting cluster", vmc.Status.RancherRegistration.Message)
  1012  			return nil
  1013  		})
  1014  
  1015  	mock.EXPECT().
  1016  		List(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil())).
  1017  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
  1018  			vz := v1beta1.Verrazzano{}
  1019  			list.Items = append(list.Items, vz)
  1020  			return nil
  1021  		})
  1022  
  1023  	// Create and make the request
  1024  	request = newRequest(namespace, testManagedCluster)
  1025  	reconciler = newVMCReconciler(mock)
  1026  	result, err = reconciler.Reconcile(context.TODO(), request)
  1027  
  1028  	// Validate the results
  1029  	mocker.Finish()
  1030  	asserts.NoError(err)
  1031  	asserts.Equal(true, result.Requeue)
  1032  }
  1033  
  1034  // TestSyncManifestSecretFailRancherRegistration tests syncing the manifest secret
  1035  // when Rancher registration fails
  1036  // GIVEN a call to sync the manifest secret
  1037  // WHEN Rancher registration fails
  1038  // THEN the manifest secret is still created and syncManifestSecret returns no error
  1039  func TestSyncManifestSecretFailRancherRegistration(t *testing.T) {
  1040  	// clear any cached user auth tokens when the test completes
  1041  	defer rancherutil.DeleteStoredTokens()
  1042  
  1043  	asserts := assert.New(t)
  1044  	mocker := gomock.NewController(t)
  1045  	mock := mocks.NewMockClient(mocker)
  1046  	mockStatus := mocks.NewMockStatusWriter(mocker)
  1047  	asserts.NotNil(mockStatus)
  1048  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1049  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1050  	defer func() {
  1051  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1052  	}()
  1053  	rancherutil.RancherHTTPClient = mockRequestSender
  1054  
  1055  	clusterName := "cluster1"
  1056  
  1057  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.RancherSystemNamespace, Name: rancherAdminSecret}, gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1058  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1059  			secret.Data = map[string][]byte{
  1060  				"password": []byte("super-secret"),
  1061  			}
  1062  			return nil
  1063  		})
  1064  	// Expect a call to get the Rancher ingress and return no spec rules, which will cause registration to fail
  1065  	mock.EXPECT().
  1066  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  1067  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1068  			return nil
  1069  		})
  1070  
  1071  	// Expect to get existing VMC for status update
  1072  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: clusterName}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1073  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1074  			return nil
  1075  		})
  1076  
  1077  	mock.EXPECT().Status().Return(mockStatus)
  1078  	mockStatus.EXPECT().
  1079  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1080  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1081  			asserts.Equal(v1alpha1.RegistrationFailed, vmc.Status.RancherRegistration.Status)
  1082  			asserts.Contains(vmc.Status.RancherRegistration.Message, "Failed to create Rancher API client")
  1083  			return nil
  1084  		})
  1085  
  1086  	// Expect a call to get the manifest secret - return that it does not exist
  1087  	mock.EXPECT().
  1088  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetManifestSecretName(clusterName)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1089  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetManifestSecretName(clusterName)))
  1090  
  1091  	// Expect a call to create the manifest secret
  1092  	mock.EXPECT().
  1093  		Create(gomock.Any(), gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1094  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1095  			return nil
  1096  		})
  1097  
  1098  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: clusterName}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1099  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1100  			return nil
  1101  		})
  1102  
  1103  	// Expect a call to update the VerrazzanoManagedCluster kubeconfig secret testManagedCluster - return success
  1104  	mock.EXPECT().
  1105  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  1106  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1107  			asserts.Equal(vmc.Spec.ManagedClusterManifestSecret, GetManifestSecretName(clusterName), "Manifest secret testManagedCluster did not match")
  1108  			return nil
  1109  		})
  1110  
  1111  	// Create a reconciler and call the function to sync the manifest secret - the call to register the cluster with Rancher will
  1112  	// fail but the result of syncManifestSecret should be success
  1113  	vmc := v1alpha1.VerrazzanoManagedCluster{ObjectMeta: metav1.ObjectMeta{Name: clusterName, Namespace: constants.VerrazzanoMultiClusterNamespace}}
  1114  	reconciler := newVMCReconciler(mock)
  1115  	reconciler.log = vzlog.DefaultLogger()
  1116  
  1117  	vzVMCWaitingForClusterID, err := reconciler.syncManifestSecret(context.TODO(), true, &vmc)
  1118  
  1119  	// Validate the results
  1120  	mocker.Finish()
  1121  	asserts.NoError(err)
  1122  	asserts.False(vzVMCWaitingForClusterID)
  1123  }
  1124  
  1125  // TestSyncManifestSecretEmptyRancherManifest tests syncing the manifest secret
  1126  // when Rancher returns an empty registration manifest YAML string.
  1127  // GIVEN a call to sync the manifest secret
  1128  // WHEN Rancher returns an empty manifest
  1129  // THEN the status is set to failed on the VMC with an appropriate message and the syncManifestSecret call returns an error
  1130  func TestSyncManifestSecretEmptyRancherManifest(t *testing.T) {
  1131  	// clear any cached user auth tokens when the test completes
  1132  	defer rancherutil.DeleteStoredTokens()
  1133  
  1134  	asserts := assert.New(t)
  1135  	mocker := gomock.NewController(t)
  1136  	mock := mocks.NewMockClient(mocker)
  1137  	mockStatus := mocks.NewMockStatusWriter(mocker)
  1138  	asserts.NotNil(mockStatus)
  1139  
  1140  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1141  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1142  	defer func() {
  1143  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1144  	}()
  1145  	rancherutil.RancherHTTPClient = mockRequestSender
  1146  
  1147  	defer setConfigFunc(getConfigFunc)
  1148  	setConfigFunc(fakeGetConfig)
  1149  
  1150  	// Expect all the calls needed to register the cluster with Rancher - note we are passing an empty string for the Rancher manifest YAML
  1151  	// that will be returned when calling the Rancher API
  1152  	expectRegisterClusterWithRancher(t, mock, mockRequestSender, nil, testManagedCluster, false, "")
  1153  
  1154  	// Expect the Rancher registration status to be set appropriately
  1155  	mock.EXPECT().Status().Return(mockStatus)
  1156  	mockStatus.EXPECT().
  1157  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1158  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1159  			asserts.Equal(v1alpha1.RegistrationFailed, vmc.Status.RancherRegistration.Status)
  1160  			asserts.Equal(unitTestRancherClusterID, vmc.Status.RancherRegistration.ClusterID)
  1161  			asserts.Equal("Empty Rancher manifest YAML", vmc.Status.RancherRegistration.Message)
  1162  			return nil
  1163  		})
  1164  
  1165  	// Create a reconciler and call the function to sync the manifest secret
  1166  	vmc := v1alpha1.VerrazzanoManagedCluster{ObjectMeta: metav1.ObjectMeta{Name: testManagedCluster, Namespace: constants.VerrazzanoMultiClusterNamespace}}
  1167  	reconciler := newVMCReconciler(mock)
  1168  	reconciler.log = vzlog.DefaultLogger()
  1169  
  1170  	vzVMCWaitingForClusterID, err := reconciler.syncManifestSecret(context.TODO(), true, &vmc)
  1171  
  1172  	// Validate the results
  1173  	mocker.Finish()
  1174  	asserts.ErrorContains(err, "Failed retrieving Rancher manifest, YAML is an empty string")
  1175  	asserts.False(vzVMCWaitingForClusterID)
  1176  }
  1177  
  1178  // TestRegisterClusterWithRancherK8sErrorCases tests errors cases using the Kubernetes
  1179  // client when registering with Rancher.
  1180  func TestRegisterClusterWithRancherK8sErrorCases(t *testing.T) {
  1181  	// clear any cached user auth tokens when the test completes
  1182  	defer rancherutil.DeleteStoredTokens()
  1183  
  1184  	asserts := assert.New(t)
  1185  	mocker := gomock.NewController(t)
  1186  	mock := mocks.NewMockClient(mocker)
  1187  
  1188  	// GIVEN a call to register a managed cluster with Rancher
  1189  	// WHEN the call to get the ingress host name returns no ingress rules
  1190  	// THEN the registration call returns an error
  1191  
  1192  	// Expect a call to get the ingress host name but there are no ingress rules
  1193  	mock.EXPECT().
  1194  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  1195  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1196  			return nil
  1197  		})
  1198  
  1199  	// Expect a call for the verrazzano cluser user secret
  1200  	mock.EXPECT().
  1201  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: constants.VerrazzanoClusterRancherName}, gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1202  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1203  			secret.Data = map[string][]byte{
  1204  				"password": []byte("super-secret"),
  1205  			}
  1206  			return nil
  1207  		})
  1208  
  1209  	rc, err := rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1210  
  1211  	mocker.Finish()
  1212  	asserts.Error(err)
  1213  	asserts.Nil(rc)
  1214  
  1215  	// GIVEN a call to register a managed cluster with Rancher
  1216  	// WHEN the call to get the Rancher root CA cert secret fails
  1217  	// THEN the registration call returns an error
  1218  	mocker = gomock.NewController(t)
  1219  	mock = mocks.NewMockClient(mocker)
  1220  
  1221  	// Expect a call to get the ingress host name
  1222  	mock.EXPECT().
  1223  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  1224  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1225  			rule := networkingv1.IngressRule{Host: "rancher.unit-test.com"}
  1226  			ingress.Spec.Rules = append(ingress.Spec.Rules, rule)
  1227  			return nil
  1228  		})
  1229  
  1230  	// Expect a call to get the secret with the Rancher root CA cert but the call fails
  1231  	mock.EXPECT().
  1232  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherTLSSecret}), gomock.Not(gomock.Nil()), gomock.Any()).
  1233  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1234  			return errors.NewResourceExpired("something bad happened")
  1235  		})
  1236  
  1237  	// Expect a call for the verrazzano cluser user secret
  1238  	mock.EXPECT().
  1239  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: constants.VerrazzanoClusterRancherName}, gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1240  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1241  			secret.Data = map[string][]byte{
  1242  				"password": []byte("super-secret"),
  1243  			}
  1244  			return nil
  1245  		})
  1246  
  1247  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1248  
  1249  	mocker.Finish()
  1250  	asserts.Error(err)
  1251  	asserts.Nil(rc)
  1252  }
  1253  
  1254  // TestRegisterClusterWithRancherHTTPErrorCases tests errors cases using the HTTP
  1255  // client when registering with Rancher.
  1256  func TestRegisterClusterWithRancherHTTPErrorCases(t *testing.T) {
  1257  	// clear any cached user auth tokens when the test completes
  1258  	defer rancherutil.DeleteStoredTokens()
  1259  
  1260  	asserts := assert.New(t)
  1261  	mocker := gomock.NewController(t)
  1262  	mock := mocks.NewMockClient(mocker)
  1263  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1264  
  1265  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1266  	defer func() {
  1267  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1268  	}()
  1269  	rancherutil.RancherHTTPClient = mockRequestSender
  1270  
  1271  	// GIVEN a call to register a managed cluster with Rancher
  1272  	// WHEN the call to get the Rancher admin token fails
  1273  	// THEN the registration call returns an error
  1274  
  1275  	// Expect all of the Kubernetes calls
  1276  	expectRancherConfigK8sCalls(t, mock, false)
  1277  
  1278  	// Expect an HTTP request to fetch the admin token from Rancher but the call fails
  1279  	mockRequestSender.EXPECT().
  1280  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1281  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1282  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1283  			resp := &http.Response{
  1284  				StatusCode: http.StatusUnauthorized,
  1285  				Body:       r,
  1286  				Request:    &http.Request{Method: http.MethodPost},
  1287  			}
  1288  			return resp, nil
  1289  		})
  1290  
  1291  	rc, err := rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1292  
  1293  	mocker.Finish()
  1294  	asserts.Error(err)
  1295  	asserts.Nil(rc)
  1296  	rancherutil.DeleteStoredTokens()
  1297  
  1298  	// GIVEN a call to register a managed cluster with Rancher
  1299  	// WHEN the call to import the cluster into Rancher fails
  1300  	// THEN the registration call returns an error
  1301  	mocker = gomock.NewController(t)
  1302  	mock = mocks.NewMockClient(mocker)
  1303  	mockRequestSender = mocks.NewMockRequestSender(mocker)
  1304  	rancherutil.RancherHTTPClient = mockRequestSender
  1305  
  1306  	// Expect all of the Kubernetes calls
  1307  	expectRancherConfigK8sCalls(t, mock, false)
  1308  
  1309  	// Expect an HTTP request to fetch the admin token from Rancher
  1310  	mockRequestSender.EXPECT().
  1311  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1312  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1313  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  1314  			resp := &http.Response{
  1315  				StatusCode: http.StatusCreated,
  1316  				Body:       r,
  1317  				Request:    &http.Request{Method: http.MethodPost},
  1318  			}
  1319  			return resp, nil
  1320  		})
  1321  
  1322  	// Expect an HTTP request to import the cluster to Rancher but the call fails
  1323  	mockRequestSender.EXPECT().
  1324  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  1325  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1326  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1327  			resp := &http.Response{
  1328  				StatusCode: http.StatusConflict,
  1329  				Body:       r,
  1330  				Request:    &http.Request{Method: http.MethodPost},
  1331  			}
  1332  			return resp, nil
  1333  		})
  1334  
  1335  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1336  	asserts.NoError(err)
  1337  
  1338  	regYAML, _, err := RegisterManagedClusterWithRancher(rc, testManagedCluster, "", vzlog.DefaultLogger())
  1339  
  1340  	mocker.Finish()
  1341  	asserts.Error(err)
  1342  	asserts.Empty(regYAML)
  1343  	rancherutil.DeleteStoredTokens()
  1344  
  1345  	// GIVEN a call to register a managed cluster with Rancher
  1346  	// WHEN the call to create the Rancher registration token fails
  1347  	// THEN the registration call returns an error
  1348  	mocker = gomock.NewController(t)
  1349  	mock = mocks.NewMockClient(mocker)
  1350  	mockRequestSender = mocks.NewMockRequestSender(mocker)
  1351  	rancherutil.RancherHTTPClient = mockRequestSender
  1352  
  1353  	// Expect all of the Kubernetes calls
  1354  	expectRancherConfigK8sCalls(t, mock, false)
  1355  
  1356  	// Expect an HTTP request to fetch the admin token from Rancher
  1357  	mockRequestSender.EXPECT().
  1358  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1359  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1360  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  1361  			resp := &http.Response{
  1362  				StatusCode: http.StatusCreated,
  1363  				Body:       r,
  1364  				Request:    &http.Request{Method: http.MethodPost},
  1365  			}
  1366  			return resp, nil
  1367  		})
  1368  
  1369  	// Expect an HTTP request to import the cluster to Rancher
  1370  	mockRequestSender.EXPECT().
  1371  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  1372  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1373  			r := io.NopCloser(bytes.NewReader([]byte(`{"id":"some-cluster"}`)))
  1374  			resp := &http.Response{
  1375  				StatusCode: http.StatusCreated,
  1376  				Body:       r,
  1377  			}
  1378  			return resp, nil
  1379  		})
  1380  
  1381  	// Expect an HTTP request to get the registration token in Rancher for the clusterId
  1382  	mockRequestSender.EXPECT().
  1383  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  1384  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1385  			asserts.Contains(clusterRegTokenPath, req.URL.Path)
  1386  
  1387  			_, err := io.ReadAll(req.Body)
  1388  			asserts.NoError(err)
  1389  
  1390  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[]}`)))
  1391  			resp := &http.Response{
  1392  				StatusCode: http.StatusOK,
  1393  				Body:       r,
  1394  				Request:    &http.Request{Method: http.MethodGet},
  1395  			}
  1396  			return resp, nil
  1397  		})
  1398  
  1399  	// Expect an HTTP request to create the registration token in Rancher but the call fails
  1400  	mockRequestSender.EXPECT().
  1401  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  1402  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1403  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1404  			resp := &http.Response{
  1405  				StatusCode: http.StatusBadRequest,
  1406  				Body:       r,
  1407  				Request:    &http.Request{Method: http.MethodPost},
  1408  			}
  1409  			return resp, nil
  1410  		})
  1411  
  1412  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1413  	asserts.NoError(err)
  1414  
  1415  	regYAML, _, err = RegisterManagedClusterWithRancher(rc, testManagedCluster, "", vzlog.DefaultLogger())
  1416  
  1417  	mocker.Finish()
  1418  	asserts.Error(err)
  1419  	asserts.Empty(regYAML)
  1420  	rancherutil.DeleteStoredTokens()
  1421  
  1422  	// GIVEN a call to register a managed cluster with Rancher
  1423  	// WHEN the call to get the Rancher manifest YAML fails
  1424  	// THEN the registration call returns an error
  1425  	mocker = gomock.NewController(t)
  1426  	mock = mocks.NewMockClient(mocker)
  1427  	mockRequestSender = mocks.NewMockRequestSender(mocker)
  1428  	rancherutil.RancherHTTPClient = mockRequestSender
  1429  
  1430  	// Expect all of the Kubernetes calls
  1431  	expectRancherConfigK8sCalls(t, mock, false)
  1432  
  1433  	// Expect an HTTP request to fetch the admin token from Rancher
  1434  	mockRequestSender.EXPECT().
  1435  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1436  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1437  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  1438  			resp := &http.Response{
  1439  				StatusCode: http.StatusCreated,
  1440  				Body:       r,
  1441  				Request:    &http.Request{Method: http.MethodPost},
  1442  			}
  1443  			return resp, nil
  1444  		})
  1445  
  1446  	// Expect an HTTP request to import the cluster to Rancher
  1447  	mockRequestSender.EXPECT().
  1448  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  1449  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1450  			r := io.NopCloser(bytes.NewReader([]byte(`{"id":"some-cluster"}`)))
  1451  			resp := &http.Response{
  1452  				StatusCode: http.StatusCreated,
  1453  				Body:       r,
  1454  			}
  1455  			return resp, nil
  1456  		})
  1457  
  1458  	// Expect an HTTP request to get the registration token in Rancher for the clusterId
  1459  	mockRequestSender.EXPECT().
  1460  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  1461  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1462  			asserts.Contains(clusterRegTokenPath, req.URL.Path)
  1463  
  1464  			_, err := io.ReadAll(req.Body)
  1465  			asserts.NoError(err)
  1466  
  1467  			// return a response with the CRT
  1468  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[{"token":"manifest-token","state":"active","clusterId":"some-cluster"}]}`)))
  1469  			resp := &http.Response{
  1470  				StatusCode: http.StatusOK,
  1471  				Body:       r,
  1472  				Request:    &http.Request{Method: http.MethodGet},
  1473  			}
  1474  			return resp, nil
  1475  		})
  1476  
  1477  	// Expect an HTTP request to fetch the manifest YAML from Rancher but the call fails
  1478  	mockRequestSender.EXPECT().
  1479  		Do(gomock.Not(gomock.Nil()), gomock.Not(gomock.Nil())).
  1480  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1481  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1482  			resp := &http.Response{
  1483  				StatusCode: http.StatusUnsupportedMediaType,
  1484  				Body:       r,
  1485  				Request:    &http.Request{Method: http.MethodGet},
  1486  			}
  1487  			return resp, nil
  1488  		})
  1489  
  1490  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1491  	asserts.NoError(err)
  1492  
  1493  	regYAML, _, err = RegisterManagedClusterWithRancher(rc, testManagedCluster, "", vzlog.DefaultLogger())
  1494  
  1495  	mocker.Finish()
  1496  	asserts.Error(err)
  1497  	asserts.Empty(regYAML)
  1498  }
  1499  
  1500  // GIVEN a call to register a managed cluster with Rancher
  1501  // WHEN the call to get the admin token from Rancher fails
  1502  // AND the error is retryable
  1503  // THEN ensure that the request is retried
  1504  func TestRegisterClusterWithRancherRetryRequest(t *testing.T) {
  1505  	// clear any cached user auth tokens when the test completes
  1506  	defer rancherutil.DeleteStoredTokens()
  1507  
  1508  	asserts := assert.New(t)
  1509  	mocker := gomock.NewController(t)
  1510  	mock := mocks.NewMockClient(mocker)
  1511  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1512  
  1513  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1514  	defer func() {
  1515  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1516  	}()
  1517  	rancherutil.RancherHTTPClient = mockRequestSender
  1518  
  1519  	// replace the retry configuration so all of the retries happen very quickly
  1520  	retrySteps := 3
  1521  	savedRetry := rancherutil.DefaultRetry
  1522  	defer func() {
  1523  		rancherutil.DefaultRetry = savedRetry
  1524  	}()
  1525  	rancherutil.DefaultRetry = wait.Backoff{
  1526  		Steps:    retrySteps,
  1527  		Duration: 1 * time.Millisecond,
  1528  		Factor:   1.0,
  1529  		Jitter:   0.1,
  1530  	}
  1531  
  1532  	// Expect all of the Kubernetes calls
  1533  	expectRancherConfigK8sCalls(t, mock, false)
  1534  
  1535  	// Expect an HTTP request to fetch the admin token from Rancher - return an error response and
  1536  	// the request should be retried for a total of "retrySteps" # of times
  1537  	mockRequestSender.EXPECT().
  1538  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1539  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1540  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1541  			resp := &http.Response{
  1542  				StatusCode: http.StatusInternalServerError,
  1543  				Body:       r,
  1544  				Request:    &http.Request{Method: http.MethodPost},
  1545  			}
  1546  			return resp, nil
  1547  		}).Times(retrySteps)
  1548  
  1549  	_, err := rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1550  
  1551  	mocker.Finish()
  1552  	asserts.Error(err)
  1553  }
  1554  
  1555  // newScheme creates a new scheme that includes this package's object to use for testing
  1556  func newScheme() *runtime.Scheme {
  1557  	scheme := runtime.NewScheme()
  1558  	_ = corev1.AddToScheme(scheme)
  1559  	_ = v1alpha1.AddToScheme(scheme)
  1560  	return scheme
  1561  }
  1562  
  1563  // newRequest creates a new reconciler request for testing
  1564  // namespace - The namespace to use in the request
  1565  // testManagedCluster - The testManagedCluster to use in the request
  1566  func newRequest(namespace string, name string) ctrl.Request {
  1567  	return ctrl.Request{
  1568  		NamespacedName: types.NamespacedName{
  1569  			Namespace: namespace,
  1570  			Name:      name}}
  1571  }
  1572  
  1573  // newVMCReconciler creates a new reconciler for testing
  1574  // c - The Kerberos client to inject into the reconciler
  1575  func newVMCReconciler(c client.Client) VerrazzanoManagedClusterReconciler {
  1576  	scheme := newScheme()
  1577  	reconciler := VerrazzanoManagedClusterReconciler{
  1578  		Client: c,
  1579  		Scheme: scheme}
  1580  	return reconciler
  1581  }
  1582  
  1583  func fakeGetConfig() (*rest.Config, error) {
  1584  	conf := rest.Config{
  1585  		TLSClientConfig: rest.TLSClientConfig{
  1586  			CAData: []byte("fakeCA"),
  1587  		},
  1588  	}
  1589  	return &conf, nil
  1590  }
  1591  
  1592  // Expect syncRoleBinding related calls
  1593  func expectSyncRoleBinding(t *testing.T, mock *mocks.MockClient, name string, succeed bool) {
  1594  	asserts := assert.New(t)
  1595  
  1596  	// Expect a call to get the RoleBinding - return that it does not exist
  1597  	mock.EXPECT().
  1598  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1599  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "RoleBinding"}, generateManagedResourceName(name)))
  1600  
  1601  	// Expect a call to create the RoleBinding - return success or failure based on the succeed argument
  1602  	mock.EXPECT().
  1603  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1604  		DoAndReturn(func(ctx context.Context, binding *rbacv1.RoleBinding, opts ...client.CreateOption) error {
  1605  			if succeed {
  1606  				asserts.Equalf(generateManagedResourceName(name), binding.Name, "RoleBinding testManagedCluster did not match")
  1607  				asserts.Equalf(vpoconstants.MCClusterRole, binding.RoleRef.Name, "RoleBinding roleref did not match")
  1608  				asserts.Equalf(generateManagedResourceName(name), binding.Subjects[0].Name, "Subject did not match")
  1609  				asserts.Equalf(constants.VerrazzanoMultiClusterNamespace, binding.Subjects[0].Namespace, "Subject namespace did not match")
  1610  				return nil
  1611  			}
  1612  			return errors.NewInternalError(fmt.Errorf("failing syncRoleBinding"))
  1613  		})
  1614  }
  1615  
  1616  // Expect syncServiceAccount related calls
  1617  func expectSyncServiceAccount(t *testing.T, mock *mocks.MockClient, name string, succeed bool) {
  1618  	asserts := assert.New(t)
  1619  
  1620  	// Expect a call to get the ServiceAccount - return that it does not exist
  1621  	mock.EXPECT().
  1622  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1623  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "ServiceAccount"}, generateManagedResourceName(name)))
  1624  
  1625  	// Expect a call to create the ServiceAccount - return success
  1626  	mock.EXPECT().
  1627  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1628  		DoAndReturn(func(ctx context.Context, serviceAccount *corev1.ServiceAccount, opts ...client.CreateOption) error {
  1629  			asserts.Equalf(constants.VerrazzanoMultiClusterNamespace, serviceAccount.Namespace, "ServiceAccount namespace did not match")
  1630  			asserts.Equalf(generateManagedResourceName(name), serviceAccount.Name, "ServiceAccount testManagedCluster did not match")
  1631  			return nil
  1632  		})
  1633  
  1634  	// Expect a call to get the Token Secret - return that it does not exist
  1635  	mock.EXPECT().
  1636  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name) + "-token"}, gomock.Not(gomock.Nil()), gomock.Any()).
  1637  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, generateManagedResourceName(name)+"-token"))
  1638  
  1639  	// Expect a call to create the Token Secret - return success
  1640  	mock.EXPECT().
  1641  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1642  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1643  			asserts.Equalf(constants.VerrazzanoMultiClusterNamespace, secret.Namespace, "Secret namespace did not match")
  1644  			asserts.Equalf(generateManagedResourceName(name)+"-token", secret.Name, "Secret testManagedCluster did not match")
  1645  			return nil
  1646  		})
  1647  
  1648  	// Expect a call to update the VerrazzanoManagedCluster service account name - return success or
  1649  	// failure depending on the succeed argument
  1650  	mock.EXPECT().
  1651  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  1652  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1653  			if succeed {
  1654  				asserts.Equal(vmc.Spec.ServiceAccount, generateManagedResourceName(name), "ServiceAccount testManagedCluster did not match")
  1655  				return nil
  1656  			}
  1657  			return errors.NewInternalError(fmt.Errorf("failing syncServiceAccount"))
  1658  		})
  1659  }
  1660  
  1661  // Expect syncAgent related calls
  1662  func expectSyncAgent(t *testing.T, mock *mocks.MockClient, name string, rancherEnabled bool, noSASecret bool) {
  1663  	saSecretName := "saSecret"
  1664  	rancherURL := "http://rancher-url"
  1665  	rancherCAData := "rancherCAData"
  1666  	userAPIServerURL := "https://testurl"
  1667  	if noSASecret {
  1668  		// Expect a call to get the ServiceAccount, return without the secret set
  1669  		mock.EXPECT().
  1670  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1671  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, sa *corev1.ServiceAccount, opts ...client.GetOption) error {
  1672  				sa.Name = name.Name
  1673  				return nil
  1674  			})
  1675  		// Set the secret name to the service account token created by the VMC controller
  1676  		saSecretName = generateManagedResourceName(name) + "-token"
  1677  
  1678  	} else {
  1679  		// Expect a call to get the ServiceAccount, return one with the secret testManagedCluster set
  1680  		mock.EXPECT().
  1681  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1682  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, sa *corev1.ServiceAccount, opts ...client.GetOption) error {
  1683  				sa.Secrets = []corev1.ObjectReference{{
  1684  					Name: saSecretName,
  1685  				}}
  1686  				return nil
  1687  			})
  1688  	}
  1689  
  1690  	// Expect a call to list Verrazzanos and return a Verrazzano that has Rancher URL in status only
  1691  	// if rancherEnabled is true
  1692  	mock.EXPECT().
  1693  		List(gomock.Any(), &v1beta1.VerrazzanoList{}, gomock.Not(gomock.Nil())).
  1694  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
  1695  			var status v1beta1.VerrazzanoStatus
  1696  			if rancherEnabled {
  1697  				status = v1beta1.VerrazzanoStatus{
  1698  					VerrazzanoInstance: &v1beta1.InstanceInfo{RancherURL: &rancherURL},
  1699  				}
  1700  			}
  1701  			vz := v1beta1.Verrazzano{
  1702  				Spec:   v1beta1.VerrazzanoSpec{},
  1703  				Status: status,
  1704  			}
  1705  			list.Items = append(list.Items, vz)
  1706  			return nil
  1707  		})
  1708  
  1709  	// Expect a call to get the service token secret, return the secret with the token
  1710  	mock.EXPECT().
  1711  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: saSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  1712  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1713  			secret.Data = map[string][]byte{
  1714  				mcconstants.TokenKey: []byte(token),
  1715  			}
  1716  			return nil
  1717  		})
  1718  
  1719  	if rancherEnabled {
  1720  		// Expect a call to get the tls-ca secret, return the secret as not found
  1721  		mock.EXPECT().
  1722  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.PrivateCABundle}, gomock.Not(gomock.Nil()), gomock.Any()).
  1723  			Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoSystemNamespace, Resource: "Secret"}, constants.PrivateCABundle))
  1724  
  1725  		// Expect a call to get the Rancher ingress tls secret, return the secret with the fields set
  1726  		mock.EXPECT().
  1727  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.RancherSystemNamespace, Name: rancherTLSSecret}, gomock.Not(gomock.Nil()), gomock.Any()).
  1728  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1729  				secret.Data = map[string][]byte{
  1730  					mcconstants.CaCrtKey: []byte(rancherCAData),
  1731  				}
  1732  				return nil
  1733  			})
  1734  	} else {
  1735  		// Expect a call to get the verrazzano-admin-cluster configmap
  1736  		mock.EXPECT().
  1737  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: vpoconstants.AdminClusterConfigMapName}, gomock.Not(gomock.Nil()), gomock.Any()).
  1738  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, cm *corev1.ConfigMap, opts ...client.GetOption) error {
  1739  				cm.Data = map[string]string{
  1740  					vpoconstants.ServerDataKey: userAPIServerURL,
  1741  				}
  1742  				return nil
  1743  			})
  1744  	}
  1745  
  1746  	// Expect a call to get the Agent secret - return that it does not exist
  1747  	mock.EXPECT().
  1748  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetAgentSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1749  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetAgentSecretName(name)))
  1750  
  1751  	// Expect a call to create the Agent secret
  1752  	mock.EXPECT().
  1753  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1754  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1755  			adminKubeconfig := string(secret.Data[mcconstants.KubeconfigKey])
  1756  			if rancherEnabled {
  1757  				assert.Contains(t, adminKubeconfig, "server: "+rancherURL)
  1758  			} else {
  1759  				assert.Contains(t, adminKubeconfig, "server: "+userAPIServerURL)
  1760  			}
  1761  			return nil
  1762  		})
  1763  }
  1764  
  1765  // Expect syncRegistration related calls
  1766  func expectSyncRegistration(t *testing.T, mock *mocks.MockClient, name string, externalES bool, rancherEnabled bool) {
  1767  	const vzEsURLData = "https://vz-testhost:443"
  1768  	const vzUserData = "vz-user"
  1769  	const vzPasswordData = "vz-pw"
  1770  	const vzCaData = "vz-ca"
  1771  
  1772  	const externalEsURLData = "https://external-testhost:443"
  1773  	const externalUserData = "external-user"
  1774  	const externalPasswordData = "external-pw"
  1775  	const externalCaData = "external-ca"
  1776  
  1777  	fluentdESURL := "http://verrazzano-authproxy-opensearch:8775"
  1778  	fluentdESSecret := "verrazzano"
  1779  	esSecret := constants.VerrazzanoESInternal
  1780  	if externalES {
  1781  		fluentdESURL = externalEsURLData
  1782  		fluentdESSecret = "some-external-es-secret"
  1783  		esSecret = fluentdESSecret
  1784  	}
  1785  
  1786  	asserts := assert.New(t)
  1787  
  1788  	// Expect a call to get the registration secret - return that it does not exist
  1789  	mock.EXPECT().
  1790  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetRegistrationSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1791  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetRegistrationSecretName(name)))
  1792  
  1793  	// Expect a call to list Verrazzanos - return the Verrazzano configured with fluentd
  1794  	mock.EXPECT().
  1795  		List(gomock.Any(), &v1beta1.VerrazzanoList{}, gomock.Not(gomock.Nil())).
  1796  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
  1797  			vz := v1beta1.Verrazzano{
  1798  				Spec: v1beta1.VerrazzanoSpec{
  1799  					Components: v1beta1.ComponentSpec{
  1800  						Fluentd: &v1beta1.FluentdComponent{
  1801  							OpenSearchURL:    fluentdESURL,
  1802  							OpenSearchSecret: fluentdESSecret,
  1803  						},
  1804  					},
  1805  				},
  1806  			}
  1807  			if rancherEnabled {
  1808  				vz.Spec.Components.Rancher = &v1beta1.RancherComponent{Enabled: &trueValue}
  1809  			}
  1810  			list.Items = append(list.Items, vz)
  1811  			return nil
  1812  		}).Times(5)
  1813  
  1814  	// Expect a call to get the tls ingress and return the ingress.
  1815  	if !externalES {
  1816  		mock.EXPECT().
  1817  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: operatorOSIngress}, gomock.Not(gomock.Nil()), gomock.Any()).
  1818  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1819  				ingress.TypeMeta = metav1.TypeMeta{
  1820  					APIVersion: "networking.k8s.io/v1",
  1821  					Kind:       "ingress"}
  1822  				ingress.ObjectMeta = metav1.ObjectMeta{
  1823  					Namespace: name.Namespace,
  1824  					Name:      name.Name}
  1825  				ingress.Spec.Rules = []networkingv1.IngressRule{{
  1826  					Host: "vz-testhost",
  1827  				}}
  1828  				return nil
  1829  			})
  1830  	}
  1831  
  1832  	// Expect a call to get the opensearch secret, return the secret with the fields set
  1833  	mock.EXPECT().
  1834  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: esSecret}, gomock.Not(gomock.Nil()), gomock.Any()).
  1835  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1836  			if externalES {
  1837  				secret.Data = map[string][]byte{
  1838  					mcconstants.VerrazzanoUsernameKey: []byte(externalUserData),
  1839  					mcconstants.VerrazzanoPasswordKey: []byte(externalPasswordData),
  1840  					mcconstants.FluentdESCaBundleKey:  []byte(externalCaData),
  1841  				}
  1842  			} else {
  1843  				secret.Data = map[string][]byte{
  1844  					mcconstants.VerrazzanoUsernameKey: []byte(vzUserData),
  1845  					mcconstants.VerrazzanoPasswordKey: []byte(vzPasswordData),
  1846  				}
  1847  			}
  1848  			return nil
  1849  		})
  1850  
  1851  	// Expect a call to get the tls secret, return the secret with the fields set
  1852  	mock.EXPECT().
  1853  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: "verrazzano-tls"}, gomock.Not(gomock.Nil()), gomock.Any()).
  1854  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1855  			secret.Data = map[string][]byte{
  1856  				mcconstants.CaCrtKey: []byte(vzCaData),
  1857  			}
  1858  			return nil
  1859  		})
  1860  
  1861  	// Expect a call to get the tls-ca secret, return the secret as not found
  1862  	mock.EXPECT().
  1863  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.PrivateCABundle}, gomock.Not(gomock.Nil()), gomock.Any()).
  1864  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoSystemNamespace, Resource: "Secret"}, constants.PrivateCABundle))
  1865  
  1866  	// Expect a call to get the keycloak ingress and return the ingress.
  1867  	mock.EXPECT().
  1868  		Get(gomock.Any(), types.NamespacedName{Namespace: "keycloak", Name: "keycloak"}, gomock.Not(gomock.Nil()), gomock.Any()).
  1869  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1870  			ingress.TypeMeta = metav1.TypeMeta{
  1871  				APIVersion: "networking.k8s.io/v1",
  1872  				Kind:       "ingress"}
  1873  			ingress.ObjectMeta = metav1.ObjectMeta{
  1874  				Namespace: name.Namespace,
  1875  				Name:      name.Name}
  1876  			ingress.Spec.Rules = []networkingv1.IngressRule{{
  1877  				Host: "keycloak",
  1878  			}}
  1879  			return nil
  1880  		})
  1881  
  1882  	// Expect a call to get the dex ingress and return the ingress.
  1883  	mock.EXPECT().
  1884  		Get(gomock.Any(), types.NamespacedName{Namespace: "verrazzano-auth", Name: "dex"}, gomock.Not(gomock.Nil()), gomock.Any()).
  1885  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1886  			ingress.TypeMeta = metav1.TypeMeta{
  1887  				APIVersion: "networking.k8s.io/v1",
  1888  				Kind:       "ingress"}
  1889  			ingress.ObjectMeta = metav1.ObjectMeta{
  1890  				Namespace: name.Namespace,
  1891  				Name:      name.Name}
  1892  			ingress.Spec.Rules = []networkingv1.IngressRule{{
  1893  				Host: "auth",
  1894  			}}
  1895  			return nil
  1896  		})
  1897  
  1898  	// Expect a call to create the registration secret
  1899  	mock.EXPECT().
  1900  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1901  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1902  			asserts.Equalf(testManagedCluster, string(secret.Data[mcconstants.ManagedClusterNameKey]), "Incorrect cluster testManagedCluster in Registration secret ")
  1903  			asserts.Equalf("https://keycloak", string(secret.Data[mcconstants.KeycloakURLKey]), "Incorrect admin ca bundle in Registration secret ")
  1904  			asserts.Equalf(vzCaData, string(secret.Data[mcconstants.AdminCaBundleKey]), "Incorrect admin ca bundle in Registration secret ")
  1905  			if externalES {
  1906  				asserts.Equalf(externalEsURLData, string(secret.Data[mcconstants.ESURLKey]), "Incorrect ES URL in Registration secret ")
  1907  				asserts.Equalf(externalCaData, string(secret.Data[mcconstants.ESCaBundleKey]), "Incorrect ES ca bundle in Registration secret ")
  1908  				asserts.Equalf(externalUserData, string(secret.Data[mcconstants.RegistrationUsernameKey]), "Incorrect ES user in Registration secret ")
  1909  				asserts.Equalf(externalPasswordData, string(secret.Data[mcconstants.RegistrationPasswordKey]), "Incorrect ES password in Registration secret ")
  1910  			} else {
  1911  				asserts.Equalf(vzEsURLData, string(secret.Data[mcconstants.ESURLKey]), "Incorrect ES URL in Registration secret ")
  1912  				asserts.Equalf(vzCaData, string(secret.Data[mcconstants.ESCaBundleKey]), "Incorrect ES ca bundle in Registration secret ")
  1913  				asserts.Equalf(vzUserData, string(secret.Data[mcconstants.RegistrationUsernameKey]), "Incorrect ES user in Registration secret ")
  1914  				asserts.Equalf(vzPasswordData, string(secret.Data[mcconstants.RegistrationPasswordKey]), "Incorrect ES password in Registration secret ")
  1915  			}
  1916  			return nil
  1917  		})
  1918  }
  1919  
  1920  // Expect syncManifest related calls
  1921  func expectSyncManifest(t *testing.T, mock *mocks.MockClient, mockStatus *mocks.MockStatusWriter, mockRequestSender *mocks.MockRequestSender, name string, clusterAlreadyRegistered bool, expectedRancherYAML string, rancherEnabled bool, rancherClusterState string) {
  1922  
  1923  	asserts := assert.New(t)
  1924  	clusterName := "cluster1"
  1925  	caData := "ca"
  1926  	userData := "user"
  1927  	passwordData := "pw"
  1928  	kubeconfigData := "fakekubeconfig"
  1929  	urlData := "https://testhost:443"
  1930  
  1931  	if rancherEnabled {
  1932  		// Expect all the calls needed to register the cluster with Rancher
  1933  		expectRegisterClusterWithRancher(t, mock, mockRequestSender, mockStatus, name, clusterAlreadyRegistered, expectedRancherYAML)
  1934  	}
  1935  
  1936  	expectRancherConfigK8sCalls(t, mock, true)
  1937  
  1938  	if rancherClusterState == rancherClusterStateActive {
  1939  		// expect a check for existence of verrazzano-system namespace,
  1940  		mockRequestSender.EXPECT().
  1941  			Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(k8sClustersPath+unitTestRancherClusterID+"/api/v1/namespaces/verrazzano-system")).
  1942  			DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1943  				var resp *http.Response
  1944  				r := io.NopCloser(bytes.NewReader([]byte(`{"kind":"table", "apiVersion":"meta.k8s.io/v1"}`)))
  1945  				resp = &http.Response{
  1946  					StatusCode: http.StatusOK,
  1947  					Body:       r,
  1948  				}
  1949  				return resp, nil
  1950  			})
  1951  
  1952  		// Expect a call to get the Agent secret
  1953  		mock.EXPECT().
  1954  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetAgentSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1955  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1956  				secret.Data = map[string][]byte{
  1957  					mcconstants.KubeconfigKey: []byte(kubeconfigData),
  1958  				}
  1959  				return nil
  1960  			}).MinTimes(1)
  1961  
  1962  		// Expect a call to get the registration secret
  1963  		mock.EXPECT().
  1964  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetRegistrationSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1965  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1966  				secret.Data = map[string][]byte{
  1967  					mcconstants.ManagedClusterNameKey:   []byte(clusterName),
  1968  					mcconstants.CaCrtKey:                []byte(caData),
  1969  					mcconstants.RegistrationUsernameKey: []byte(userData),
  1970  					mcconstants.RegistrationPasswordKey: []byte(passwordData),
  1971  					mcconstants.ESURLKey:                []byte(urlData),
  1972  				}
  1973  				return nil
  1974  			}).MinTimes(1)
  1975  	}
  1976  
  1977  	// Expect a call to get the manifest secret - return that it does not exist
  1978  	mock.EXPECT().
  1979  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetManifestSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1980  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetManifestSecretName(name)))
  1981  
  1982  	// Expect to get existing VMC for status update
  1983  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1984  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1985  			return nil
  1986  		})
  1987  
  1988  	mock.EXPECT().
  1989  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  1990  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1991  			return nil
  1992  		})
  1993  
  1994  	// Expect a call to create the manifest secret
  1995  	mock.EXPECT().
  1996  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1997  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1998  			data := secret.Data[mcconstants.YamlKey]
  1999  			asserts.NotZero(len(data), "Expected yaml data in manifest secret")
  2000  
  2001  			// YAML should contain the Rancher manifest things
  2002  			yamlString := string(data)
  2003  			asserts.True(strings.Contains(yamlString, expectedRancherYAML), "Manifest YAML does not contain the correct Rancher resources")
  2004  
  2005  			return nil
  2006  		})
  2007  
  2008  	// Expect to get existing VMC to update manifest secret entry
  2009  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2010  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2011  			return nil
  2012  		})
  2013  
  2014  	// Expect a call to update the vmc status
  2015  	mock.EXPECT().Status().Return(mockStatus)
  2016  	mockStatus.EXPECT().
  2017  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2018  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2019  			return nil
  2020  		})
  2021  }
  2022  
  2023  func expectPushManifestRequests(t *testing.T, mockRequestSender *mocks.MockRequestSender, mock *mocks.MockClient, rancherClusterState string, vzNSExists bool) {
  2024  	// expect a login request for the vz-cluster-reg user
  2025  	expectRancherGetAuthTokenHTTPCall(t, mockRequestSender)
  2026  
  2027  	mockRequestSender.EXPECT().
  2028  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clustersPath+"/"+unitTestRancherClusterID)).
  2029  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2030  			var resp *http.Response
  2031  			r := io.NopCloser(bytes.NewReader([]byte(`{"state": "` + rancherClusterState + `", "agentImage":"test"}`)))
  2032  			resp = &http.Response{
  2033  				StatusCode: http.StatusOK,
  2034  				Body:       r,
  2035  			}
  2036  			return resp, nil
  2037  		}).MinTimes(2)
  2038  	expectRancherConfigK8sCalls(t, mock, true)
  2039  
  2040  	if rancherClusterState == rancherClusterStateActive {
  2041  		// expect a check for existence of verrazzano-system namespace
  2042  		mockRequestSender.EXPECT().
  2043  			Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(k8sClustersPath+unitTestRancherClusterID+"/api/v1/namespaces/verrazzano-system")).
  2044  			DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2045  				var resp *http.Response
  2046  				if vzNSExists {
  2047  					r := io.NopCloser(bytes.NewReader([]byte(`{"kind":"table", "apiVersion":"meta.k8s.io/v1"}`)))
  2048  					resp = &http.Response{
  2049  						StatusCode: http.StatusOK,
  2050  						Body:       r,
  2051  					}
  2052  				} else {
  2053  					r := io.NopCloser(bytes.NewReader([]byte("")))
  2054  					resp = &http.Response{
  2055  						StatusCode: http.StatusNotFound,
  2056  						Body:       r,
  2057  					}
  2058  				}
  2059  				return resp, nil
  2060  			})
  2061  	}
  2062  }
  2063  
  2064  func expectVmcGetAndUpdate(t *testing.T, mock *mocks.MockClient, name string, caSecretExists bool, rancherClusterAlreadyRegistered bool) {
  2065  	asserts := assert.New(t)
  2066  	labels := map[string]string{"label1": "test"}
  2067  
  2068  	// Expect a call to get the VerrazzanoManagedCluster resource.
  2069  	mock.EXPECT().
  2070  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: name}, gomock.Not(gomock.Nil()), gomock.Any()).
  2071  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2072  			vmc.TypeMeta = metav1.TypeMeta{
  2073  				APIVersion: apiVersion,
  2074  				Kind:       kind}
  2075  			vmc.ObjectMeta = metav1.ObjectMeta{
  2076  				Namespace: name.Namespace,
  2077  				Name:      name.Name,
  2078  				Labels:    labels}
  2079  			if caSecretExists {
  2080  				vmc.Spec = v1alpha1.VerrazzanoManagedClusterSpec{
  2081  					CASecret: getCASecretName(name.Name),
  2082  				}
  2083  			}
  2084  			vmc.Status = v1alpha1.VerrazzanoManagedClusterStatus{
  2085  				PrometheusHost: getPrometheusHost(),
  2086  			}
  2087  			vmc.Status.RancherRegistration = v1alpha1.RancherRegistration{}
  2088  			if rancherClusterAlreadyRegistered {
  2089  				vmc.Status.RancherRegistration.Status = v1alpha1.RegistrationCompleted
  2090  				vmc.Status.RancherRegistration.ClusterID = unitTestRancherClusterID
  2091  			}
  2092  			return nil
  2093  		})
  2094  
  2095  	// Expect a call to update the VerrazzanoManagedCluster finalizer
  2096  	mock.EXPECT().
  2097  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2098  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2099  			asserts.True(len(vmc.ObjectMeta.Finalizers) == 1, "Wrong number of finalizers")
  2100  			asserts.Equal(finalizerName, vmc.ObjectMeta.Finalizers[0], "wrong finalizer")
  2101  			return nil
  2102  		})
  2103  
  2104  }
  2105  
  2106  func expectSyncPrometheusScraper(t *testing.T, mock *mocks.MockClient, vmcName string, prometheusYaml string, jobs string, caSecretExists bool, cacrtSecretData string, f AssertFn, additionalScrapeConfigsAssertFunc secretAssertFn, managedClusterCertsAssertFunc secretAssertFn) {
  2107  	const internalSecretPassword = "nRXlxXgMwN" //nolint:gosec //#gosec G101
  2108  
  2109  	if caSecretExists {
  2110  		// Expect a call to get the prometheus secret - return it
  2111  		mock.EXPECT().
  2112  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: getCASecretName(vmcName)}, gomock.Not(gomock.Nil()), gomock.Any()).
  2113  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2114  
  2115  				secret.Data = map[string][]byte{
  2116  					"cacrt": []byte(cacrtSecretData),
  2117  				}
  2118  				return nil
  2119  			})
  2120  	}
  2121  
  2122  	// Expect a call to get the verrazzano-monitoring namespace
  2123  	mock.EXPECT().
  2124  		Get(gomock.Any(), types.NamespacedName{Name: vpoconstants.VerrazzanoMonitoringNamespace}, gomock.Not(gomock.Nil()), gomock.Any()).
  2125  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ns *corev1.Namespace, opts ...client.GetOption) error {
  2126  			ns.SetName(vpoconstants.VerrazzanoMonitoringNamespace)
  2127  			return nil
  2128  		})
  2129  
  2130  	// Expect a call to get the managed cluster TLS certs secret - return NotFound error
  2131  	mock.EXPECT().
  2132  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: vpoconstants.PromManagedClusterCACertsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2133  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, vpoconstants.PromManagedClusterCACertsSecretName))
  2134  
  2135  	// Expect a call to create the managed cluster TLS certs secret
  2136  	mock.EXPECT().
  2137  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  2138  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2139  			return managedClusterCertsAssertFunc(secret)
  2140  		})
  2141  
  2142  	expectThanosDelete(t, mock)
  2143  
  2144  	// Expect a call to get the additional scrape config secret - return it
  2145  	mock.EXPECT().
  2146  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2147  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2148  			secret.Data = map[string][]byte{
  2149  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2150  			}
  2151  			return nil
  2152  		})
  2153  
  2154  	// Expect a call to get the Verrazzano Prometheus internal secret - return it
  2155  	mock.EXPECT().
  2156  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.VerrazzanoPromInternal}, gomock.Not(gomock.Nil()), gomock.Any()).
  2157  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2158  			secret.Data = map[string][]byte{
  2159  				mcconstants.VerrazzanoPasswordKey: []byte(internalSecretPassword),
  2160  			}
  2161  			return nil
  2162  		})
  2163  
  2164  	// Expect a call to get the additional scrape config secret (we call controllerruntime.CreateOrUpdate so it fetches again) - return it
  2165  	mock.EXPECT().
  2166  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2167  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2168  			secret.Data = map[string][]byte{
  2169  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2170  			}
  2171  			return nil
  2172  		})
  2173  
  2174  	// Expect a call to update the additional scrape config secret
  2175  	mock.EXPECT().
  2176  		Update(gomock.Any(), gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  2177  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2178  			return additionalScrapeConfigsAssertFunc(secret)
  2179  		})
  2180  
  2181  }
  2182  
  2183  // expectRegisterClusterWithRancher asserts all of the expected calls on the Kubernetes client mock and the HTTP client mock
  2184  func expectRegisterClusterWithRancher(t *testing.T, k8sMock *mocks.MockClient, requestSenderMock *mocks.MockRequestSender, mockStatus *mocks.MockStatusWriter, clusterName string, clusterAlreadyRegistered bool, expectedRancherYAML string) {
  2185  
  2186  	expectRancherConfigK8sCalls(t, k8sMock, true)
  2187  	expectRegisterClusterWithRancherHTTPCalls(t, requestSenderMock, clusterName, clusterAlreadyRegistered, expectedRancherYAML)
  2188  	// Expect to get existing VMC to update manifest secret entry
  2189  	k8sMock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2190  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2191  			return nil
  2192  		})
  2193  }
  2194  
  2195  // expectRegisterClusterWithRancherHTTPCalls asserts all of the expected calls on the HTTP client mock
  2196  func expectRegisterClusterWithRancherHTTPCalls(t *testing.T, requestSenderMock *mocks.MockRequestSender, clusterName string, clusterAlreadyRegistered bool, rancherManifestYAML string) {
  2197  	asserts := assert.New(t)
  2198  
  2199  	expectRancherGetAuthTokenHTTPCall(t, requestSenderMock)
  2200  
  2201  	if !clusterAlreadyRegistered {
  2202  		// Cluster is not already registered - we now only expect import to happen if the cluster is NOT already registered
  2203  		// Expect an HTTP request to import the cluster to Rancher
  2204  		requestSenderMock.EXPECT().
  2205  			Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  2206  			DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2207  				asserts.Equal(clusterPath, req.URL.Path)
  2208  
  2209  				var resp *http.Response
  2210  				r := io.NopCloser(bytes.NewReader([]byte(`{"id":"` + unitTestRancherClusterID + `"}`)))
  2211  				resp = &http.Response{
  2212  					StatusCode: http.StatusCreated,
  2213  					Body:       r,
  2214  				}
  2215  				return resp, nil
  2216  			})
  2217  	}
  2218  
  2219  	manifestToken := "unit-test-manifest-token"
  2220  
  2221  	// Expect an HTTP request to get the registration token in Rancher
  2222  	requestSenderMock.EXPECT().
  2223  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  2224  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2225  			asserts.Contains(clusterRegTokenPath, req.URL.Path)
  2226  
  2227  			// assert that the cluster ID in the request body is what we expect
  2228  			_, err := io.ReadAll(req.Body)
  2229  			asserts.NoError(err)
  2230  
  2231  			// return a response with the empty data, no CRT exists for this cluster
  2232  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[]}`)))
  2233  			resp := &http.Response{
  2234  				StatusCode: http.StatusOK,
  2235  				Body:       r,
  2236  				Request:    &http.Request{Method: http.MethodGet},
  2237  			}
  2238  			return resp, nil
  2239  		})
  2240  
  2241  	// Expect an HTTP request to create the registration token in Rancher
  2242  	requestSenderMock.EXPECT().
  2243  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  2244  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2245  			asserts.Equal(clusterRegTokenPath, req.URL.Path)
  2246  
  2247  			// assert that the cluster ID in the request body is what we expect
  2248  			body, err := io.ReadAll(req.Body)
  2249  			asserts.NoError(err)
  2250  			jsonString, err := gabs.ParseJSON(body)
  2251  			asserts.NoError(err)
  2252  			clusterID, ok := jsonString.Path("clusterId").Data().(string)
  2253  			asserts.True(ok)
  2254  			asserts.Equal(unitTestRancherClusterID, clusterID)
  2255  
  2256  			// return a response with the manifest token
  2257  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"` + manifestToken + `"}`)))
  2258  			resp := &http.Response{
  2259  				StatusCode: http.StatusCreated,
  2260  				Body:       r,
  2261  				Request:    &http.Request{Method: http.MethodPost},
  2262  			}
  2263  			return resp, nil
  2264  		})
  2265  
  2266  	// Expect an HTTP request to fetch the manifest YAML from Rancher
  2267  	requestSenderMock.EXPECT().
  2268  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(manifestPath+manifestToken+"_"+unitTestRancherClusterID+".yaml")).
  2269  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2270  			// asserts.Equal(manifestPath+manifestToken+"_"+unitTestRancherClusterID+".yaml", req.URL.Path)
  2271  
  2272  			r := io.NopCloser(bytes.NewReader([]byte(rancherManifestYAML)))
  2273  			resp := &http.Response{
  2274  				StatusCode: http.StatusOK,
  2275  				Body:       r,
  2276  				Request:    &http.Request{Method: http.MethodGet},
  2277  			}
  2278  			return resp, nil
  2279  		}).MinTimes(1)
  2280  }
  2281  
  2282  func expectRancherGetAuthTokenHTTPCall(t *testing.T, requestSenderMock *mocks.MockRequestSender) {
  2283  	asserts := assert.New(t)
  2284  
  2285  	// Expect an HTTP request to fetch the admin token from Rancher
  2286  	requestSenderMock.EXPECT().
  2287  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  2288  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2289  			asserts.Equal(loginQueryString, req.URL.RawQuery)
  2290  
  2291  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  2292  			resp := &http.Response{
  2293  				StatusCode: http.StatusCreated,
  2294  				Body:       r,
  2295  				Request:    &http.Request{Method: http.MethodPost},
  2296  			}
  2297  			return resp, nil
  2298  		}).AnyTimes()
  2299  
  2300  }
  2301  
  2302  func expectThanosDelete(t *testing.T, mock *mocks.MockClient) {
  2303  	// Expect a call to get the Istio CRDs
  2304  	mock.EXPECT().
  2305  		Get(gomock.Any(), gomock.Eq(client.ObjectKey{Name: destinationRuleCRDName}), gomock.AssignableToTypeOf(&apiv1.CustomResourceDefinition{}), gomock.Any()).
  2306  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, crd *apiv1.CustomResourceDefinition, opts ...client.GetOption) error {
  2307  			return errors.NewNotFound(schema.GroupResource{}, "not found")
  2308  		})
  2309  	mock.EXPECT().
  2310  		Get(gomock.Any(), gomock.Eq(client.ObjectKey{Name: serviceEntryCRDName}), gomock.AssignableToTypeOf(&apiv1.CustomResourceDefinition{}), gomock.Any()).
  2311  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, crd *apiv1.CustomResourceDefinition, opts ...client.GetOption) error {
  2312  			return errors.NewNotFound(schema.GroupResource{}, "not found")
  2313  		})
  2314  }
  2315  
  2316  // expectSyncCACertRancherHTTPCalls asserts all of the expected calls on the HTTP client mock when sync'ing the managed cluster
  2317  // CA cert secret
  2318  func expectSyncCACertRancherHTTPCalls(t *testing.T, requestSenderMock *mocks.MockRequestSender, caCertSecretData string, rancherClusterState string) {
  2319  	// Expect an HTTP request to fetch the managed cluster info from Rancher
  2320  	fetchClusterPath := fmt.Sprintf("/v3/clusters/%s", unitTestRancherClusterID)
  2321  	requestSenderMock.EXPECT().
  2322  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(fetchClusterPath)).
  2323  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2324  
  2325  			r := io.NopCloser(bytes.NewReader([]byte(`{"state": "` + rancherClusterState + `", "agentImage":"test-image:1.0.0"}`)))
  2326  			resp := &http.Response{
  2327  				StatusCode: http.StatusOK,
  2328  				Body:       r,
  2329  				Request:    &http.Request{Method: http.MethodGet},
  2330  			}
  2331  			return resp, nil
  2332  		})
  2333  
  2334  	// Expect an HTTP request to fetch the Rancher TLS additional CA secret from the managed cluster and return an HTTP 404
  2335  	managedClusterAdditionalTLSCAPath := fmt.Sprintf("/k8s/clusters/%s/api/v1/namespaces/cattle-system/secrets/tls-ca", unitTestRancherClusterID)
  2336  	requestSenderMock.EXPECT().
  2337  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(managedClusterAdditionalTLSCAPath)).
  2338  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2339  			r := io.NopCloser(bytes.NewReader([]byte{}))
  2340  			resp := &http.Response{
  2341  				StatusCode: http.StatusNotFound,
  2342  				Body:       r,
  2343  				Request:    &http.Request{Method: http.MethodGet},
  2344  			}
  2345  			return resp, nil
  2346  		})
  2347  
  2348  	// Expect an HTTP request to fetch the Verrazzano system TLS CA secret from the managed cluster and return the secret
  2349  	managedClusterSystemCAPath := fmt.Sprintf("/k8s/clusters/%s/api/v1/namespaces/verrazzano-system/secrets/verrazzano-tls", unitTestRancherClusterID)
  2350  	requestSenderMock.EXPECT().
  2351  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(managedClusterSystemCAPath)).
  2352  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2353  			statusCode := http.StatusOK
  2354  			if len(caCertSecretData) == 0 {
  2355  				statusCode = http.StatusNotFound
  2356  			}
  2357  			r := io.NopCloser(bytes.NewReader([]byte(caCertSecretData)))
  2358  			resp := &http.Response{
  2359  				StatusCode: statusCode,
  2360  				Body:       r,
  2361  				Request:    &http.Request{Method: http.MethodGet},
  2362  			}
  2363  			return resp, nil
  2364  		})
  2365  }
  2366  
  2367  // expectSyncCACertRancherK8sCalls asserts all of the expected calls on the Kubernetes client mock when sync'ing the managed cluster
  2368  // CA cert secret
  2369  func expectSyncCACertRancherK8sCalls(t *testing.T, k8sMock *mocks.MockClient, mockRequestSender *mocks.MockRequestSender, shouldSyncCACert bool) {
  2370  	asserts := assert.New(t)
  2371  
  2372  	if shouldSyncCACert {
  2373  		expectRancherConfigK8sCalls(t, k8sMock, true)
  2374  
  2375  		// Expect a call to get the CA cert secret for the managed cluster - return not found
  2376  		k8sMock.EXPECT().
  2377  			Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: "ca-secret-test"}), gomock.Not(gomock.Nil()), gomock.Any()).
  2378  			Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, "ca-secret-test"))
  2379  
  2380  		// Expect a call to create the CA cert secret for the managed cluster
  2381  		k8sMock.EXPECT().
  2382  			Create(gomock.Any(), gomock.Any(), gomock.Any()).
  2383  			DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  2384  				data := secret.Data[caCertSecretKey]
  2385  				asserts.NotZero(len(data), "Expected data in CA cert secret")
  2386  				return nil
  2387  			})
  2388  
  2389  		// Expect a call to update the VMC with ca secret name
  2390  		k8sMock.EXPECT().
  2391  			Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2392  			DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2393  				asserts.Equal(vmc.Spec.CASecret, getCASecretName(vmc.Name), "CA secret name %s did not match", vmc.Spec.CASecret)
  2394  				return nil
  2395  			})
  2396  	}
  2397  }
  2398  
  2399  // getScrapeConfig gets a representation of the vmc scrape configuration from the provided yaml
  2400  func getScrapeConfig(prometheusYaml string, name string) (*gabs.Container, error) {
  2401  	cfg, err := parsePrometheusConfig(prometheusYaml)
  2402  	if err != nil {
  2403  		return nil, err
  2404  	}
  2405  	scrapeConfigs := cfg.Path(scrapeConfigsKey).Children()
  2406  	return getJob(scrapeConfigs, name), nil
  2407  }
  2408  
  2409  // getJob returns the scrape config job identified by the passed name from the slice of scrape configs
  2410  func getJob(scrapeConfigs []*gabs.Container, name string) *gabs.Container {
  2411  	var job *gabs.Container
  2412  	for _, scrapeConfig := range scrapeConfigs {
  2413  		jobName := scrapeConfig.Search(constants.PrometheusJobNameKey).Data()
  2414  		if jobName == name {
  2415  			job = scrapeConfig
  2416  			break
  2417  		}
  2418  	}
  2419  	return job
  2420  }
  2421  
  2422  // getPrometheusHost returns the prometheus host for testManagedCluster
  2423  func getPrometheusHost() string {
  2424  	return "prometheus.vmi.system.default.1.2.3.4.nip.io"
  2425  }
  2426  
  2427  // getPrometheusHost returns the prometheus host for testManagedCluster
  2428  func getCaCrt() string {
  2429  	// this is fake data
  2430  	return "    -----BEGIN CERTIFICATE-----\n" +
  2431  		"    MIIBiDCCAS6gAwIBAgIBADAKBggqhkjOPQQDAjA7MRwwGgYDVQQKExNkeW5hbWlj\n" +
  2432  		"    -----END CERTIFICATE-----"
  2433  }
  2434  
  2435  func expectStatusUpdateReadyCondition(asserts *assert.Assertions, mock *mocks.MockClient, mockStatus *mocks.MockStatusWriter, expectReady corev1.ConditionStatus, msg string, assertManagedCACondition bool) {
  2436  	// mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2437  	//	DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2438  	//		return nil
  2439  	//	})
  2440  
  2441  	mock.EXPECT().Status().Return(mockStatus)
  2442  	mockStatus.EXPECT().
  2443  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2444  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2445  			readyFound := false
  2446  			managedCaFound := false
  2447  			readyConditionCount := 0
  2448  			managedCaConditionCount := 0
  2449  			for _, condition := range vmc.Status.Conditions {
  2450  				if condition.Type == v1alpha1.ConditionReady {
  2451  					readyConditionCount++
  2452  					if condition.Status == expectReady {
  2453  						readyFound = true
  2454  						asserts.Contains(condition.Message, msg)
  2455  					}
  2456  				}
  2457  				if condition.Type == v1alpha1.ConditionManagedCARetrieved {
  2458  					managedCaConditionCount++
  2459  					if condition.Status == expectReady {
  2460  						managedCaFound = true
  2461  						// asserts.Contains(condition.Message, msg)
  2462  					}
  2463  				}
  2464  			}
  2465  			asserts.True(readyFound, "Expected Ready condition on VMC not found")
  2466  			asserts.Equal(1, readyConditionCount, "Found more than one Ready condition")
  2467  			if assertManagedCACondition {
  2468  				asserts.True(managedCaFound, "Expected ManagedCARetrieved condition on VMC not found")
  2469  				asserts.Equal(1, managedCaConditionCount, "Found more than one ManagedCARetrieved condition")
  2470  			}
  2471  
  2472  			return nil
  2473  		})
  2474  }
  2475  
  2476  // validateScrapeConfig validates that a scrape config job has the expected field names and values
  2477  func validateScrapeConfig(t *testing.T, scrapeConfig *gabs.Container, caBasePath string, expectTLSConfig bool) {
  2478  	asserts := assert.New(t)
  2479  	asserts.NotNil(scrapeConfig)
  2480  	asserts.Equal(getPrometheusHost(),
  2481  		scrapeConfig.Search("static_configs", "0", "targets", "0").Data(), "No host entry found")
  2482  	asserts.NotEmpty(scrapeConfig.Search("basic_auth", "password").Data(), "No password")
  2483  
  2484  	// assert that the verrazzano_cluster label is added in the static config
  2485  	asserts.Equal(testManagedCluster, scrapeConfig.Search(
  2486  		"static_configs", "0", "labels", "verrazzano_cluster").Data(),
  2487  		"Label verrazzano_cluster not set correctly in static_configs")
  2488  
  2489  	// assert that the VMC job relabels verrazzano_cluster label to the right value
  2490  	asserts.Equal("verrazzano_cluster", scrapeConfig.Search("metric_relabel_configs", "0",
  2491  		"target_label").Data(),
  2492  		"metric_relabel_configs entry to post-process verrazzano_cluster label does not have expected target_label value")
  2493  	asserts.Equal(testManagedCluster, scrapeConfig.Search("metric_relabel_configs", "0",
  2494  		"replacement").Data(),
  2495  		"metric_relabel_configs entry to post-process verrazzano_cluster label does not have right replacement value")
  2496  	schemePath := scrapeConfig.Path("scheme")
  2497  	tlsScrapeConfig := scrapeConfig.Search("tls_config", "ca_file")
  2498  	if expectTLSConfig {
  2499  		asserts.Equal("https", schemePath.Data(), "wrong scheme")
  2500  		assert.NotNil(t, tlsScrapeConfig)
  2501  		asserts.Equal(caBasePath+"ca-test", tlsScrapeConfig.Data(), "Wrong cert path")
  2502  	} else {
  2503  		assert.Nil(t, tlsScrapeConfig)
  2504  		asserts.Equal("https", schemePath.Data(), "wrong scheme")
  2505  	}
  2506  }
  2507  
  2508  // expectRancherConfigK8sCalls asserts all of the expected calls on the Kubernetes client mock
  2509  // when creating a new Rancher config for the purpose of making http calls
  2510  func expectRancherConfigK8sCalls(t *testing.T, k8sMock *mocks.MockClient, admin bool) {
  2511  	// Expect a call to get the ingress host name
  2512  	k8sMock.EXPECT().
  2513  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  2514  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  2515  			rule := networkingv1.IngressRule{Host: "rancher.unit-test.com"}
  2516  			ingress.Spec.Rules = append(ingress.Spec.Rules, rule)
  2517  			return nil
  2518  		})
  2519  
  2520  	// Expect a call to get the secret with the Rancher root CA cert
  2521  	k8sMock.EXPECT().
  2522  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherTLSSecret}), gomock.Not(gomock.Nil()), gomock.Any()).
  2523  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2524  			secret.Data = map[string][]byte{
  2525  				"ca.crt": {},
  2526  			}
  2527  			return nil
  2528  		})
  2529  
  2530  	secNS := constants.VerrazzanoMultiClusterNamespace
  2531  	secName := constants.VerrazzanoClusterRancherName
  2532  	if admin {
  2533  		secNS = constants.RancherSystemNamespace
  2534  		secName = rancherAdminSecret
  2535  	}
  2536  	// Expect a call to get the admin secret
  2537  	k8sMock.EXPECT().
  2538  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: secNS, Name: secName}), gomock.Not(gomock.Nil()), gomock.Any()).
  2539  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2540  			secret.Data = map[string][]byte{
  2541  				"password": []byte("super-secret"),
  2542  			}
  2543  			return nil
  2544  		})
  2545  
  2546  	// Expect a call to get the Rancher additional CA secret
  2547  	k8sMock.EXPECT().
  2548  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.PrivateCABundle}), gomock.Not(gomock.Nil()), gomock.Any()).
  2549  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoSystemNamespace, Resource: "Secret"}, constants.PrivateCABundle))
  2550  }
  2551  
  2552  // expectMockCallsForDelete mocks expectations for the VMC deletion scenario. These are the common mock expectations across
  2553  // tests that exercise delete functionality. Individual tests add mock expectations after these to test various scenarios.
  2554  func expectMockCallsForDelete(t *testing.T, mock *mocks.MockClient, namespace string) {
  2555  	asserts := assert.New(t)
  2556  
  2557  	// Expect a call to get the VerrazzanoManagedCluster resource.
  2558  	mock.EXPECT().
  2559  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.Not(gomock.Nil()), gomock.Any()).
  2560  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2561  			vmc.TypeMeta = metav1.TypeMeta{
  2562  				APIVersion: apiVersion,
  2563  				Kind:       kind}
  2564  			vmc.ObjectMeta = metav1.ObjectMeta{
  2565  				Namespace:         name.Namespace,
  2566  				Name:              name.Name,
  2567  				DeletionTimestamp: &metav1.Time{Time: time.Now()},
  2568  				Finalizers:        []string{finalizerName}}
  2569  			vmc.Status = v1alpha1.VerrazzanoManagedClusterStatus{
  2570  				PrometheusHost: getPrometheusHost(),
  2571  				RancherRegistration: v1alpha1.RancherRegistration{
  2572  					ClusterID: unitTestRancherClusterID,
  2573  				},
  2574  			}
  2575  
  2576  			return nil
  2577  		})
  2578  
  2579  	jobs := `  - ` + constants.PrometheusJobNameKey + `: test
  2580      scrape_interval: 20s
  2581      scrape_timeout: 15s
  2582      scheme: http
  2583    - ` + constants.PrometheusJobNameKey + `: test2
  2584      scrape_interval: 20s
  2585      scrape_timeout: 15s
  2586      scheme: http`
  2587  
  2588  	// Expect a call to get the additional scrape config secret - return it configured with the two scrape jobs
  2589  	mock.EXPECT().
  2590  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2591  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2592  			secret.Data = map[string][]byte{
  2593  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2594  			}
  2595  			return nil
  2596  		})
  2597  
  2598  	// Expect a call to get the additional scrape config secret (we call controllerruntime.CreateOrUpdate so it fetches again) - return it
  2599  	mock.EXPECT().
  2600  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2601  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2602  			secret.Data = map[string][]byte{
  2603  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2604  			}
  2605  			return nil
  2606  		})
  2607  
  2608  	// Expect a call to update the additional scrape config secret
  2609  	mock.EXPECT().
  2610  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2611  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2612  			// validate that the scrape config for the managed cluster is no longer present
  2613  			scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]))
  2614  			if err != nil {
  2615  				return err
  2616  			}
  2617  			asserts.Len(scrapeConfigs.Children(), 1, "Expected only one scrape config")
  2618  			scrapeJobName := scrapeConfigs.Children()[0].Search(constants.PrometheusJobNameKey).Data()
  2619  			asserts.Equal("test2", scrapeJobName)
  2620  			return nil
  2621  		})
  2622  
  2623  	// Expect a call to get the verrazzano-monitoring namespace
  2624  	mock.EXPECT().
  2625  		Get(gomock.Any(), types.NamespacedName{Name: vpoconstants.VerrazzanoMonitoringNamespace}, gomock.Not(gomock.Nil()), gomock.Any()).
  2626  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ns *corev1.Namespace, opts ...client.GetOption) error {
  2627  			ns.SetName(vpoconstants.VerrazzanoMonitoringNamespace)
  2628  			return nil
  2629  		})
  2630  
  2631  	// Expect a call to get the managed cluster TLS certs secret - return it configured with two managed cluster certs
  2632  	mock.EXPECT().
  2633  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: vpoconstants.PromManagedClusterCACertsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2634  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2635  			secret.Data = map[string][]byte{
  2636  				"ca-test":  []byte("ca-cert-1"),
  2637  				"ca-test2": []byte("ca-cert-1"),
  2638  			}
  2639  			return nil
  2640  		})
  2641  
  2642  	// Expect a call to update the managed cluster TLS certs secret
  2643  	mock.EXPECT().
  2644  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2645  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2646  			// validate that the cert for the cluster being deleted is no longer present
  2647  			asserts.Len(secret.Data, 1, "Expected only one managed cluster cert")
  2648  			asserts.Contains(secret.Data, "ca-test2", "Expected to find cert for managed cluster not being deleted")
  2649  			return nil
  2650  		})
  2651  
  2652  	// Expect a call to delete the argocd cluster secret
  2653  	mock.EXPECT().
  2654  		Delete(gomock.Any(), gomock.Any(), gomock.Any()).
  2655  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2656  			return nil
  2657  		})
  2658  
  2659  	// Expect Rancher k8s calls to configure the API client
  2660  	expectRancherConfigK8sCalls(t, mock, true)
  2661  }
  2662  
  2663  func expectMockCallsForCreateClusterRoleBindingTemplate(mock *mocks.MockClient, clusterID string) {
  2664  	name := fmt.Sprintf("crtb-verrazzano-cluster-%s", clusterID)
  2665  	mock.EXPECT().
  2666  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Name: name, Namespace: clusterID}), gomock.Not(gomock.Nil()), gomock.Any()).
  2667  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, resource *unstructured.Unstructured, opts ...client.GetOption) error {
  2668  			data := resource.UnstructuredContent()
  2669  			data[ClusterRoleTemplateBindingAttributeClusterName] = clusterID
  2670  			data[ClusterRoleTemplateBindingAttributeUserName] = constants.VerrazzanoClusterRancherUsername
  2671  			data[ClusterRoleTemplateBindingAttributeRoleTemplateName] = constants.VerrazzanoClusterRancherName
  2672  			return nil
  2673  		})
  2674  }
  2675  
  2676  func expectMockCallsForListingRancherUsers(mock *mocks.MockClient) {
  2677  	usersList := unstructured.UnstructuredList{}
  2678  	usersList.SetGroupVersionKind(schema.GroupVersionKind{
  2679  		Group:   APIGroupRancherManagement,
  2680  		Version: APIGroupVersionRancherManagement,
  2681  		Kind:    UserListKind,
  2682  	})
  2683  	mock.EXPECT().
  2684  		List(gomock.Any(), &usersList, gomock.Not(gomock.Nil())).
  2685  		DoAndReturn(func(ctx context.Context, userList *unstructured.UnstructuredList, options *client.ListOptions) error {
  2686  			user := unstructured.Unstructured{}
  2687  			user.SetGroupVersionKind(schema.GroupVersionKind{
  2688  				Group:   APIGroupRancherManagement,
  2689  				Version: APIGroupVersionRancherManagement,
  2690  				Kind:    UserKind,
  2691  			})
  2692  			user.SetName(constants.VerrazzanoClusterRancherUsername)
  2693  			data := user.UnstructuredContent()
  2694  			data[UserUsernameAttribute] = constants.VerrazzanoClusterRancherUsername
  2695  			userList.Items = []unstructured.Unstructured{user}
  2696  			return nil
  2697  		})
  2698  }