github.com/verrazzano/verrazzano@v1.7.0/application-operator/mcagent/mcagent_cluster_secrets_test.go (about)

     1  // Copyright (c) 2022, 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 mcagent
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"fmt"
    10  	"path/filepath"
    11  	"testing"
    12  
    13  	asserts "github.com/stretchr/testify/assert"
    14  	"github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    15  	"github.com/verrazzano/verrazzano/pkg/constants"
    16  	"github.com/verrazzano/verrazzano/pkg/mcconstants"
    17  	constants2 "github.com/verrazzano/verrazzano/platform-operator/constants"
    18  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    19  	corev1 "k8s.io/api/core/v1"
    20  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    21  
    22  	clusterstest "github.com/verrazzano/verrazzano/application-operator/controllers/clusters/test"
    23  	"go.uber.org/zap"
    24  	"k8s.io/apimachinery/pkg/runtime"
    25  	"k8s.io/apimachinery/pkg/types"
    26  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    27  )
    28  
    29  const (
    30  	clusterRegSecretPath       = "testdata/clusterca-clusterregsecret.yaml"
    31  	adminRegSecretPath         = "testdata/clusterca-adminregsecret.yaml"
    32  	adminRegNewSecretPath      = "testdata/clusterca-adminregsecret-new.yaml"
    33  	clusterCAAdminSecretPath   = "testdata/clusterca-admincasecret.yaml"
    34  	mcCASecretPath             = "testdata/clusterca-mccasecret.yaml"
    35  	adminAgentSecretPath       = "testdata/admin-agent-secret.yaml"
    36  	adminAgentNewSecretPath    = "testdata/admin-agent-secret-new.yaml"
    37  	vzTLSSecretPathNew         = "testdata/clusterca-mctlssecret-new.yaml"
    38  	vzTLSSecretPath            = "testdata/clusterca-mctlssecret.yaml"
    39  	vmcPath                    = "testdata/clusterca-vmc.yaml"
    40  	noCAVMCPath                = "testdata/no-clusterca-vmc.yaml"
    41  	sampleAdminCAReadErrMsg    = "failed to read sample Admin CA Secret"
    42  	sampleClusterRegReadErrMsg = "failed to read sample Managed Cluster Registration Secret"
    43  	sampleAdminRegReadErrMsg   = "failed to read sample Admin Cluster Registration Secret for the managed cluster"
    44  	sampleMCTLSReadErrMsg      = "failed to read sample MC TLS Secret"
    45  	sampleMCCAReadErrMsg       = "failed to read sample MC CA Secret"
    46  	sampleVMCReadErrMsg        = "failed to read sample VMC"
    47  	regSecChangedErrMsg        = "registration secret was changed"
    48  	mcCASecChangedErrMsg       = "MC CA secret was changed"
    49  	sampleAdminAgentReadErrMsg = "failed to read sample Admin agent Secret"
    50  )
    51  
    52  // TestSyncAdminCANoDifference tests the synchronization method for the following use case.
    53  // GIVEN a request to sync Admin registration info
    54  // WHEN the CAs are the same and registration info is the same
    55  // THEN ensure that no secret is updated.
    56  func TestSyncCACertsNoDifference(t *testing.T) {
    57  	assert := asserts.New(t)
    58  	log := zap.S().With("test")
    59  
    60  	// Test data
    61  	testAdminCASecret, err := getSampleSecret(clusterCAAdminSecretPath)
    62  	assert.NoError(err, sampleAdminCAReadErrMsg)
    63  
    64  	testAdminRegSecret, err := getSampleSecret(adminRegSecretPath)
    65  	assert.NoError(err, sampleAdminRegReadErrMsg)
    66  
    67  	testClusterRegSecret, err := getSampleSecret(clusterRegSecretPath)
    68  	assert.NoError(err, sampleClusterRegReadErrMsg)
    69  
    70  	testMCTLSSecret, err := getSampleSecret(vzTLSSecretPath)
    71  	assert.NoError(err, sampleMCTLSReadErrMsg)
    72  
    73  	testMCCASecret, err := getSampleSecret(mcCASecretPath)
    74  	assert.NoError(err, sampleMCCAReadErrMsg)
    75  
    76  	testVMC, err := getSampleClusterCAVMC(vmcPath)
    77  	assert.NoError(err, sampleVMCReadErrMsg)
    78  
    79  	origRegCA := testClusterRegSecret.Data[mcconstants.AdminCaBundleKey]
    80  	origMCCA := testMCCASecret.Data[keyCaCrtNoDot]
    81  
    82  	adminClient := fake.NewClientBuilder().
    83  		WithScheme(newClusterCAScheme()).
    84  		WithRuntimeObjects(&testAdminCASecret, &testMCCASecret, &testVMC, &testAdminRegSecret).
    85  		Build()
    86  
    87  	localClient := fake.NewClientBuilder().
    88  		WithScheme(newClusterCAScheme()).
    89  		WithRuntimeObjects(&testClusterRegSecret, &testMCTLSSecret).
    90  		Build()
    91  
    92  	// Make the request
    93  	s := &Syncer{
    94  		AdminClient:        adminClient,
    95  		LocalClient:        localClient,
    96  		Log:                log,
    97  		ManagedClusterName: testClusterName,
    98  		Context:            context.TODO(),
    99  	}
   100  	localClusterResult, err := s.syncClusterCAs()
   101  
   102  	// Validate the results
   103  	assert.NoError(err)
   104  
   105  	// assert no update on local cluster
   106  	assert.Equal(controllerutil.OperationResultNone, localClusterResult)
   107  
   108  	// Verify the CA secrets were not updated
   109  	localSecret := &corev1.Secret{}
   110  	err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testClusterRegSecret.Name, Namespace: testClusterRegSecret.Namespace}, localSecret)
   111  	assert.NoError(err)
   112  	assert.Equal(origRegCA, localSecret.Data[mcconstants.AdminCaBundleKey], regSecChangedErrMsg)
   113  
   114  	adminSecret := &corev1.Secret{}
   115  	err = s.AdminClient.Get(s.Context, types.NamespacedName{Name: testMCCASecret.Name, Namespace: testMCCASecret.Namespace}, adminSecret)
   116  	assert.NoError(err)
   117  	assert.Equal(origMCCA, adminSecret.Data[keyCaCrtNoDot], mcCASecChangedErrMsg)
   118  
   119  	// The registration info should not have been changed since the admin secret had the same info
   120  	// as the existing managed cluster registration secret
   121  	assertRegistrationInfoEqual(t, localSecret, testClusterRegSecret)
   122  }
   123  
   124  // TestSyncCACertsAreDifferent tests the synchronization method for the following use case.
   125  // GIVEN a request to sync Admin CA certs
   126  // WHEN the CAs are different but registration info is same,
   127  // THEN ensure that the secrets are updated, but nothing else is
   128  func TestSyncCACertsAreDifferent(t *testing.T) {
   129  	assert := asserts.New(t)
   130  	log := zap.S().With("test")
   131  
   132  	// Test data
   133  	testAdminCASecret, err := getSampleSecret("testdata/clusterca-admincasecret-new.yaml")
   134  	assert.NoError(err, sampleAdminCAReadErrMsg)
   135  
   136  	testAdminRegSecret, err := getSampleSecret(adminRegSecretPath)
   137  	assert.NoError(err, sampleAdminRegReadErrMsg)
   138  
   139  	testClusterRegSecret, err := getSampleSecret(clusterRegSecretPath)
   140  	assert.NoError(err, sampleClusterRegReadErrMsg)
   141  
   142  	testMCTLSSecret, err := getSampleSecret(vzTLSSecretPathNew)
   143  	assert.NoError(err, sampleMCTLSReadErrMsg)
   144  
   145  	testMCCASecret, err := getSampleSecret(mcCASecretPath)
   146  	assert.NoError(err, sampleMCCAReadErrMsg)
   147  
   148  	testVMC, err := getSampleClusterCAVMC(vmcPath)
   149  	assert.NoError(err, sampleVMCReadErrMsg)
   150  
   151  	newRegCA := testAdminCASecret.Data[mcconstants.AdminCaBundleKey]
   152  	newMCCA := testMCTLSSecret.Data[mcconstants.CaCrtKey]
   153  
   154  	adminClient := fake.NewClientBuilder().
   155  		WithScheme(newClusterCAScheme()).
   156  		WithRuntimeObjects(&testAdminCASecret, &testMCCASecret, &testVMC, &testAdminRegSecret).
   157  		Build()
   158  
   159  	localClient := fake.NewClientBuilder().
   160  		WithScheme(newClusterCAScheme()).
   161  		WithRuntimeObjects(&testClusterRegSecret, &testMCTLSSecret).
   162  		Build()
   163  
   164  	// Make the request
   165  	s := &Syncer{
   166  		AdminClient:        adminClient,
   167  		LocalClient:        localClient,
   168  		Log:                log,
   169  		ManagedClusterName: testClusterName,
   170  		Context:            context.TODO(),
   171  	}
   172  	localClusterResult, err := s.syncClusterCAs()
   173  
   174  	// Validate the results
   175  	assert.NoError(err)
   176  
   177  	// assert there was a change on local cluster
   178  	assert.NotEqual(controllerutil.OperationResultNone, localClusterResult)
   179  
   180  	// Verify the CA secrets were updated
   181  	localSecret := &corev1.Secret{}
   182  	err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testClusterRegSecret.Name, Namespace: testClusterRegSecret.Namespace}, localSecret)
   183  	assert.NoError(err)
   184  	assert.Equal(newRegCA, localSecret.Data[mcconstants.AdminCaBundleKey], regSecChangedErrMsg)
   185  
   186  	adminSecret := &corev1.Secret{}
   187  	err = s.AdminClient.Get(s.Context, types.NamespacedName{Name: testMCCASecret.Name, Namespace: testMCCASecret.Namespace}, adminSecret)
   188  	assert.NoError(err)
   189  	assert.Equal(newMCCA, adminSecret.Data[keyCaCrtNoDot], mcCASecChangedErrMsg)
   190  
   191  	// The registration info should not have been changed since the admin secret had the same info
   192  	// as the existing managed cluster registration secret
   193  	assertRegistrationInfoEqual(t, localSecret, testClusterRegSecret)
   194  }
   195  
   196  // Test the case when managed cluster uses Let's Encrypt staging (i.e. the verrazzano-tls-ca secret
   197  // is present, and is preferred for sync even if verrazzano-tls is present.)
   198  func TestSyncCACertsAdditionalTLSPresent(t *testing.T) {
   199  	assert := asserts.New(t)
   200  	log := zap.S().With("test")
   201  
   202  	// Test data
   203  	testAdminCASecret, err := getSampleSecret("testdata/clusterca-admincasecret-new.yaml")
   204  	assert.NoError(err, sampleAdminCAReadErrMsg)
   205  
   206  	testAdminRegSecret, err := getSampleSecret(adminRegSecretPath)
   207  	assert.NoError(err, sampleAdminRegReadErrMsg)
   208  
   209  	testClusterRegSecret, err := getSampleSecret(clusterRegSecretPath)
   210  	assert.NoError(err, sampleClusterRegReadErrMsg)
   211  
   212  	// Managed cluster "normal" VZ ingress TLS secret (verrazzano-tls)
   213  	testMCTLSSecret, err := getSampleSecret(vzTLSSecretPathNew)
   214  	assert.NoError(err, sampleMCTLSReadErrMsg)
   215  
   216  	// Managed cluster additional TLS secret is also present
   217  	testMCAdditionalTLSSecret, err := getSampleSecret("testdata/clusterca-mc-verrazzanotls-secret.yaml")
   218  	assert.NoError(err, "failed to read sample MC additional TLS CA Secret")
   219  
   220  	testMCCASecret, err := getSampleSecret(mcCASecretPath)
   221  	assert.NoError(err, sampleMCCAReadErrMsg)
   222  
   223  	testVMC, err := getSampleClusterCAVMC(vmcPath)
   224  	assert.NoError(err, sampleVMCReadErrMsg)
   225  
   226  	newRegCA := testAdminCASecret.Data[mcconstants.AdminCaBundleKey]
   227  	// Managed cluster private CA bundle secret is the one to sync to admin cluster
   228  	newMCCA := testMCAdditionalTLSSecret.Data[constants.CABundleKey]
   229  
   230  	adminClient := fake.NewClientBuilder().
   231  		WithScheme(newClusterCAScheme()).
   232  		WithRuntimeObjects(&testAdminCASecret, &testMCCASecret, &testVMC, &testAdminRegSecret).
   233  		Build()
   234  
   235  	localClient := fake.NewClientBuilder().
   236  		WithScheme(newClusterCAScheme()).
   237  		WithRuntimeObjects(&testClusterRegSecret, &testMCTLSSecret, &testMCAdditionalTLSSecret).
   238  		Build()
   239  
   240  	// Make the request
   241  	s := &Syncer{
   242  		AdminClient:        adminClient,
   243  		LocalClient:        localClient,
   244  		Log:                log,
   245  		ManagedClusterName: testClusterName,
   246  		Context:            context.TODO(),
   247  	}
   248  	localClusterResult, err := s.syncClusterCAs()
   249  
   250  	// Validate the results
   251  	assert.NoError(err)
   252  
   253  	// assert there was a change on local cluster
   254  	assert.NotEqual(controllerutil.OperationResultNone, localClusterResult)
   255  
   256  	// Verify the CA secrets were updated
   257  	localSecret := &corev1.Secret{}
   258  	err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testClusterRegSecret.Name, Namespace: testClusterRegSecret.Namespace}, localSecret)
   259  	assert.NoError(err)
   260  	assert.Equal(newRegCA, localSecret.Data[mcconstants.AdminCaBundleKey], regSecChangedErrMsg)
   261  
   262  	adminSecret := &corev1.Secret{}
   263  	err = s.AdminClient.Get(s.Context, types.NamespacedName{Name: testMCCASecret.Name, Namespace: testMCCASecret.Namespace}, adminSecret)
   264  	assert.NoError(err)
   265  	assert.Equal(newMCCA, adminSecret.Data[keyCaCrtNoDot], "MC CA secret on admin cluster did not match the additional TLS CA secret on managed cluster.")
   266  
   267  	// Registration info should not have changed
   268  	assertRegistrationInfoEqual(t, localSecret, testClusterRegSecret)
   269  }
   270  
   271  // TestSyncRegistrationInfoDifferent tests the synchronization method for the following use case.
   272  // GIVEN a request to sync Admin registration info
   273  // WHEN the registration info is different but CAs are the same,
   274  // THEN ensure that the reg info is updated, but nothing else is
   275  func TestSyncRegistrationInfoDifferent(t *testing.T) {
   276  	assert := asserts.New(t)
   277  	log := zap.S().With("test")
   278  
   279  	// Test data
   280  
   281  	// Admin CA secret is the unchanged one
   282  	testAdminCASecret, err := getSampleSecret(clusterCAAdminSecretPath)
   283  	assert.NoError(err, sampleAdminCAReadErrMsg)
   284  
   285  	// Use the "updated" admin registration data to simulate admin cluster reg secret changed
   286  	testAdminRegSecret, err := getSampleSecret(adminRegNewSecretPath)
   287  	assert.NoError(err, sampleAdminRegReadErrMsg)
   288  
   289  	testClusterRegSecret, err := getSampleSecret(clusterRegSecretPath)
   290  	assert.NoError(err, sampleClusterRegReadErrMsg)
   291  
   292  	testMCCASecret, err := getSampleSecret(mcCASecretPath)
   293  	assert.NoError(err, sampleMCCAReadErrMsg)
   294  
   295  	testMCTLSSecret, err := getSampleSecret(vzTLSSecretPath)
   296  	assert.NoError(err, sampleMCTLSReadErrMsg)
   297  
   298  	testVMC, err := getSampleClusterCAVMC(vmcPath)
   299  	assert.NoError(err, sampleVMCReadErrMsg)
   300  
   301  	origRegCA := testClusterRegSecret.Data[mcconstants.AdminCaBundleKey]
   302  	origMCCA := testMCCASecret.Data[keyCaCrtNoDot]
   303  	newRegSecret := testAdminRegSecret
   304  
   305  	adminClient := fake.NewClientBuilder().
   306  		WithScheme(newClusterCAScheme()).
   307  		WithRuntimeObjects(&testAdminCASecret, &testMCCASecret, &testVMC, &testAdminRegSecret).
   308  		Build()
   309  
   310  	localClient := fake.NewClientBuilder().
   311  		WithScheme(newClusterCAScheme()).
   312  		WithRuntimeObjects(&testClusterRegSecret, &testMCTLSSecret).
   313  		Build()
   314  
   315  	// Make the request
   316  	s := &Syncer{
   317  		AdminClient:        adminClient,
   318  		LocalClient:        localClient,
   319  		Log:                log,
   320  		ManagedClusterName: testClusterName,
   321  		Context:            context.TODO(),
   322  	}
   323  	localClusterResult, err := s.syncClusterCAs()
   324  
   325  	// Validate the results
   326  	assert.NoError(err)
   327  
   328  	// assert there was a change on local cluster
   329  	assert.NotEqual(controllerutil.OperationResultNone, localClusterResult)
   330  
   331  	// Verify the CA secrets were NOT updated
   332  	localSecret := &corev1.Secret{}
   333  	err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testClusterRegSecret.Name, Namespace: testClusterRegSecret.Namespace}, localSecret)
   334  	assert.NoError(err)
   335  	assert.Equal(origRegCA, localSecret.Data[mcconstants.AdminCaBundleKey], regSecChangedErrMsg)
   336  
   337  	adminSecret := &corev1.Secret{}
   338  	err = s.AdminClient.Get(s.Context, types.NamespacedName{Name: testMCCASecret.Name, Namespace: testMCCASecret.Namespace}, adminSecret)
   339  	assert.NoError(err)
   340  	assert.Equal(origMCCA, adminSecret.Data[keyCaCrtNoDot], mcCASecChangedErrMsg)
   341  
   342  	// The registration info SHOULD have been changed since the admin secret had different info
   343  	// from the existing managed cluster registration secret
   344  	assertRegistrationInfoEqual(t, localSecret, newRegSecret)
   345  }
   346  
   347  func TestSyncRegistrationFromAdminCluster(t *testing.T) {
   348  	testAdminCASecret, err := getSampleSecret(clusterCAAdminSecretPath)
   349  	asserts.NoError(t, err, sampleAdminCAReadErrMsg)
   350  	log := zap.S().With("test")
   351  	tests := []struct {
   352  		name                    string
   353  		testAdminCASecret       *corev1.Secret
   354  		adminRegistrationSecret *corev1.Secret
   355  		localRegistrationSecret *corev1.Secret
   356  		expectedOperation       controllerutil.OperationResult
   357  		expectedError           error
   358  	}{
   359  		{
   360  			"OS url is updated in admin cluster but not synced to managed1",
   361  			&testAdminCASecret,
   362  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   363  				mcconstants.ESURLKey: "new OS url",
   364  			}, "", ""),
   365  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   366  			controllerutil.OperationResultUpdated,
   367  			nil,
   368  		},
   369  		{
   370  			"OS CA bundle is updated in admin cluster but not synced to managed1",
   371  			&testAdminCASecret,
   372  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   373  				mcconstants.ESCaBundleKey: "new CA bundle",
   374  			}, "", ""),
   375  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   376  			controllerutil.OperationResultUpdated,
   377  			nil,
   378  		},
   379  		{
   380  			"Registration username is updated in admin cluster but not synced to managed1",
   381  			&testAdminCASecret,
   382  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   383  				mcconstants.RegistrationUsernameKey: "new user",
   384  			}, "", ""),
   385  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   386  			controllerutil.OperationResultUpdated,
   387  			nil,
   388  		},
   389  		{
   390  			"Registration password  is updated in admin cluster but not synced to managed1",
   391  			&testAdminCASecret,
   392  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   393  				mcconstants.RegistrationPasswordKey: "new password",
   394  			}, "", ""),
   395  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   396  			controllerutil.OperationResultUpdated,
   397  			nil,
   398  		},
   399  		{
   400  			"Keycloak url is updated in admin cluster but not synced to managed1",
   401  			&testAdminCASecret,
   402  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   403  				mcconstants.KeycloakURLKey: "new keycloak url",
   404  			}, "", ""),
   405  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   406  			controllerutil.OperationResultUpdated,
   407  			nil,
   408  		},
   409  		{
   410  			"Jaeger OS url is updated in admin cluster but not synced to managed1",
   411  			&testAdminCASecret,
   412  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   413  				mcconstants.JaegerOSURLKey: "new value",
   414  			}, "", ""),
   415  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   416  			controllerutil.OperationResultUpdated,
   417  			nil,
   418  		},
   419  		{
   420  			"Jaeger OS username is updated in admin cluster but not synced to managed1",
   421  			&testAdminCASecret,
   422  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   423  				mcconstants.JaegerOSUsernameKey: "newuser",
   424  			}, "", ""),
   425  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   426  			controllerutil.OperationResultUpdated,
   427  			nil,
   428  		},
   429  		{
   430  			"Jaeger OS password is updated in admin cluster but not synced to managed1",
   431  			&testAdminCASecret,
   432  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   433  				mcconstants.JaegerOSPasswordKey: "newpassword",
   434  			}, "", ""),
   435  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   436  			controllerutil.OperationResultUpdated,
   437  			nil,
   438  		},
   439  		{
   440  			"Jaeger TLS CA is updated in admin cluster but not synced to managed1",
   441  			&testAdminCASecret,
   442  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   443  				mcconstants.JaegerOSTLSCAKey: "newCAKey",
   444  			}, "", ""),
   445  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   446  			controllerutil.OperationResultUpdated,
   447  			nil,
   448  		},
   449  		{
   450  			"Jaeger TLS cert is updated in admin cluster but not synced to managed1",
   451  			&testAdminCASecret,
   452  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   453  				mcconstants.JaegerOSTLSCertKey: "newTLSCertKey",
   454  			}, "", ""),
   455  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   456  			controllerutil.OperationResultUpdated,
   457  			nil,
   458  		},
   459  		{
   460  			"Jaeger TLS key is updated in admin cluster but not synced to managed1",
   461  			&testAdminCASecret,
   462  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   463  				mcconstants.JaegerOSTLSKey: "newTLSKey",
   464  			}, "", ""),
   465  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   466  			controllerutil.OperationResultUpdated,
   467  			nil,
   468  		},
   469  		{
   470  			"Admin CA bundle is different in managed cluster",
   471  			&testAdminCASecret,
   472  			createSecretWithOverrides(adminRegSecretPath, nil, "", ""),
   473  			createSecretWithOverrides(clusterRegSecretPath, map[string]string{
   474  				mcconstants.AdminCaBundleKey: "new CA bundle",
   475  			}, "", ""),
   476  			controllerutil.OperationResultUpdated,
   477  			nil,
   478  		},
   479  		{
   480  			"All values are in sync between admin and managed1 cluster",
   481  			&testAdminCASecret,
   482  			createSecretWithOverrides(adminRegSecretPath, nil, "", ""),
   483  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   484  			controllerutil.OperationResultNone,
   485  			nil,
   486  		},
   487  		{
   488  			"When registration secret is missing in admin cluster, then it should return error",
   489  			&testAdminCASecret,
   490  			nil,
   491  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   492  			controllerutil.OperationResultNone,
   493  			fmt.Errorf("secrets \"verrazzano-cluster-managed1-registration\" not found"),
   494  		},
   495  		{
   496  			"When registration secret is missing in local cluster, then it should return error",
   497  			&testAdminCASecret,
   498  			createSecretWithOverrides(adminRegSecretPath, nil, "", ""),
   499  			nil,
   500  			controllerutil.OperationResultNone,
   501  			fmt.Errorf("secrets \"verrazzano-cluster-registration\" not found"),
   502  		},
   503  		{
   504  			"When CA cert secret is missing in admin cluster, then it should return error",
   505  			nil,
   506  			createSecretWithOverrides(adminRegSecretPath, nil, "", ""),
   507  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   508  			controllerutil.OperationResultNone,
   509  			fmt.Errorf("secrets \"verrazzano-local-ca-bundle\" not found"),
   510  		},
   511  		{
   512  			"Dex url is updated in admin cluster but not synced to managed1",
   513  			&testAdminCASecret,
   514  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   515  				mcconstants.DexURLKey: "new dex url",
   516  			}, "", ""),
   517  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   518  			controllerutil.OperationResultUpdated,
   519  			nil,
   520  		},
   521  		{
   522  			"OIDC Provider is updated in admin cluster but not synced to managed1",
   523  			&testAdminCASecret,
   524  			createSecretWithOverrides(adminRegSecretPath, map[string]string{
   525  				mcconstants.OidcProviderKey: "dex or keycloak",
   526  			}, "", ""),
   527  			createSecretWithOverrides(clusterRegSecretPath, nil, "", ""),
   528  			controllerutil.OperationResultUpdated,
   529  			nil,
   530  		},
   531  	}
   532  
   533  	for _, tt := range tests {
   534  		t.Run(tt.name, func(t *testing.T) {
   535  			adminRuntimeObjects := []runtime.Object{}
   536  			if tt.testAdminCASecret != nil {
   537  				adminRuntimeObjects = append(adminRuntimeObjects, tt.testAdminCASecret)
   538  			}
   539  			if tt.adminRegistrationSecret != nil {
   540  				adminRuntimeObjects = append(adminRuntimeObjects, tt.adminRegistrationSecret)
   541  			}
   542  			adminClient := fake.NewClientBuilder().
   543  				WithScheme(newClusterCAScheme()).
   544  				WithRuntimeObjects(adminRuntimeObjects...).
   545  				Build()
   546  
   547  			localRuntimeObjects := []runtime.Object{}
   548  			if tt.localRegistrationSecret != nil {
   549  				localRuntimeObjects = append(localRuntimeObjects, tt.localRegistrationSecret)
   550  			}
   551  			localClient := fake.NewClientBuilder().
   552  				WithScheme(newClusterCAScheme()).
   553  				WithRuntimeObjects(localRuntimeObjects...).
   554  				Build()
   555  
   556  			s := &Syncer{
   557  				AdminClient:        adminClient,
   558  				LocalClient:        localClient,
   559  				Log:                log,
   560  				ManagedClusterName: testClusterName,
   561  				Context:            context.TODO(),
   562  			}
   563  			actualOperationResult, err := s.syncRegistrationFromAdminCluster()
   564  			if tt.expectedError != nil {
   565  				asserts.Equal(t, err.Error(), tt.expectedError.Error())
   566  				return
   567  			}
   568  			asserts.NoError(t, err)
   569  			asserts.Equal(t, tt.expectedOperation, actualOperationResult)
   570  			// post sync call both the secrets should have the same values of registration secrets
   571  			// and calling sync again should be a no-op (unchanged).
   572  			reSyncOperationResult, err := s.syncRegistrationFromAdminCluster()
   573  			asserts.NoError(t, err)
   574  			asserts.Equal(t, controllerutil.OperationResultNone, reSyncOperationResult)
   575  		})
   576  	}
   577  }
   578  
   579  // TestSyncAgentSecretFromAdminCluster tests the synchronization method for the following use case.
   580  // GIVEN a request to sync Admin agent secret
   581  // WHEN the agent secret info is different in either admin-kubeconfig or managed-cluster-name
   582  // THEN ensure that managed cluster agent secret is updated, but not otherwise.
   583  func TestSyncAgentSecretFromAdminCluster(t *testing.T) {
   584  	testAdminAgentSecret := createSecretWithOverrides(adminAgentSecretPath, nil, "", getAgentSecretName(testClusterName))
   585  	testUnchangedLocalAgentSecret := createSecretWithOverrides(adminAgentSecretPath, nil, constants.VerrazzanoSystemNamespace, constants2.MCAgentSecret)
   586  	testNewAdminAgentSecret := createSecretWithOverrides(adminAgentNewSecretPath, nil, "", getAgentSecretName(testClusterName))
   587  	log := zap.S().With("test")
   588  	tests := []struct {
   589  		name                 string
   590  		testAdminAgentSecret *corev1.Secret
   591  		localAgentSecret     *corev1.Secret
   592  		otherAdminSecret     *corev1.Secret // some other unrelated secret present on admin cluster
   593  		expectedOperation    controllerutil.OperationResult
   594  		expectedError        error
   595  	}{
   596  		{
   597  			"admin agent secret identical to managed",
   598  			testAdminAgentSecret,
   599  			testUnchangedLocalAgentSecret,
   600  			nil,
   601  			controllerutil.OperationResultNone,
   602  			nil,
   603  		},
   604  		{
   605  			"admin agent secret kubeconfig changed",
   606  			testNewAdminAgentSecret,
   607  			testUnchangedLocalAgentSecret,
   608  			nil,
   609  			controllerutil.OperationResultUpdated,
   610  			nil,
   611  		},
   612  		{
   613  			"admin agent secret cluster name changed",
   614  			testAdminAgentSecret,
   615  			createSecretWithOverrides(adminAgentSecretPath, map[string]string{
   616  				mcconstants.ManagedClusterNameKey: "newmanagedclustername",
   617  			}, constants.VerrazzanoSystemNamespace, constants2.MCAgentSecret),
   618  			nil,
   619  			controllerutil.OperationResultUpdated,
   620  			nil,
   621  		},
   622  		{
   623  			"admin agent secret some unused field added",
   624  			createSecretWithOverrides(adminAgentSecretPath, map[string]string{
   625  				"somekeynotused": "somevalue",
   626  			}, "", getAgentSecretName(testClusterName)),
   627  			testUnchangedLocalAgentSecret,
   628  			nil,
   629  			controllerutil.OperationResultNone,
   630  			nil,
   631  		},
   632  	}
   633  	for _, tt := range tests {
   634  		t.Run(tt.name, func(t *testing.T) {
   635  			adminRuntimeObjects := []runtime.Object{}
   636  			if tt.testAdminAgentSecret != nil {
   637  				adminRuntimeObjects = append(adminRuntimeObjects, tt.testAdminAgentSecret)
   638  			}
   639  			adminClient := fake.NewClientBuilder().
   640  				WithScheme(newClusterCAScheme()).
   641  				WithRuntimeObjects(adminRuntimeObjects...).
   642  				Build()
   643  
   644  			localRuntimeObjects := []runtime.Object{}
   645  			if tt.localAgentSecret != nil {
   646  				localRuntimeObjects = append(localRuntimeObjects, tt.localAgentSecret)
   647  			}
   648  			localClient := fake.NewClientBuilder().
   649  				WithScheme(newClusterCAScheme()).
   650  				WithRuntimeObjects(localRuntimeObjects...).
   651  				Build()
   652  
   653  			s := &Syncer{
   654  				AdminClient:        adminClient,
   655  				LocalClient:        localClient,
   656  				Log:                log,
   657  				ManagedClusterName: testClusterName,
   658  				Context:            context.TODO(),
   659  			}
   660  			actualOperationResult, err := s.syncAgentSecretFromAdminCluster()
   661  			if tt.expectedError != nil {
   662  				asserts.Equal(t, err.Error(), tt.expectedError.Error())
   663  				return
   664  			}
   665  			asserts.NoError(t, err)
   666  			asserts.Equal(t, tt.expectedOperation, actualOperationResult)
   667  			// post sync call both the secrets should have the same values of registration secrets
   668  			// and calling sync again should be a no-op (unchanged).
   669  			reSyncOperationResult, err := s.syncAgentSecretFromAdminCluster()
   670  			asserts.NoError(t, err)
   671  			asserts.Equal(t, controllerutil.OperationResultNone, reSyncOperationResult)
   672  
   673  		})
   674  	}
   675  }
   676  
   677  // TestSyncLocalClusterCA tests an additional case of syncing just the MC CA to the admin cluster
   678  // when the CA cert is empty
   679  func TestSyncLocalClusterCA(t *testing.T) {
   680  	assert := asserts.New(t)
   681  	log := zap.S().With("test")
   682  	testMCLocalNonEmptyCA, err := getSampleSecret(vzTLSSecretPath)
   683  	assert.NoError(err, sampleMCTLSReadErrMsg)
   684  	testAdminMCNonEmptyCA, err := getSampleSecret(mcCASecretPath)
   685  	assert.NoError(err, sampleMCCAReadErrMsg)
   686  
   687  	testMCLocalEmptyCA := testMCLocalNonEmptyCA.DeepCopy()
   688  	testMCLocalEmptyCA.Data[mcconstants.CaCrtKey] = nil
   689  	testAdminMCEmptyCA := testAdminMCNonEmptyCA.DeepCopy()
   690  	testAdminMCEmptyCA.Data[keyCaCrtNoDot] = nil
   691  
   692  	testVMC, err := getSampleClusterCAVMC(vmcPath)
   693  	assert.NoError(err, sampleVMCReadErrMsg)
   694  
   695  	testVMCNoCASecret, err := getSampleClusterCAVMC(noCAVMCPath)
   696  	assert.NoError(err, sampleVMCReadErrMsg)
   697  
   698  	tests := []struct {
   699  		name                string
   700  		testMCLocalCASecret *corev1.Secret
   701  		testAdminMCCASecret *corev1.Secret
   702  		vmc                 v1alpha1.VerrazzanoManagedCluster
   703  	}{
   704  		{
   705  			"Both admin MC CA and managed cluster local CA empty",
   706  			testMCLocalEmptyCA,
   707  			testAdminMCEmptyCA,
   708  			testVMC,
   709  		},
   710  		{
   711  			"Managed cluster local CA empty but admin MC CA is non-empty",
   712  			testMCLocalEmptyCA,
   713  			&testAdminMCNonEmptyCA,
   714  			testVMC,
   715  		},
   716  		{
   717  			"Admin MC CA empty, managed cluster local CA non-empty",
   718  			&testMCLocalNonEmptyCA,
   719  			testAdminMCEmptyCA,
   720  			testVMC,
   721  		},
   722  		{
   723  			"Both admin MC CA and managed cluster local CA are non-empty and equal",
   724  			&testMCLocalNonEmptyCA,
   725  			&testAdminMCNonEmptyCA,
   726  			testVMC,
   727  		},
   728  		{
   729  			"Both admin MC CA and managed cluster local CA are non-empty and different",
   730  			&testMCLocalNonEmptyCA,
   731  			&testAdminMCNonEmptyCA,
   732  			testVMC,
   733  		},
   734  		{
   735  			"No CA secret name in VMC",
   736  			&testMCLocalNonEmptyCA,
   737  			nil,
   738  			testVMCNoCASecret,
   739  		},
   740  	}
   741  	for _, tt := range tests {
   742  		t.Run(tt.name, func(t *testing.T) {
   743  			adminRuntimeObjects := []runtime.Object{&tt.vmc}
   744  			managedCA := ""
   745  			if tt.testAdminMCCASecret != nil {
   746  				adminRuntimeObjects = append(adminRuntimeObjects, tt.testAdminMCCASecret)
   747  			}
   748  			adminClient := fake.NewClientBuilder().
   749  				WithScheme(newClusterCAScheme()).
   750  				WithRuntimeObjects(adminRuntimeObjects...).
   751  				Build()
   752  
   753  			localRuntimeObjects := []runtime.Object{}
   754  			if tt.testMCLocalCASecret != nil {
   755  				localRuntimeObjects = append(localRuntimeObjects, tt.testMCLocalCASecret)
   756  				managedCA = string(tt.testMCLocalCASecret.Data[mcconstants.CaCrtKey])
   757  			}
   758  			localClient := fake.NewClientBuilder().
   759  				WithScheme(newClusterCAScheme()).
   760  				WithRuntimeObjects(localRuntimeObjects...).
   761  				Build()
   762  
   763  			s := &Syncer{
   764  				AdminClient:        adminClient,
   765  				LocalClient:        localClient,
   766  				Log:                log,
   767  				ManagedClusterName: testClusterName,
   768  				Context:            context.TODO(),
   769  			}
   770  			err := s.syncLocalClusterCA()
   771  			assert.NoError(err)
   772  			if tt.testAdminMCCASecret != nil {
   773  				adminMCSecretAfterTest := corev1.Secret{}
   774  				err = adminClient.Get(context.TODO(),
   775  					types.NamespacedName{
   776  						Namespace: tt.testAdminMCCASecret.Namespace,
   777  						Name:      tt.testAdminMCCASecret.Name},
   778  					&adminMCSecretAfterTest)
   779  				assert.NoError(err)
   780  				// in all cases, after the call to syncLocalClusterCAs, the managed cluster CA on the
   781  				// admin side should equal the one on the managed side (either through update or because
   782  				// they were equal to start with
   783  				assert.Equal(managedCA, string(adminMCSecretAfterTest.Data[keyCaCrtNoDot]))
   784  			}
   785  		})
   786  	}
   787  }
   788  
   789  // getSampleClusterCAVMC creates and returns a sample VMC
   790  func getSampleClusterCAVMC(filePath string) (v1alpha1.VerrazzanoManagedCluster, error) {
   791  	vmc := v1alpha1.VerrazzanoManagedCluster{}
   792  	sampleVMCFile, err := filepath.Abs(filePath)
   793  	if err != nil {
   794  		return vmc, err
   795  	}
   796  
   797  	rawResource, err := clusterstest.ReadYaml2Json(sampleVMCFile)
   798  	if err != nil {
   799  		return vmc, err
   800  	}
   801  
   802  	err = json.Unmarshal(rawResource, &vmc)
   803  	return vmc, err
   804  }
   805  
   806  func newClusterCAScheme() *runtime.Scheme {
   807  	scheme := runtime.NewScheme()
   808  	corev1.SchemeBuilder.AddToScheme(scheme)
   809  	v1alpha1.AddToScheme(scheme)
   810  	return scheme
   811  }
   812  
   813  func assertRegistrationInfoEqual(t *testing.T, regSecret1 *corev1.Secret, regSecret2 corev1.Secret) {
   814  	asserts.Equal(t, regSecret1.Data[mcconstants.ESURLKey], regSecret2.Data[mcconstants.ESURLKey], "ES URL is different")
   815  	asserts.Equal(t, regSecret1.Data[mcconstants.KeycloakURLKey], regSecret2.Data[mcconstants.KeycloakURLKey], "Keycloak URL is different")
   816  	asserts.Equal(t, regSecret1.Data[mcconstants.RegistrationUsernameKey], regSecret2.Data[mcconstants.RegistrationUsernameKey], "Registration Username is different")
   817  	asserts.Equal(t, regSecret1.Data[mcconstants.RegistrationPasswordKey], regSecret2.Data[mcconstants.RegistrationPasswordKey], "Registration Password is different")
   818  	asserts.Equal(t, regSecret1.Data[mcconstants.ESCaBundleKey], regSecret2.Data[mcconstants.ESCaBundleKey], "Registration Password is different")
   819  	asserts.Equal(t, regSecret1.Data[mcconstants.JaegerOSURLKey], regSecret2.Data[mcconstants.JaegerOSURLKey], "Jaeger OS URL is different")
   820  	asserts.Equal(t, regSecret1.Data[mcconstants.JaegerOSUsernameKey], regSecret2.Data[mcconstants.JaegerOSUsernameKey], "Jaeger OS username is different")
   821  	asserts.Equal(t, regSecret1.Data[mcconstants.JaegerOSPasswordKey], regSecret2.Data[mcconstants.JaegerOSPasswordKey], "Jaeger OS password different")
   822  	asserts.Equal(t, regSecret1.Data[mcconstants.JaegerOSTLSCAKey], regSecret2.Data[mcconstants.JaegerOSTLSCAKey], "Jaeger OS TLS CA is different")
   823  	asserts.Equal(t, regSecret1.Data[mcconstants.JaegerOSTLSCertKey], regSecret2.Data[mcconstants.JaegerOSTLSCertKey], "Jaeger OS TLS Cert is different")
   824  	asserts.Equal(t, regSecret1.Data[mcconstants.JaegerOSTLSKey], regSecret2.Data[mcconstants.JaegerOSTLSKey], "Jaeger OS TLS Key is different")
   825  	asserts.Equal(t, regSecret1.Data[mcconstants.DexURLKey], regSecret2.Data[mcconstants.DexURLKey], "Dex URL is different")
   826  	asserts.Equal(t, regSecret1.Data[mcconstants.OidcProviderKey], regSecret2.Data[mcconstants.OidcProviderKey], "OIDC Provider is different")
   827  }
   828  
   829  func createSecretWithOverrides(filepath string, overrides map[string]string, newNamespace string, newName string) *corev1.Secret {
   830  	secret, err := getSampleSecret(filepath)
   831  	if err != nil {
   832  		pkg.Log(pkg.Error, err.Error())
   833  		return &corev1.Secret{}
   834  	}
   835  	for key, value := range overrides {
   836  		secret.Data[key] = []byte(value)
   837  	}
   838  	if newName != "" {
   839  		secret.Name = newName
   840  	}
   841  	if newNamespace != "" {
   842  		secret.Namespace = newNamespace
   843  	}
   844  	return &secret
   845  }