github.com/verrazzano/verrazzano@v1.7.0/application-operator/mcagent/mcagent_k8ssecret_test.go (about) 1 // Copyright (c) 2021, 2022, 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 "path/filepath" 10 "testing" 11 12 asserts "github.com/stretchr/testify/assert" 13 clustersv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1" 14 "github.com/verrazzano/verrazzano/application-operator/constants" 15 clusterstest "github.com/verrazzano/verrazzano/application-operator/controllers/clusters/test" 16 constants2 "github.com/verrazzano/verrazzano/pkg/constants" 17 "go.uber.org/zap" 18 corev1 "k8s.io/api/core/v1" 19 apierrors "k8s.io/apimachinery/pkg/api/errors" 20 "k8s.io/apimachinery/pkg/runtime" 21 "k8s.io/apimachinery/pkg/types" 22 "sigs.k8s.io/controller-runtime/pkg/client/fake" 23 ) 24 25 // TestCreateSecretOneMCAppConfig tests the synchronization method for the following use case. 26 // GIVEN a request to sync Secret objects with a single MultiClusterApplicationConfiguration object 27 // 28 // containing two secrets 29 // 30 // WHEN the new object exists 31 // THEN ensure that the Secret objects are created 32 func TestCreateSecretOneMCAppConfig(t *testing.T) { 33 assert := asserts.New(t) 34 log := zap.S().With("test") 35 36 // Test data 37 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 38 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 39 40 testSecret1, err := getSampleSecret("testdata/secret1.yaml") 41 assert.NoError(err, "failed to read sample data for Secret") 42 43 testSecret2, err := getSampleSecret("testdata/secret2.yaml") 44 assert.NoError(err, "failed to read sample data for Secret") 45 46 adminClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testMCAppConfig, &testSecret1, &testSecret2).Build() 47 48 localClient := fake.NewClientBuilder().WithScheme(newTestScheme()).Build() 49 50 // Make the request 51 s := &Syncer{ 52 AdminClient: adminClient, 53 LocalClient: localClient, 54 Log: log, 55 ManagedClusterName: testClusterName, 56 Context: context.TODO(), 57 } 58 59 err = s.syncSecretObjects(testMCAppConfigNamespace) 60 61 // Validate the results 62 assert.NoError(err) 63 64 // Verify the associated secrets got created on local cluster 65 secret := &corev1.Secret{} 66 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 67 assert.NoError(err) 68 assert.Equal(4, len(secret.Labels)) 69 assertCommonLabels(assert, secret, "unit-mcappconfig") 70 assert.Contains(secret.Labels["label1"], "test1", "secret label did not match") 71 72 secret = &corev1.Secret{} 73 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 74 assert.NoError(err) 75 assert.Equal(3, len(secret.Labels)) 76 assertCommonLabels(assert, secret, "unit-mcappconfig") 77 } 78 79 // TestCreateSecretTwoMCAppConfigs tests the synchronization method for the following use case. 80 // GIVEN a request to sync Secret objects with two MultiClusterApplicationConfiguration objects 81 // 82 // and one of the secrets is shared by two MultiClusterApplicationConfiguration objects 83 // 84 // WHEN the new object exists 85 // THEN ensure that the Secret objects are created 86 func TestCreateSecretTwoMCAppConfigs(t *testing.T) { 87 assert := asserts.New(t) 88 log := zap.S().With("test") 89 90 // Test data 91 testMCAppConfig1, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 92 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 93 94 testMCAppConfig2, err := getSampleMCAppConfig("testdata/multicluster-appconfig2.yaml") 95 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 96 97 testSecret1, err := getSampleSecret("testdata/secret1.yaml") 98 assert.NoError(err, "failed to read sample data for Secret") 99 100 testSecret2, err := getSampleSecret("testdata/secret2.yaml") 101 assert.NoError(err, "failed to read sample data for Secret") 102 103 adminClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testMCAppConfig1, &testMCAppConfig2, &testSecret1, &testSecret2).Build() 104 105 localClient := fake.NewClientBuilder().WithScheme(newTestScheme()).Build() 106 107 // Make the request 108 s := &Syncer{ 109 AdminClient: adminClient, 110 LocalClient: localClient, 111 Log: log, 112 ManagedClusterName: testClusterName, 113 Context: context.TODO(), 114 } 115 116 err = s.syncSecretObjects(testMCAppConfigNamespace) 117 118 // Validate the results 119 assert.NoError(err) 120 121 // Verify the associated secrets got created on local cluster 122 secret := &corev1.Secret{} 123 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 124 assert.NoError(err) 125 assert.Equal(4, len(secret.Labels)) 126 assertCommonLabels(assert, secret, "unit-mcappconfig,unit-mcappconfig2") 127 assert.Contains(secret.Labels["label1"], "test1", "secret label did not match") 128 129 secret = &corev1.Secret{} 130 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 131 assert.NoError(err) 132 assert.Equal(3, len(secret.Labels)) 133 assert.Contains(secret.Labels[managedClusterLabel], testClusterName, "secret label did not match") 134 assert.Contains(secret.Labels[mcAppConfigsLabel], "unit-mcappconfig", "secret label did not match") 135 assert.Contains(secret.Labels[constants2.VerrazzanoManagedLabelKey], constants.LabelVerrazzanoManagedDefault, "secret label did not match") 136 } 137 138 // TestChangePlacement tests the synchronization method for the following use case. 139 // GIVEN a request to move a MultiClusterApplicationConfiguration object 140 // 141 // from one cluster to another 142 // 143 // WHEN the new object exists 144 // THEN ensure that the Secret objects are created and then removed 145 func TestChangePlacement(t *testing.T) { 146 assert := asserts.New(t) 147 log := zap.S().With("test") 148 149 // Test data 150 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 151 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 152 153 testSecret1, err := getSampleSecret("testdata/secret1.yaml") 154 assert.NoError(err, "failed to read sample data for Secret") 155 156 testSecret2, err := getSampleSecret("testdata/secret2.yaml") 157 assert.NoError(err, "failed to read sample data for Secret") 158 159 adminClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testMCAppConfig, &testSecret1, &testSecret2).Build() 160 161 localClient := fake.NewClientBuilder().WithScheme(newTestScheme()).Build() 162 163 // Make the request 164 s := &Syncer{ 165 AdminClient: adminClient, 166 LocalClient: localClient, 167 Log: log, 168 ManagedClusterName: testClusterName, 169 Context: context.TODO(), 170 } 171 172 err = s.syncSecretObjects(testMCAppConfigNamespace) 173 assert.NoError(err) 174 175 // Verify the associated secrets got created on local cluster 176 secret := &corev1.Secret{} 177 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 178 assert.NoError(err) 179 assert.Equal(4, len(secret.Labels)) 180 assertCommonLabels(assert, secret, "unit-mcappconfig") 181 assert.Contains(secret.Labels["label1"], "test1", "secret label did not match") 182 183 secret = &corev1.Secret{} 184 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 185 assert.NoError(err) 186 assert.Equal(3, len(secret.Labels)) 187 assertCommonLabels(assert, secret, "unit-mcappconfig") 188 189 testMCAppConfig.Spec.Placement.Clusters[0].Name = "managed2" 190 err = s.AdminClient.Update(s.Context, &testMCAppConfig) 191 assert.NoError(err) 192 193 err = s.syncSecretObjects(testMCAppConfigNamespace) 194 assert.NoError(err) 195 196 // Check that secrets have been deleted on the local cluster since the placement has changed 197 secret = &corev1.Secret{} 198 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 199 assert.True(apierrors.IsNotFound(err)) 200 201 secret = &corev1.Secret{} 202 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 203 assert.True(apierrors.IsNotFound(err)) 204 } 205 206 // TestDeleteSecret tests the deletion of secrets for the following use case. 207 // GIVEN a request to delete a MultiClusterApplicationConfiguration object 208 // 209 // containing two secrets that are not shared 210 // 211 // WHEN the MultiClusterApplicationConfiguration object is deleted 212 // THEN ensure that the Secret objects are deleted 213 func TestDeleteSecret(t *testing.T) { 214 assert := asserts.New(t) 215 log := zap.S().With("test") 216 217 // Test data 218 testMCAppConfig, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 219 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 220 221 testSecret1, err := getSampleSecret("testdata/secret1.yaml") 222 assert.NoError(err, "failed to read sample data for Secret") 223 224 testSecret2, err := getSampleSecret("testdata/secret2.yaml") 225 assert.NoError(err, "failed to read sample data for Secret") 226 227 adminClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testMCAppConfig, &testSecret1, &testSecret2).Build() 228 229 localClient := fake.NewClientBuilder().WithScheme(newTestScheme()).Build() 230 231 // Make the request 232 s := &Syncer{ 233 AdminClient: adminClient, 234 LocalClient: localClient, 235 Log: log, 236 ManagedClusterName: testClusterName, 237 Context: context.TODO(), 238 } 239 240 err = s.syncSecretObjects(testMCAppConfigNamespace) 241 assert.NoError(err) 242 243 // Verify the associated secrets got created on local cluster 244 secret := &corev1.Secret{} 245 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 246 assert.NoError(err) 247 assert.Equal(4, len(secret.Labels)) 248 assert.Contains(secret.Labels["label1"], "test1", "secret label did not match") 249 assertCommonLabels(assert, secret, "unit-mcappconfig") 250 251 secret = &corev1.Secret{} 252 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 253 assert.NoError(err) 254 assert.Equal(3, len(secret.Labels)) 255 assertCommonLabels(assert, secret, "unit-mcappconfig") 256 257 // Delete the MultiClusterApplicationConfigurarion object from the admin cluster 258 err = s.AdminClient.Delete(s.Context, &testMCAppConfig) 259 assert.NoError(err) 260 261 // sync 262 err = s.syncSecretObjects(testMCAppConfigNamespace) 263 assert.NoError(err) 264 265 // Check that secrets have been deleted on the local cluster 266 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 267 assert.True(apierrors.IsNotFound(err)) 268 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 269 assert.True(apierrors.IsNotFound(err)) 270 } 271 272 // TestDeleteSecretSharedSecret tests the deletion of secrets for the following use case. 273 // GIVEN a request to delete a MultiClusterApplicationConfiguration object 274 // 275 // containing a secret that is shared by another MultiClusterApplicationConfiguration object 276 // 277 // WHEN the MultiClusterApplicationConfiguration object is deleted 278 // THEN ensure that the shared secret is not deleted and the verrazzano.io/mc-app-configs label is updated to reflect 279 // 280 // the deleted MultiClusterApplicationConfiguration object 281 func TestDeleteSecretSharedSecret(t *testing.T) { 282 assert := asserts.New(t) 283 log := zap.S().With("test") 284 285 // Test data 286 testMCAppConfig1, err := getSampleMCAppConfig("testdata/multicluster-appconfig.yaml") 287 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 288 289 testMCAppConfig2, err := getSampleMCAppConfig("testdata/multicluster-appconfig2.yaml") 290 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 291 292 testSecret1, err := getSampleSecret("testdata/secret1.yaml") 293 assert.NoError(err, "failed to read sample data for Secret") 294 295 testSecret2, err := getSampleSecret("testdata/secret2.yaml") 296 assert.NoError(err, "failed to read sample data for Secret") 297 298 adminClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testMCAppConfig1, &testMCAppConfig2, &testSecret1, &testSecret2).Build() 299 300 localClient := fake.NewClientBuilder().WithScheme(newTestScheme()).Build() 301 302 // Make the request 303 s := &Syncer{ 304 AdminClient: adminClient, 305 LocalClient: localClient, 306 Log: log, 307 ManagedClusterName: testClusterName, 308 Context: context.TODO(), 309 } 310 311 err = s.syncSecretObjects(testMCAppConfigNamespace) 312 assert.NoError(err) 313 314 // Verify the associated secrets got created on local cluster 315 secret := &corev1.Secret{} 316 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 317 assert.NoError(err) 318 assert.Equal(4, len(secret.Labels)) 319 assertCommonLabels(assert, secret, "unit-mcappconfig,unit-mcappconfig2") 320 assert.Contains(secret.Labels["label1"], "test1", "secret label did not match") 321 322 secret = &corev1.Secret{} 323 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 324 assert.NoError(err) 325 assert.Equal(3, len(secret.Labels)) 326 assertCommonLabels(assert, secret, "unit-mcappconfig") 327 328 // Delete the MultiClusterApplicationConfigurarion object from the admin cluster 329 err = s.AdminClient.Delete(s.Context, &testMCAppConfig1) 330 assert.NoError(err) 331 332 // sync 333 err = s.syncSecretObjects(testMCAppConfigNamespace) 334 assert.NoError(err) 335 336 // shared secret1 should not have been deleted on the local cluster 337 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 338 assert.NoError(err) 339 340 // label for secret1 should have been updated 341 assert.Contains(secret.Labels[mcAppConfigsLabel], "unit-mcappconfig2", "secret label did not match") 342 343 // secret2 should have been deleted on the local cluster 344 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 345 assert.True(apierrors.IsNotFound(err)) 346 } 347 348 // TestDeleteSecretExtra tests the deletion of secrets for the following use case. 349 // GIVEN a request to delete a MultiClusterApplicationConfiguration object 350 // 351 // containing a secret and there is also a secret not part of the MultiClusterApplicationConfiguration object 352 // 353 // WHEN the MultiClusterApplicationConfiguration object is deleted 354 // THEN ensure that only the secret in the MultiClusterApplicationConfiguration object is deleted 355 func TestDeleteSecretExtra(t *testing.T) { 356 assert := asserts.New(t) 357 log := zap.S().With("test") 358 359 // Test data 360 testMCAppConfig2, err := getSampleMCAppConfig("testdata/multicluster-appconfig2.yaml") 361 assert.NoError(err, "failed to read sample data for MultiClusterApplicationConfiguration") 362 363 testSecret1, err := getSampleSecret("testdata/secret1.yaml") 364 assert.NoError(err, "failed to read sample data for Secret") 365 366 testSecret2, err := getSampleSecret("testdata/secret2.yaml") 367 assert.NoError(err, "failed to read sample data for Secret") 368 369 adminClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testMCAppConfig2, &testSecret1).Build() 370 371 localClient := fake.NewClientBuilder().WithScheme(newTestScheme()).WithObjects(&testSecret2).Build() 372 373 // Make the request 374 s := &Syncer{ 375 AdminClient: adminClient, 376 LocalClient: localClient, 377 Log: log, 378 ManagedClusterName: testClusterName, 379 Context: context.TODO(), 380 } 381 382 err = s.syncSecretObjects(testMCAppConfigNamespace) 383 assert.NoError(err) 384 385 // Verify the associated secrets got created on local cluster 386 secret := &corev1.Secret{} 387 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 388 assert.NoError(err) 389 assert.Equal(4, len(secret.Labels)) 390 assertCommonLabels(assert, secret, "unit-mcappconfig") 391 assert.Contains(secret.Labels["label1"], "test1", "secret label did not match") 392 393 secret = &corev1.Secret{} 394 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 395 assert.NoError(err) 396 assert.Equal(0, len(secret.Labels)) 397 398 // Delete the MultiClusterApplicationConfigurarion object from the admin cluster 399 err = s.AdminClient.Delete(s.Context, &testMCAppConfig2) 400 assert.NoError(err) 401 402 // sync 403 err = s.syncSecretObjects(testMCAppConfigNamespace) 404 assert.NoError(err) 405 406 // secret1 should have been deleted on the local cluster 407 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret1.Name, Namespace: testSecret1.Namespace}, secret) 408 assert.True(apierrors.IsNotFound(err)) 409 // secret2 should not have been deleted on the local cluster 410 err = s.LocalClient.Get(s.Context, types.NamespacedName{Name: testSecret2.Name, Namespace: testSecret2.Namespace}, secret) 411 assert.NoError(err) 412 } 413 414 // getSampleSecret returns a sample secret object 415 func getSampleSecret(filePath string) (corev1.Secret, error) { 416 secret := corev1.Secret{} 417 sampleSecretFile, err := filepath.Abs(filePath) 418 if err != nil { 419 return secret, err 420 } 421 422 rawResource, err := clusterstest.ReadYaml2Json(sampleSecretFile) 423 if err != nil { 424 return secret, err 425 } 426 427 err = json.Unmarshal(rawResource, &secret) 428 return secret, err 429 } 430 431 // assert labels common to all K8S secrets synced to managed cluster 432 func assertCommonLabels(assert *asserts.Assertions, secret *corev1.Secret, appConfigs string) { 433 assert.Contains(secret.Labels[managedClusterLabel], testClusterName, "secret label did not match") 434 assert.Contains(secret.Labels[mcAppConfigsLabel], appConfigs, "secret label did not match") 435 assert.Contains(secret.Labels[constants2.VerrazzanoManagedLabelKey], constants.LabelVerrazzanoManagedDefault, "secret label did not match") 436 } 437 438 func newTestScheme() *runtime.Scheme { 439 scheme := runtime.NewScheme() 440 clustersv1alpha1.AddToScheme(scheme) 441 corev1.AddToScheme(scheme) 442 return scheme 443 }