open-cluster-management.io/governance-policy-propagator@v0.13.0/test/e2e/case9_templates_test.go (about) 1 // Copyright (c) 2021 Red Hat, Inc. 2 // Copyright Contributors to the Open Cluster Management project 3 4 package e2e 5 6 import ( 7 "context" 8 "fmt" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 "k8s.io/apimachinery/pkg/types" 15 16 "open-cluster-management.io/governance-policy-propagator/test/utils" 17 ) 18 19 var _ = Describe("Test policy templates", func() { 20 const ( 21 case9PolicyName = "case9-test-policy" 22 case9PathPrefix = "../resources/case9_templates/" 23 case9PolicyYaml = case9PathPrefix + "case9-test-policy.yaml" 24 case9ReplicatedPolicyYamlM1 = case9PathPrefix + "case9-test-replpolicy-managed1.yaml" 25 case9ReplicatedPolicyYamlM1Update = case9PathPrefix + "case9-test-replpolicy-managed1-relabelled.yaml" 26 case9ReplicatedPolicyYamlM2 = case9PathPrefix + "case9-test-replpolicy-managed2.yaml" 27 case9PolicyNameEncrypted = "case9-test-policy-encrypted" 28 case9PolicyYamlEncrypted = case9PathPrefix + "case9-test-policy_encrypted.yaml" 29 case9PolicyYamlEncryptedRepl = case9PathPrefix + "case9-test-replpolicy_encrypted-" 30 case9EncryptionSecret = case9PathPrefix + "case9-test-encryption-secret.yaml" 31 case9EncryptionSecretName = "policy-encryption-key" 32 case9SecretName = "case9-secret" 33 case9PolicyNameCopy = "case9-test-policy-copy" 34 case9PolicyYamlCopy = case9PathPrefix + "case9-test-policy_copy.yaml" 35 case9PolicyYamlCopiedRepl = case9PathPrefix + "case9-test-replpolicy_copied-" 36 case9PolicyWithCSLookupName = "case9-test-policy-cslookup" 37 case9PolicyWithCSLookupYaml = case9PathPrefix + "case9-test-policy-cslookup.yaml" 38 ) 39 40 Describe("Create policy, placement and referenced resource in ns:"+testNamespace, Ordered, func() { 41 It("should be created in user ns", func() { 42 By("Creating " + case9PolicyYaml) 43 utils.Kubectl("apply", 44 "-f", case9PolicyYaml, 45 "-n", testNamespace, 46 "--kubeconfig="+kubeconfigHub) 47 plc := utils.GetWithTimeout( 48 clientHubDynamic, gvrPolicy, case9PolicyName, testNamespace, true, defaultTimeoutSeconds, 49 ) 50 Expect(plc).NotTo(BeNil()) 51 }) 52 It("should resolve templates and propagate to cluster ns managed1", func() { 53 By("Patching test-policy-plr with decision of cluster managed1") 54 plr := utils.GetWithTimeout( 55 clientHubDynamic, gvrPlacementRule, case9PolicyName+"-plr", testNamespace, 56 true, defaultTimeoutSeconds, 57 ) 58 plr.Object["status"] = utils.GeneratePlrStatus("managed1") 59 _, err := clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus( 60 context.TODO(), plr, metav1.UpdateOptions{}, 61 ) 62 Expect(err).ToNot(HaveOccurred()) 63 plc := utils.GetWithTimeout( 64 clientHubDynamic, gvrPolicy, testNamespace+"."+case9PolicyName, "managed1", 65 true, defaultTimeoutSeconds, 66 ) 67 Expect(plc).ToNot(BeNil()) 68 69 yamlPlc := utils.ParseYaml(case9ReplicatedPolicyYamlM1) 70 Eventually(func(g Gomega) interface{} { 71 replicatedPlc := utils.GetWithTimeout( 72 clientHubDynamic, 73 gvrPolicy, 74 testNamespace+"."+case9PolicyName, 75 "managed1", 76 true, 77 defaultTimeoutSeconds, 78 ) 79 80 err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc) 81 g.Expect(err).ToNot(HaveOccurred()) 82 83 return replicatedPlc.Object["spec"] 84 }, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(yamlPlc.Object["spec"])) 85 }) 86 It("should update the templated value when the managed cluster labels change", func() { 87 By("Updating the label on managed1") 88 utils.Kubectl("label", "managedcluster", "managed1", 89 "vendor=Fake", "--overwrite", "--kubeconfig="+kubeconfigHub) 90 91 By("Verifying the policy is updated") 92 yamlPlc := utils.ParseYaml(case9ReplicatedPolicyYamlM1Update) 93 Eventually(func(g Gomega) interface{} { 94 replicatedPlc := utils.GetWithTimeout( 95 clientHubDynamic, 96 gvrPolicy, 97 testNamespace+"."+case9PolicyName, 98 "managed1", 99 true, 100 defaultTimeoutSeconds, 101 ) 102 103 err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc) 104 g.Expect(err).ToNot(HaveOccurred()) 105 106 return replicatedPlc.Object["spec"] 107 }, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(yamlPlc.Object["spec"])) 108 }) 109 It("should resolve templates and propagate to cluster ns managed2", func() { 110 By("Patching test-policy-plr with decision of cluster managed2") 111 plr := utils.GetWithTimeout( 112 clientHubDynamic, gvrPlacementRule, case9PolicyName+"-plr", testNamespace, 113 true, defaultTimeoutSeconds, 114 ) 115 plr.Object["status"] = utils.GeneratePlrStatus("managed2") 116 _, err := clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus( 117 context.TODO(), plr, metav1.UpdateOptions{}, 118 ) 119 Expect(err).ToNot(HaveOccurred()) 120 plc := utils.GetWithTimeout( 121 clientHubDynamic, gvrPolicy, testNamespace+"."+case9PolicyName, "managed2", 122 true, defaultTimeoutSeconds, 123 ) 124 Expect(plc).ToNot(BeNil()) 125 126 yamlPlc := utils.ParseYaml(case9ReplicatedPolicyYamlM2) 127 Eventually(func(g Gomega) interface{} { 128 replicatedPlc := utils.GetWithTimeout( 129 clientHubDynamic, 130 gvrPolicy, 131 testNamespace+"."+case9PolicyName, 132 "managed2", 133 true, 134 defaultTimeoutSeconds, 135 ) 136 137 err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc) 138 g.Expect(err).ToNot(HaveOccurred()) 139 140 return replicatedPlc.Object["spec"] 141 }, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(yamlPlc.Object["spec"])) 142 }) 143 AfterAll(func() { 144 utils.Kubectl("delete", 145 "-f", case9PolicyYaml, 146 "-n", testNamespace, 147 "--kubeconfig="+kubeconfigHub, 148 "--ignore-not-found") 149 utils.Kubectl("label", "managedcluster", "managed1", 150 "vendor=auto-detect", "--overwrite", "--kubeconfig="+kubeconfigHub) 151 opt := metav1.ListOptions{} 152 utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, defaultTimeoutSeconds) 153 }) 154 }) 155 156 Describe("Test encrypted policy templates", Ordered, func() { 157 for i := 1; i <= 2; i++ { 158 managedCluster := "managed" + fmt.Sprint(i) 159 160 It("should be created in user ns", func() { 161 By("Creating " + case9PolicyYamlEncrypted) 162 utils.Kubectl("apply", 163 "-f", case9PolicyYamlEncrypted, 164 "-n", testNamespace, 165 "--kubeconfig="+kubeconfigHub) 166 plc := utils.GetWithTimeout( 167 clientHubDynamic, gvrPolicy, case9PolicyNameEncrypted, testNamespace, 168 true, defaultTimeoutSeconds, 169 ) 170 Expect(plc).NotTo(BeNil()) 171 }) 172 173 It("should resolve templates and propagate to cluster ns "+managedCluster, func() { 174 By("Initializing AES Encryption Secret") 175 _, err := utils.KubectlWithOutput("apply", 176 "-f", case9EncryptionSecret, 177 "-n", managedCluster, 178 "--kubeconfig="+kubeconfigHub) 179 Expect(err).ToNot(HaveOccurred()) 180 181 By("Patching test-policy-plr with decision of cluster " + managedCluster) 182 plr := utils.GetWithTimeout( 183 clientHubDynamic, gvrPlacementRule, case9PolicyNameEncrypted+"-plr", testNamespace, 184 true, defaultTimeoutSeconds, 185 ) 186 plr.Object["status"] = utils.GeneratePlrStatus(managedCluster) 187 _, err = clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus( 188 context.TODO(), plr, metav1.UpdateOptions{}, 189 ) 190 Expect(err).ToNot(HaveOccurred()) 191 192 var replicatedPlc *unstructured.Unstructured 193 By("Waiting for encrypted values") 194 Eventually(func() interface{} { 195 replicatedPlc = utils.GetWithTimeout( 196 clientHubDynamic, 197 gvrPolicy, 198 testNamespace+"."+case9PolicyNameEncrypted, 199 managedCluster, 200 true, 201 defaultTimeoutSeconds, 202 ) 203 204 return fmt.Sprint(replicatedPlc.Object["spec"]) 205 }, defaultTimeoutSeconds, 1).Should(ContainSubstring("$ocm_encrypted:")) 206 207 By("Patching the initialization vector with a static value") 208 // Setting Initialization Vector so that the test results will be deterministic 209 initializationVector := "7cznVUq5SXEE4RMZNkGOrQ==" 210 annotations := replicatedPlc.GetAnnotations() 211 annotations[IVAnnotation] = initializationVector 212 replicatedPlc.SetAnnotations(annotations) 213 _, err = clientHubDynamic.Resource(gvrPolicy).Namespace(managedCluster).Update( 214 context.TODO(), replicatedPlc, metav1.UpdateOptions{}, 215 ) 216 Expect(err).ToNot(HaveOccurred()) 217 218 By("Verifying the replicated policy against a snapshot") 219 yamlPlc := utils.ParseYaml(case9PolicyYamlEncryptedRepl + managedCluster + ".yaml") 220 Eventually(func(g Gomega) interface{} { 221 replicatedPlc = utils.GetWithTimeout( 222 clientHubDynamic, 223 gvrPolicy, 224 testNamespace+"."+case9PolicyNameEncrypted, 225 managedCluster, 226 true, 227 defaultTimeoutSeconds, 228 ) 229 230 err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc) 231 g.Expect(err).ToNot(HaveOccurred()) 232 233 return replicatedPlc.Object["spec"] 234 }, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(yamlPlc.Object["spec"])) 235 }) 236 237 It("should reconcile when the secret referenced in the template is updated", func() { 238 By("Updating the secret " + case9SecretName) 239 newToken := "THVrZS4gSSBhbSB5b3VyIGZhdGhlci4=" 240 patch := []byte(`{"data": {"token": "` + newToken + `"}}`) 241 _, err := clientHub.CoreV1().Secrets(testNamespace).Patch( 242 context.TODO(), case9SecretName, types.StrategicMergePatchType, patch, metav1.PatchOptions{}, 243 ) 244 Expect(err).ToNot(HaveOccurred()) 245 246 By("Verifying the replicated policy was updated") 247 expected := "$ocm_encrypted:dbHPzG98PxV7RXcAx25mMGPBAUbfjJTEMyFc7kE2W7U3FW5+X31LkidHu/25ic4m" 248 Eventually(func() string { 249 replicatedPlc := utils.GetWithTimeout( 250 clientHubDynamic, 251 gvrPolicy, 252 testNamespace+"."+case9PolicyNameEncrypted, 253 managedCluster, 254 true, 255 defaultTimeoutSeconds, 256 ) 257 258 templates, _, _ := unstructured.NestedSlice(replicatedPlc.Object, "spec", "policy-templates") 259 if len(templates) < 1 { 260 return "" 261 } 262 263 template, ok := templates[0].(map[string]interface{}) 264 if !ok { 265 return "" 266 } 267 268 objectTemplates, _, _ := unstructured.NestedSlice( 269 template, "objectDefinition", "spec", "object-templates", 270 ) 271 if len(objectTemplates) < 1 { 272 return "" 273 } 274 275 objectTemplate, ok := objectTemplates[0].(map[string]interface{}) 276 if !ok { 277 return "" 278 } 279 280 secretValue, _, _ := unstructured.NestedString( 281 objectTemplate, "objectDefinition", "data", "someTopSecretThing", 282 ) 283 284 return secretValue 285 }, defaultTimeoutSeconds, 1).Should(Equal(expected)) 286 }) 287 288 It("should clean up the encryption key", func() { 289 utils.Kubectl("delete", "secret", 290 case9EncryptionSecretName, 291 "-n", managedCluster, 292 "--kubeconfig="+kubeconfigHub) 293 utils.GetWithTimeout( 294 clientHubDynamic, gvrSecret, case9EncryptionSecretName, managedCluster, 295 false, defaultTimeoutSeconds, 296 ) 297 }) 298 299 It("should clean up", func() { 300 utils.Kubectl("delete", "-f", case9PolicyYamlEncrypted, 301 "-n", testNamespace, "--kubeconfig="+kubeconfigHub) 302 opt := metav1.ListOptions{} 303 utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, defaultTimeoutSeconds) 304 }) 305 } 306 }) 307 308 Describe("Test encrypted policy templates with secret copy", Ordered, func() { 309 for i := 1; i <= 2; i++ { 310 managedCluster := "managed" + fmt.Sprint(i) 311 312 It("should be created in user ns", func() { 313 By("Creating " + case9PolicyYamlCopy) 314 utils.Kubectl("apply", 315 "-f", case9PolicyYamlCopy, 316 "-n", testNamespace, 317 "--kubeconfig="+kubeconfigHub) 318 plc := utils.GetWithTimeout( 319 clientHubDynamic, gvrPolicy, case9PolicyNameCopy, testNamespace, 320 true, defaultTimeoutSeconds, 321 ) 322 Expect(plc).NotTo(BeNil()) 323 }) 324 325 It("should resolve templates and propagate to cluster ns "+managedCluster, func() { 326 By("Initializing AES Encryption Secret") 327 _, err := utils.KubectlWithOutput("apply", 328 "-f", case9EncryptionSecret, 329 "-n", managedCluster, 330 "--kubeconfig="+kubeconfigHub) 331 Expect(err).ToNot(HaveOccurred()) 332 333 By("Patching test-policy-plr with decision of cluster " + managedCluster) 334 plr := utils.GetWithTimeout( 335 clientHubDynamic, gvrPlacementRule, case9PolicyNameCopy+"-plr", testNamespace, 336 true, defaultTimeoutSeconds, 337 ) 338 plr.Object["status"] = utils.GeneratePlrStatus(managedCluster) 339 _, err = clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus( 340 context.TODO(), plr, metav1.UpdateOptions{}, 341 ) 342 Expect(err).ToNot(HaveOccurred()) 343 344 var replicatedPlc *unstructured.Unstructured 345 By("Waiting for encrypted values") 346 Eventually(func() interface{} { 347 replicatedPlc = utils.GetWithTimeout( 348 clientHubDynamic, 349 gvrPolicy, 350 testNamespace+"."+case9PolicyNameCopy, 351 managedCluster, 352 true, 353 defaultTimeoutSeconds, 354 ) 355 356 return fmt.Sprint(replicatedPlc.Object["spec"]) 357 }, defaultTimeoutSeconds, 1).Should(ContainSubstring("$ocm_encrypted:")) 358 359 By("Patching the initialization vector with a static value") 360 // Setting Initialization Vector so that the test results will be deterministic 361 initializationVector := "7cznVUq5SXEE4RMZNkGOrQ==" 362 annotations := replicatedPlc.GetAnnotations() 363 annotations[IVAnnotation] = initializationVector 364 replicatedPlc.SetAnnotations(annotations) 365 _, err = clientHubDynamic.Resource(gvrPolicy).Namespace(managedCluster).Update( 366 context.TODO(), replicatedPlc, metav1.UpdateOptions{}, 367 ) 368 Expect(err).ToNot(HaveOccurred()) 369 370 By("Verifying the replicated policy against a snapshot") 371 yamlPlc := utils.ParseYaml(case9PolicyYamlCopiedRepl + managedCluster + ".yaml") 372 Eventually(func(g Gomega) interface{} { 373 replicatedPlc = utils.GetWithTimeout( 374 clientHubDynamic, 375 gvrPolicy, 376 testNamespace+"."+case9PolicyNameCopy, 377 managedCluster, 378 true, 379 defaultTimeoutSeconds, 380 ) 381 382 err := utils.RemovePolicyTemplateDBAnnotations(replicatedPlc) 383 g.Expect(err).ToNot(HaveOccurred()) 384 385 return replicatedPlc.Object["spec"] 386 }, defaultTimeoutSeconds, 1).Should(utils.SemanticEqual(yamlPlc.Object["spec"])) 387 }) 388 389 It("should reconcile when the secret referenced in the template is updated", func() { 390 By("Updating the secret " + case9SecretName) 391 newToken := "THVrZS4gSSBhbSB5b3VyIGZhdGhlci4=" 392 patch := []byte(`{"data": {"token": "` + newToken + `"}}`) 393 _, err := clientHub.CoreV1().Secrets(testNamespace).Patch( 394 context.TODO(), case9SecretName, types.StrategicMergePatchType, patch, metav1.PatchOptions{}, 395 ) 396 Expect(err).ToNot(HaveOccurred()) 397 398 By("Verifying the replicated policy was updated") 399 expected := "$ocm_encrypted:dbHPzG98PxV7RXcAx25mMGPBAUbfjJTEMyFc7kE2W7U3FW5+X31LkidHu/25ic4m" 400 Eventually(func() string { 401 replicatedPlc := utils.GetWithTimeout( 402 clientHubDynamic, 403 gvrPolicy, 404 testNamespace+"."+case9PolicyNameCopy, 405 managedCluster, 406 true, 407 defaultTimeoutSeconds, 408 ) 409 410 templates, _, _ := unstructured.NestedSlice(replicatedPlc.Object, "spec", "policy-templates") 411 if len(templates) < 1 { 412 return "" 413 } 414 415 template, ok := templates[0].(map[string]interface{}) 416 if !ok { 417 return "" 418 } 419 420 objectTemplates, _, _ := unstructured.NestedSlice( 421 template, "objectDefinition", "spec", "object-templates", 422 ) 423 if len(objectTemplates) < 1 { 424 return "" 425 } 426 427 objectTemplate, ok := objectTemplates[0].(map[string]interface{}) 428 if !ok { 429 return "" 430 } 431 432 secretValue, _, _ := unstructured.NestedString( 433 objectTemplate, "objectDefinition", "data", "token", 434 ) 435 436 return secretValue 437 }, defaultTimeoutSeconds, 1).Should(Equal(expected)) 438 }) 439 440 It("should clean up the encryption key", func() { 441 utils.Kubectl("delete", "secret", 442 case9EncryptionSecretName, 443 "-n", managedCluster, 444 "--kubeconfig="+kubeconfigHub) 445 utils.GetWithTimeout( 446 clientHubDynamic, gvrSecret, case9EncryptionSecretName, managedCluster, 447 false, defaultTimeoutSeconds, 448 ) 449 }) 450 451 It("should clean up", func() { 452 utils.Kubectl("delete", "-f", case9PolicyYamlCopy, 453 "-n", testNamespace, 454 "--kubeconfig="+kubeconfigHub) 455 opt := metav1.ListOptions{} 456 utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, defaultTimeoutSeconds) 457 }) 458 AfterAll(func() { 459 utils.Kubectl("delete", "secret", 460 case9EncryptionSecretName, 461 "-n", managedCluster, 462 "--kubeconfig="+kubeconfigHub) 463 utils.Kubectl("delete", "-f", case9PolicyYamlCopy, 464 "-n", testNamespace, 465 "--kubeconfig="+kubeconfigHub) 466 }) 467 } 468 }) 469 470 Describe("Test policy templates with cluster-scoped lookup", Ordered, func() { 471 It("should be created in user ns", func() { 472 By("Creating " + case9PolicyWithCSLookupName) 473 utils.Kubectl("apply", 474 "-f", case9PolicyWithCSLookupYaml, 475 "-n", testNamespace, 476 "--kubeconfig="+kubeconfigHub) 477 plc := utils.GetWithTimeout( 478 clientHubDynamic, gvrPolicy, case9PolicyWithCSLookupName, testNamespace, true, defaultTimeoutSeconds, 479 ) 480 Expect(plc).NotTo(BeNil()) 481 }) 482 It("should resolve templates and propagate to cluster ns managed1", func() { 483 By("Patching test-policy-plr with decision of cluster managed1") 484 plr := utils.GetWithTimeout( 485 clientHubDynamic, gvrPlacementRule, case9PolicyWithCSLookupName+"-plr", testNamespace, 486 true, defaultTimeoutSeconds, 487 ) 488 plr.Object["status"] = utils.GeneratePlrStatus("managed1") 489 _, err := clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus( 490 context.TODO(), plr, metav1.UpdateOptions{}, 491 ) 492 Expect(err).ToNot(HaveOccurred()) 493 plc := utils.GetWithTimeout( 494 clientHubDynamic, gvrPolicy, testNamespace+"."+case9PolicyWithCSLookupName, "managed1", 495 true, defaultTimeoutSeconds, 496 ) 497 Expect(plc).NotTo(BeNil()) 498 499 By("Verifying the replicated policy was created with the correct error annotation in the template") 500 tmpls, _, _ := unstructured.NestedSlice(plc.Object, "spec", "policy-templates") 501 Expect(tmpls).To(HaveLen(1)) 502 503 tmplAnnotations, _, _ := unstructured.NestedStringMap(tmpls[0].(map[string]interface{}), 504 "objectDefinition", "metadata", "annotations") 505 Expect(tmplAnnotations).ToNot(BeEmpty()) 506 507 hubTmplErrAnnotation := tmplAnnotations["policy.open-cluster-management.io/hub-templates-error"] 508 Expect(hubTmplErrAnnotation).To(ContainSubstring("error calling lookup")) 509 }) 510 AfterAll(func() { 511 utils.Kubectl("delete", 512 "-f", case9PolicyWithCSLookupYaml, 513 "-n", testNamespace, 514 "--kubeconfig="+kubeconfigHub, 515 "--ignore-not-found") 516 opt := metav1.ListOptions{} 517 utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 0, false, defaultTimeoutSeconds) 518 }) 519 }) 520 })