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 }