github.com/percona/percona-xtradb-cluster-operator@v1.14.0/pkg/controller/pxc/controller_test.go (about) 1 package pxc 2 3 import ( 4 "context" 5 "fmt" 6 "path/filepath" 7 "strconv" 8 "strings" 9 "time" 10 11 cm "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" 12 . "github.com/onsi/ginkgo/v2" 13 . "github.com/onsi/gomega" 14 gs "github.com/onsi/gomega/gstruct" 15 api "github.com/percona/percona-xtradb-cluster-operator/pkg/apis/pxc/v1" 16 "github.com/percona/percona-xtradb-cluster-operator/pkg/pxc/app/statefulset" 17 appsv1 "k8s.io/api/apps/v1" 18 corev1 "k8s.io/api/core/v1" 19 k8serrors "k8s.io/apimachinery/pkg/api/errors" 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 "k8s.io/apimachinery/pkg/labels" 22 "k8s.io/apimachinery/pkg/types" 23 ctrl "sigs.k8s.io/controller-runtime" 24 "sigs.k8s.io/controller-runtime/pkg/client" 25 "sigs.k8s.io/controller-runtime/pkg/envtest" 26 "sigs.k8s.io/controller-runtime/pkg/reconcile" 27 // +kubebuilder:scaffold:imports 28 ) 29 30 var _ = Describe("PerconaXtraDB Cluster", Ordered, func() { 31 ctx := context.Background() 32 const ns = "pxc" 33 namespace := &corev1.Namespace{ 34 ObjectMeta: metav1.ObjectMeta{ 35 Name: ns, 36 Namespace: ns, 37 }, 38 } 39 crName := ns + "-reconciler" 40 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 41 42 BeforeAll(func() { 43 By("Creating the Namespace to perform the tests") 44 err := k8sClient.Create(ctx, namespace) 45 Expect(err).To(Not(HaveOccurred())) 46 }) 47 48 AfterAll(func() { 49 // TODO(user): Attention if you improve this code by adding other context test you MUST 50 // be aware of the current delete namespace limitations. More info: https://book.kubebuilder.io/reference/envtest.html#testing-considerations 51 By("Deleting the Namespace to perform the tests") 52 _ = k8sClient.Delete(ctx, namespace) 53 }) 54 55 Context("Create Percona XtraDB cluster", func() { 56 cr, err := readDefaultCR(crName, ns) 57 It("should read defautl cr.yaml", func() { 58 Expect(err).NotTo(HaveOccurred()) 59 }) 60 61 It("Should create PerconaXtraDBCluster", func() { 62 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 63 }) 64 }) 65 66 It("Should reconcile PerconaXtraDBCluster", func() { 67 _, err := reconciler().Reconcile(ctx, reconcile.Request{ 68 NamespacedName: crNamespacedName, 69 }) 70 Expect(err).To(Succeed()) 71 }) 72 }) 73 74 var _ = Describe("Finalizer delete-ssl", Ordered, func() { 75 ctx := context.Background() 76 77 const crName = "del-ssl-fnlz" 78 const ns = "del-ssl-fnlz" 79 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 80 81 namespace := &corev1.Namespace{ 82 ObjectMeta: metav1.ObjectMeta{ 83 Name: ns, 84 Namespace: ns, 85 }, 86 } 87 88 BeforeAll(func() { 89 By("Creating the Namespace to perform the tests") 90 err := k8sClient.Create(ctx, namespace) 91 Expect(err).To(Not(HaveOccurred())) 92 93 _, err = envtest.InstallCRDs(cfg, envtest.CRDInstallOptions{ 94 Paths: []string{filepath.Join("testdata", "cert-manager.yaml")}, 95 }) 96 Expect(err).NotTo(HaveOccurred()) 97 }) 98 99 AfterAll(func() { 100 By("Deleting the Namespace to perform the tests") 101 _ = k8sClient.Delete(ctx, namespace) 102 }) 103 104 Context("delete-ssl finalizer specified", Ordered, func() { 105 106 cr, err := readDefaultCR(crName, ns) 107 108 It("should read default cr.yaml", func() { 109 Expect(err).NotTo(HaveOccurred()) 110 }) 111 112 cr.Finalizers = append(cr.Finalizers, "delete-ssl") 113 cr.Spec.SSLSecretName = "cluster1-ssl" 114 cr.Spec.SSLInternalSecretName = "cluster1-ssl-internal" 115 116 It("Should create PerconaXtraDBCluster", func() { 117 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 118 }) 119 120 It("should reconcile once to create user secret", func() { 121 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 122 Expect(err).NotTo(HaveOccurred()) 123 }) 124 125 It("controller should create ssl-secrets", func() { 126 secret := &corev1.Secret{} 127 Expect(k8sClient.Get(ctx, types.NamespacedName{ 128 Namespace: cr.Namespace, 129 Name: cr.Spec.SSLSecretName, 130 }, secret)).Should(Succeed()) 131 132 Expect(k8sClient.Get(ctx, types.NamespacedName{ 133 Namespace: cr.Namespace, 134 Name: cr.Spec.SSLInternalSecretName, 135 }, secret)).Should(Succeed()) 136 }) 137 138 It("controller should create issuers and certificates", func() { 139 issuers := &cm.IssuerList{} 140 Eventually(func() bool { 141 142 opts := &client.ListOptions{Namespace: cr.Namespace} 143 err := k8sClient.List(ctx, issuers, opts) 144 145 return err == nil 146 }, time.Second*30, time.Millisecond*250).Should(BeTrue()) 147 148 Expect(issuers.Items).ShouldNot(BeEmpty()) 149 150 certs := &cm.CertificateList{} 151 Eventually(func() bool { 152 153 opts := &client.ListOptions{Namespace: cr.Namespace} 154 err := k8sClient.List(ctx, certs, opts) 155 156 return err == nil 157 }, time.Second*30, time.Millisecond*250).Should(BeTrue()) 158 159 Expect(certs.Items).ShouldNot(BeEmpty()) 160 }) 161 162 When("PXC cluster is deleted with delete-ssl finalizer certs should be removed", func() { 163 It("should delete PXC cluster and reconcile changes", func() { 164 Expect(k8sClient.Delete(ctx, cr)).Should(Succeed()) 165 166 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 167 Expect(err).NotTo(HaveOccurred()) 168 }) 169 170 It("controller should remove ssl-secrets", func() { 171 secret := &corev1.Secret{} 172 Eventually(func() bool { 173 err := k8sClient.Get(ctx, types.NamespacedName{ 174 Namespace: cr.Namespace, 175 Name: cr.Spec.SSLSecretName, 176 }, secret) 177 178 return k8serrors.IsNotFound(err) 179 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 180 181 Eventually(func() bool { 182 err := k8sClient.Get(ctx, types.NamespacedName{ 183 Namespace: cr.Namespace, 184 Name: cr.Spec.SSLInternalSecretName, 185 }, secret) 186 187 return k8serrors.IsNotFound(err) 188 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 189 190 Eventually(func() bool { 191 err := k8sClient.Get(ctx, types.NamespacedName{ 192 Namespace: cr.Namespace, 193 Name: cr.Name + "-ca-cert", 194 }, secret) 195 196 return k8serrors.IsNotFound(err) 197 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 198 }) 199 200 It("controller should delete issuers and certificates", func() { 201 issuers := &cm.IssuerList{} 202 Eventually(func() bool { 203 204 opts := &client.ListOptions{Namespace: cr.Namespace} 205 err := k8sClient.List(ctx, issuers, opts) 206 207 return err == nil 208 }, time.Second*30, time.Millisecond*250).Should(BeTrue()) 209 210 Expect(issuers.Items).Should(BeEmpty()) 211 212 certs := &cm.CertificateList{} 213 Eventually(func() bool { 214 215 opts := &client.ListOptions{Namespace: cr.Namespace} 216 err := k8sClient.List(ctx, certs, opts) 217 218 return err == nil 219 }, time.Second*30, time.Millisecond*250).Should(BeTrue()) 220 221 Expect(certs.Items).Should(BeEmpty()) 222 }) 223 }) 224 }) 225 }) 226 227 var _ = Describe("Finalizer delete-proxysql-pvc", Ordered, func() { 228 ctx := context.Background() 229 230 const crName = "del-proxysql-pvc-fnlz" 231 const ns = "del-proxysql-pvc-fnlz" 232 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 233 234 namespace := &corev1.Namespace{ 235 ObjectMeta: metav1.ObjectMeta{ 236 Name: ns, 237 Namespace: ns, 238 }, 239 } 240 241 BeforeAll(func() { 242 By("Creating the Namespace to perform the tests") 243 err := k8sClient.Create(ctx, namespace) 244 Expect(err).To(Not(HaveOccurred())) 245 246 _, err = envtest.InstallCRDs(cfg, envtest.CRDInstallOptions{ 247 Paths: []string{filepath.Join("testdata", "cert-manager.yaml")}, 248 }) 249 Expect(err).NotTo(HaveOccurred()) 250 }) 251 252 AfterAll(func() { 253 By("Deleting the Namespace to perform the tests") 254 _ = k8sClient.Delete(ctx, namespace) 255 }) 256 257 Context("delete-proxysql-pvc finalizer specified", Ordered, func() { 258 259 cr, err := readDefaultCR(crName, ns) 260 261 It("should read default cr.yaml", func() { 262 Expect(err).NotTo(HaveOccurred()) 263 }) 264 265 cr.Finalizers = append(cr.Finalizers, "delete-proxysql-pvc") 266 cr.Spec.SecretsName = "cluster1-secrets" 267 cr.Spec.HAProxy.Enabled = false 268 cr.Spec.ProxySQL.Enabled = true 269 270 sfsWithOwner := appsv1.StatefulSet{} 271 sfsProxy := statefulset.NewProxy(cr) 272 273 It("Should create PerconaXtraDBCluster", func() { 274 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 275 }) 276 277 It("should reconcile once to create user secret and pvc", func() { 278 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 279 Expect(err).NotTo(HaveOccurred()) 280 }) 281 282 It("Should create proxysql sts", func() { 283 284 Expect(k8sClient.Get(ctx, types.NamespacedName{ 285 Name: cr.Name + "-proxysql", 286 Namespace: cr.Namespace, 287 }, &sfsWithOwner)).Should(Succeed()) 288 }) 289 290 It("Should create secrets", func() { 291 secret := &corev1.Secret{} 292 Expect(k8sClient.Get(ctx, types.NamespacedName{ 293 Namespace: cr.Namespace, 294 Name: cr.Spec.SecretsName, 295 }, secret)).Should(Succeed()) 296 }) 297 298 It("should create proxysql PVC", func() { 299 for _, claim := range sfsWithOwner.Spec.VolumeClaimTemplates { 300 for i := 0; i < int(*sfsWithOwner.Spec.Replicas); i++ { 301 pvc := claim.DeepCopy() 302 pvc.Labels = sfsProxy.Labels() 303 pvc.Name = strings.Join([]string{pvc.Name, sfsWithOwner.Name, strconv.Itoa(i)}, "-") 304 pvc.Namespace = ns 305 Expect(k8sClient.Create(ctx, pvc)).Should(Succeed()) 306 } 307 } 308 }) 309 310 It("controller should have proxysql pvc", func() { 311 pvcList := corev1.PersistentVolumeClaimList{} 312 Eventually(func() bool { 313 err := k8sClient.List(ctx, 314 &pvcList, 315 &client.ListOptions{ 316 Namespace: cr.Namespace, 317 LabelSelector: labels.SelectorFromSet(map[string]string{ 318 "app.kubernetes.io/component": "proxysql", 319 }), 320 }) 321 return err == nil 322 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 323 Expect(len(pvcList.Items)).Should(Equal(3)) 324 }) 325 326 When("PXC cluster is deleted with delete-proxysql-pvc finalizer sts and pvc should be removed and secrets kept", func() { 327 It("should delete PXC cluster and reconcile changes", func() { 328 Expect(k8sClient.Delete(ctx, cr)).Should(Succeed()) 329 330 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 331 Expect(err).NotTo(HaveOccurred()) 332 }) 333 334 It("controller should remove sts", func() { 335 Eventually(func() bool { 336 err := k8sClient.Get(ctx, types.NamespacedName{ 337 Name: cr.Name + "-proxysql", 338 Namespace: cr.Namespace, 339 }, &sfsWithOwner) 340 return k8serrors.IsNotFound(err) 341 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 342 343 }) 344 345 It("controller should remove pvc for proxysql", func() { 346 pvcList := corev1.PersistentVolumeClaimList{} 347 Eventually(func() bool { 348 err := k8sClient.List(ctx, &pvcList, &client.ListOptions{ 349 Namespace: cr.Namespace, 350 LabelSelector: labels.SelectorFromSet(map[string]string{ 351 "app.kubernetes.io/component": "proxysql", 352 }), 353 }) 354 return err == nil 355 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 356 357 for _, pvc := range pvcList.Items { 358 By(fmt.Sprintf("checking pvc/%s", pvc.Name)) 359 Expect(pvc.DeletionTimestamp).ShouldNot(BeNil()) 360 } 361 }) 362 363 It("controller should keep secrets", func() { 364 secret := &corev1.Secret{} 365 Eventually(func() bool { 366 err := k8sClient.Get(ctx, types.NamespacedName{ 367 Namespace: cr.Namespace, 368 Name: cr.Spec.SecretsName, 369 }, secret) 370 371 return k8serrors.IsNotFound(err) 372 }, time.Second*15, time.Millisecond*250).Should(BeFalse()) 373 374 Eventually(func() bool { 375 err := k8sClient.Get(ctx, types.NamespacedName{ 376 Namespace: cr.Namespace, 377 Name: "internal-" + cr.Name, 378 }, secret) 379 380 return k8serrors.IsNotFound(err) 381 }, time.Second*15, time.Millisecond*250).Should(BeFalse()) 382 383 }) 384 }) 385 }) 386 }) 387 388 var _ = Describe("Finalizer delete-pxc-pvc", Ordered, func() { 389 ctx := context.Background() 390 391 const crName = "del-pxc-pvc-fnlz" 392 const ns = "del-pxc-pvc-fnlz" 393 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 394 395 namespace := &corev1.Namespace{ 396 ObjectMeta: metav1.ObjectMeta{ 397 Name: ns, 398 Namespace: ns, 399 }, 400 } 401 402 BeforeAll(func() { 403 By("Creating the Namespace to perform the tests") 404 err := k8sClient.Create(ctx, namespace) 405 Expect(err).To(Not(HaveOccurred())) 406 407 _, err = envtest.InstallCRDs(cfg, envtest.CRDInstallOptions{ 408 Paths: []string{filepath.Join("testdata", "cert-manager.yaml")}, 409 }) 410 Expect(err).NotTo(HaveOccurred()) 411 }) 412 413 AfterAll(func() { 414 By("Deleting the Namespace to perform the tests") 415 _ = k8sClient.Delete(ctx, namespace) 416 }) 417 418 Context("delete-pxc-pvc finalizer specified", Ordered, func() { 419 420 cr, err := readDefaultCR(crName, ns) 421 422 It("should read default cr.yaml", func() { 423 Expect(err).NotTo(HaveOccurred()) 424 }) 425 cr.Finalizers = append(cr.Finalizers, "delete-pxc-pvc") 426 cr.Spec.SecretsName = "cluster1-secrets" 427 428 sfsWithOwner := appsv1.StatefulSet{} 429 stsApp := statefulset.NewNode(cr) 430 431 It("Should create PerconaXtraDBCluster", func() { 432 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 433 }) 434 435 It("should reconcile once to create user secret", func() { 436 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 437 Expect(err).NotTo(HaveOccurred()) 438 }) 439 440 It("Should create pxc sts", func() { 441 442 Expect(k8sClient.Get(ctx, types.NamespacedName{ 443 Name: cr.Name + "-pxc", 444 Namespace: cr.Namespace, 445 }, &sfsWithOwner)).Should(Succeed()) 446 }) 447 448 It("Should create secrets", func() { 449 secret := &corev1.Secret{} 450 Expect(k8sClient.Get(ctx, types.NamespacedName{ 451 Namespace: cr.Namespace, 452 Name: cr.Spec.SecretsName, 453 }, secret)).Should(Succeed()) 454 }) 455 456 It("should create pxc PVC", func() { 457 for _, claim := range sfsWithOwner.Spec.VolumeClaimTemplates { 458 for i := 0; i < int(*sfsWithOwner.Spec.Replicas); i++ { 459 pvc := claim.DeepCopy() 460 pvc.Labels = stsApp.Labels() 461 pvc.Name = strings.Join([]string{pvc.Name, sfsWithOwner.Name, strconv.Itoa(i)}, "-") 462 pvc.Namespace = ns 463 Expect(k8sClient.Create(ctx, pvc)).Should(Succeed()) 464 } 465 } 466 }) 467 468 It("controller should have pxc pvc", func() { 469 pvcList := corev1.PersistentVolumeClaimList{} 470 Eventually(func() bool { 471 err := k8sClient.List(ctx, 472 &pvcList, 473 &client.ListOptions{ 474 Namespace: cr.Namespace, 475 LabelSelector: labels.SelectorFromSet(map[string]string{ 476 "app.kubernetes.io/component": "pxc", 477 }), 478 }) 479 return err == nil 480 }, time.Second*25, time.Millisecond*250).Should(BeTrue()) 481 Expect(len(pvcList.Items)).Should(Equal(3)) 482 }) 483 484 When("PXC cluster is deleted with delete-pxc-pvc finalizer sts, pvc, and secrets should be removed", func() { 485 It("should delete PXC cluster and reconcile changes", func() { 486 Expect(k8sClient.Delete(ctx, cr)).Should(Succeed()) 487 488 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 489 Expect(err).NotTo(HaveOccurred()) 490 }) 491 492 It("controller should remove sts", func() { 493 Eventually(func() bool { 494 err := k8sClient.Get(ctx, types.NamespacedName{ 495 Name: cr.Name + "-pxc", 496 Namespace: cr.Namespace, 497 }, &sfsWithOwner) 498 return k8serrors.IsNotFound(err) 499 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 500 501 }) 502 503 It("controller should remove pvc for pxc", func() { 504 pvcList := corev1.PersistentVolumeClaimList{} 505 Eventually(func() bool { 506 err := k8sClient.List(ctx, &pvcList, &client.ListOptions{ 507 Namespace: cr.Namespace, 508 LabelSelector: labels.SelectorFromSet(map[string]string{ 509 "app.kubernetes.io/component": "pxc", 510 }), 511 }) 512 return err == nil 513 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 514 515 for _, pvc := range pvcList.Items { 516 By(fmt.Sprintf("checking pvc/%s", pvc.Name)) 517 Expect(pvc.DeletionTimestamp).ShouldNot(BeNil()) 518 } 519 }) 520 521 It("controller should delete secrets", func() { 522 secret := &corev1.Secret{} 523 Eventually(func() bool { 524 err := k8sClient.Get(ctx, types.NamespacedName{ 525 Namespace: cr.Namespace, 526 Name: cr.Spec.SecretsName, 527 }, secret) 528 529 return k8serrors.IsNotFound(err) 530 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 531 532 Eventually(func() bool { 533 err := k8sClient.Get(ctx, types.NamespacedName{ 534 Namespace: cr.Namespace, 535 Name: "internal-" + cr.Name, 536 }, secret) 537 538 return k8serrors.IsNotFound(err) 539 }, time.Second*15, time.Millisecond*250).Should(BeTrue()) 540 541 }) 542 }) 543 }) 544 }) 545 546 var _ = Describe("Authentication policy", Ordered, func() { 547 ctx := context.Background() 548 549 const ns = "auth-policy" 550 namespace := &corev1.Namespace{ 551 ObjectMeta: metav1.ObjectMeta{ 552 Name: ns, 553 Namespace: ns, 554 }, 555 } 556 557 BeforeAll(func() { 558 By("Creating the Namespace to perform the tests") 559 err := k8sClient.Create(ctx, namespace) 560 Expect(err).To(Not(HaveOccurred())) 561 }) 562 563 AfterAll(func() { 564 By("Deleting the Namespace to perform the tests") 565 _ = k8sClient.Delete(ctx, namespace) 566 }) 567 568 Context("Cluster is deployed with ProxySQL", Ordered, func() { 569 const crName = "auth-policy-proxysql" 570 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 571 572 cr, err := readDefaultCR(crName, ns) 573 It("should read default cr.yaml", func() { 574 Expect(err).NotTo(HaveOccurred()) 575 }) 576 577 It("should create PerconaXtraDBCluster", func() { 578 cr.Spec.HAProxy.Enabled = false 579 cr.Spec.ProxySQL.Enabled = true 580 581 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 582 }) 583 584 It("should reconcile", func() { 585 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 586 Expect(err).NotTo(HaveOccurred()) 587 }) 588 589 It("should use mysql_native_password", func() { 590 sts := appsv1.StatefulSet{ 591 ObjectMeta: metav1.ObjectMeta{ 592 Name: crName + "-pxc", 593 Namespace: ns, 594 }, 595 } 596 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&sts), &sts) 597 Expect(err).NotTo(HaveOccurred()) 598 599 for _, c := range sts.Spec.Template.Spec.Containers { 600 if c.Name == "pxc" { 601 Expect(c.Env).Should(ContainElement(gs.MatchFields(gs.IgnoreExtras, gs.Fields{ 602 "Name": Equal("DEFAULT_AUTHENTICATION_PLUGIN"), 603 "Value": Equal("mysql_native_password"), 604 }))) 605 } 606 } 607 }) 608 }) 609 610 Context("Cluster is deployed with HAProxy", Ordered, func() { 611 const crName = "auth-policy-haproxy" 612 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 613 614 cr, err := readDefaultCR(crName, ns) 615 It("should read default cr.yaml", func() { 616 Expect(err).NotTo(HaveOccurred()) 617 }) 618 619 It("should create PerconaXtraDBCluster", func() { 620 cr.Spec.HAProxy.Enabled = true 621 cr.Spec.ProxySQL.Enabled = false 622 623 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 624 }) 625 626 It("should reconcile", func() { 627 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 628 Expect(err).NotTo(HaveOccurred()) 629 }) 630 631 It("should use caching_sha2_password", func() { 632 sts := appsv1.StatefulSet{ 633 ObjectMeta: metav1.ObjectMeta{ 634 Name: crName + "-pxc", 635 Namespace: ns, 636 }, 637 } 638 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&sts), &sts) 639 Expect(err).NotTo(HaveOccurred()) 640 641 envFound := false 642 for _, c := range sts.Spec.Template.Spec.Containers { 643 if c.Name == "pxc" { 644 for _, e := range c.Env { 645 if e.Name == "DEFAULT_AUTHENTICATION_PLUGIN" { 646 envFound = true 647 Expect(e.Value).To(Equal("caching_sha2_password")) 648 } 649 } 650 } 651 } 652 653 Expect(envFound).To(BeTrue()) 654 }) 655 656 When("Proxy is switched from HAProxy to ProxySQL", func() { 657 It("should update PerconaXtraDBCluster", func() { 658 cr := &api.PerconaXtraDBCluster{ 659 ObjectMeta: metav1.ObjectMeta{ 660 Name: crName, 661 Namespace: ns, 662 }, 663 } 664 Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr)).Should(Succeed()) 665 666 cr.Spec.HAProxy.Enabled = false 667 cr.Spec.ProxySQL.Enabled = true 668 669 Expect(k8sClient.Update(ctx, cr)).Should(Succeed()) 670 }) 671 672 It("should NOT reconcile", func() { 673 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 674 Expect(err).To(MatchError("failed to enable ProxySQL: for mysql version 8.0 you can't switch from HAProxy to ProxySQL")) 675 }) 676 }) 677 }) 678 }) 679 680 var _ = Describe("Ignore labels and annotations", Ordered, func() { 681 ctx := context.Background() 682 683 const ns = "ignore-lbl-ants" 684 namespace := &corev1.Namespace{ 685 ObjectMeta: metav1.ObjectMeta{ 686 Name: ns, 687 Namespace: ns, 688 }, 689 } 690 691 BeforeAll(func() { 692 By("Creating the Namespace to perform the tests") 693 err := k8sClient.Create(ctx, namespace) 694 Expect(err).To(Not(HaveOccurred())) 695 }) 696 697 AfterAll(func() { 698 By("Deleting the Namespace to perform the tests") 699 _ = k8sClient.Delete(ctx, namespace) 700 }) 701 702 Context("HAProxy", Ordered, func() { 703 const crName = "ignore-lbl-ants-h" 704 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 705 706 cr, err := readDefaultCR(crName, ns) 707 It("should read default cr.yaml", func() { 708 Expect(err).NotTo(HaveOccurred()) 709 }) 710 711 It("should create PerconaXtraDBCluster", func() { 712 cr.Spec.HAProxy.Enabled = true 713 cr.Spec.ProxySQL.Enabled = false 714 715 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 716 }) 717 718 It("should reconcile", func() { 719 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 720 Expect(err).NotTo(HaveOccurred()) 721 }) 722 723 It("patches services with labels and annotations", func() { 724 svc := corev1.Service{ 725 ObjectMeta: metav1.ObjectMeta{ 726 Name: crName + "-haproxy", 727 Namespace: ns, 728 }, 729 } 730 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 731 Expect(err).NotTo(HaveOccurred()) 732 733 orig := svc.DeepCopy() 734 735 svc.ObjectMeta.Annotations["notIgnoredAnnotation"] = "true" 736 svc.ObjectMeta.Annotations["ignoredAnnotation"] = "true" 737 738 svc.ObjectMeta.Labels["notIgnoredLabel"] = "true" 739 svc.ObjectMeta.Labels["ignoredLabel"] = "true" 740 741 err = k8sClient.Patch(ctx, &svc, client.MergeFrom(orig)) 742 Expect(err).NotTo(HaveOccurred()) 743 }) 744 745 It("should reconcile", func() { 746 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 747 Expect(err).NotTo(HaveOccurred()) 748 }) 749 750 It("check all labels and annotations exist in the service", func() { 751 svc := corev1.Service{ 752 ObjectMeta: metav1.ObjectMeta{ 753 Name: crName + "-haproxy", 754 Namespace: ns, 755 }, 756 } 757 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 758 Expect(err).NotTo(HaveOccurred()) 759 760 Expect(svc.ObjectMeta.Annotations).To(HaveKey("notIgnoredAnnotation")) 761 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 762 763 Expect(svc.ObjectMeta.Labels).To(HaveKey("notIgnoredLabel")) 764 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 765 }) 766 767 It("should add ignored labels and annotations", func() { 768 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 769 Expect(err).NotTo(HaveOccurred()) 770 771 orig := cr.DeepCopy() 772 773 cr.Spec.IgnoreAnnotations = append(cr.Spec.IgnoreAnnotations, "ignoredAnnotation") 774 cr.Spec.IgnoreLabels = append(cr.Spec.IgnoreLabels, "ignoredLabel") 775 776 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 777 Expect(err).NotTo(HaveOccurred()) 778 }) 779 780 It("should reconcile", func() { 781 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 782 Expect(err).NotTo(HaveOccurred()) 783 }) 784 785 It("check all labels and annotations exist in the service", func() { 786 svc := corev1.Service{ 787 ObjectMeta: metav1.ObjectMeta{ 788 Name: crName + "-haproxy", 789 Namespace: ns, 790 }, 791 } 792 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 793 Expect(err).NotTo(HaveOccurred()) 794 795 Expect(svc.ObjectMeta.Annotations).To(HaveKey("notIgnoredAnnotation")) 796 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 797 798 Expect(svc.ObjectMeta.Labels).To(HaveKey("notIgnoredLabel")) 799 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 800 }) 801 802 It("patches CR with service labels and annotations", func() { 803 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 804 Expect(err).NotTo(HaveOccurred()) 805 806 orig := cr.DeepCopy() 807 808 cr.Spec.HAProxy.ExposePrimary.Annotations = make(map[string]string) 809 cr.Spec.HAProxy.ExposePrimary.Labels = make(map[string]string) 810 811 cr.Spec.HAProxy.ExposePrimary.Annotations["crAnnotation"] = "true" 812 cr.Spec.HAProxy.ExposePrimary.Labels["crLabel"] = "true" 813 814 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 815 Expect(err).NotTo(HaveOccurred()) 816 }) 817 818 It("should reconcile", func() { 819 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 820 Expect(err).NotTo(HaveOccurred()) 821 }) 822 823 It("should delete all not ignored labels and annotations from service", func() { 824 svc := corev1.Service{ 825 ObjectMeta: metav1.ObjectMeta{ 826 Name: crName + "-haproxy", 827 Namespace: ns, 828 }, 829 } 830 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 831 Expect(err).NotTo(HaveOccurred()) 832 833 Expect(svc.ObjectMeta.Annotations).To(HaveKey("crAnnotation")) 834 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 835 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("notIgnoredAnnotation")) 836 837 Expect(svc.ObjectMeta.Labels).To(HaveKey("crLabel")) 838 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 839 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("notIgnoredLabel")) 840 }) 841 842 It("deletes service labels and annotations from CR", func() { 843 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 844 Expect(err).NotTo(HaveOccurred()) 845 846 orig := cr.DeepCopy() 847 848 delete(cr.Spec.HAProxy.ExposePrimary.Annotations, "crAnnotation") 849 delete(cr.Spec.HAProxy.ExposePrimary.Labels, "crLabel") 850 851 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 852 Expect(err).NotTo(HaveOccurred()) 853 }) 854 855 It("should reconcile", func() { 856 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 857 Expect(err).NotTo(HaveOccurred()) 858 }) 859 860 It("should not delete any labels and annotations from service", func() { 861 svc := corev1.Service{ 862 ObjectMeta: metav1.ObjectMeta{ 863 Name: crName + "-haproxy", 864 Namespace: ns, 865 }, 866 } 867 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 868 Expect(err).NotTo(HaveOccurred()) 869 870 Expect(svc.ObjectMeta.Annotations).To(HaveKey("crAnnotation")) 871 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 872 873 Expect(svc.ObjectMeta.Labels).To(HaveKey("crLabel")) 874 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 875 }) 876 877 It("patches CR with more service labels and annotations", func() { 878 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 879 Expect(err).NotTo(HaveOccurred()) 880 881 orig := cr.DeepCopy() 882 883 cr.Spec.HAProxy.ExposePrimary.Annotations = make(map[string]string) 884 cr.Spec.HAProxy.ExposePrimary.Labels = make(map[string]string) 885 886 cr.Spec.HAProxy.ExposePrimary.Annotations["secondCrAnnotation"] = "true" 887 cr.Spec.HAProxy.ExposePrimary.Annotations["thirdCrAnnotation"] = "true" 888 889 cr.Spec.HAProxy.ExposePrimary.Labels["secondCrLabel"] = "true" 890 cr.Spec.HAProxy.ExposePrimary.Labels["thirdCrLabel"] = "true" 891 892 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 893 Expect(err).NotTo(HaveOccurred()) 894 }) 895 896 It("should reconcile", func() { 897 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 898 Expect(err).NotTo(HaveOccurred()) 899 }) 900 901 It("should delete previous labels and annotations from service", func() { 902 svc := corev1.Service{ 903 ObjectMeta: metav1.ObjectMeta{ 904 Name: crName + "-haproxy", 905 Namespace: ns, 906 }, 907 } 908 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 909 Expect(err).NotTo(HaveOccurred()) 910 911 Expect(svc.ObjectMeta.Annotations).To(HaveKey("secondCrAnnotation")) 912 Expect(svc.ObjectMeta.Annotations).To(HaveKey("thirdCrAnnotation")) 913 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 914 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("crAnnotation")) 915 916 Expect(svc.ObjectMeta.Labels).To(HaveKey("secondCrLabel")) 917 Expect(svc.ObjectMeta.Labels).To(HaveKey("thirdCrLabel")) 918 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 919 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("crLabel")) 920 }) 921 922 It("deletes a label and an annotation from CR", func() { 923 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 924 Expect(err).NotTo(HaveOccurred()) 925 926 orig := cr.DeepCopy() 927 928 delete(cr.Spec.HAProxy.ExposePrimary.Annotations, "secondCrAnnotation") 929 delete(cr.Spec.HAProxy.ExposePrimary.Labels, "secondCrLabel") 930 931 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 932 Expect(err).NotTo(HaveOccurred()) 933 }) 934 935 It("should reconcile", func() { 936 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 937 Expect(err).NotTo(HaveOccurred()) 938 }) 939 940 It("should delete removed service label and annotation from service", func() { 941 svc := corev1.Service{ 942 ObjectMeta: metav1.ObjectMeta{ 943 Name: crName + "-haproxy", 944 Namespace: ns, 945 }, 946 } 947 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 948 Expect(err).NotTo(HaveOccurred()) 949 950 Expect(svc.ObjectMeta.Annotations).To(HaveKey("thirdCrAnnotation")) 951 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 952 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("secondCrAnnotation")) 953 954 Expect(svc.ObjectMeta.Labels).To(HaveKey("thirdCrLabel")) 955 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 956 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("secondCrLabel")) 957 }) 958 959 It("deletes ignored labels and annotations from CR", func() { 960 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 961 Expect(err).NotTo(HaveOccurred()) 962 963 orig := cr.DeepCopy() 964 965 cr.Spec.IgnoreAnnotations = []string{} 966 cr.Spec.IgnoreLabels = []string{} 967 968 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 969 Expect(err).NotTo(HaveOccurred()) 970 }) 971 972 It("should reconcile", func() { 973 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 974 Expect(err).NotTo(HaveOccurred()) 975 }) 976 977 It("should delete unknown labels and annotations from service", func() { 978 svc := corev1.Service{ 979 ObjectMeta: metav1.ObjectMeta{ 980 Name: crName + "-haproxy", 981 Namespace: ns, 982 }, 983 } 984 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 985 Expect(err).NotTo(HaveOccurred()) 986 987 Expect(svc.ObjectMeta.Annotations).To(HaveKey("thirdCrAnnotation")) 988 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("ignoredAnnotation")) 989 990 Expect(svc.ObjectMeta.Labels).To(HaveKey("thirdCrLabel")) 991 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("ignoredLabel")) 992 }) 993 }) 994 995 Context("ProxySQL", Ordered, func() { 996 const crName = "ignore-lbl-ants-p" 997 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 998 999 cr, err := readDefaultCR(crName, ns) 1000 It("should read default cr.yaml", func() { 1001 Expect(err).NotTo(HaveOccurred()) 1002 }) 1003 1004 It("should create PerconaXtraDBCluster", func() { 1005 cr.Spec.HAProxy.Enabled = false 1006 cr.Spec.ProxySQL.Enabled = true 1007 1008 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 1009 }) 1010 1011 It("should reconcile", func() { 1012 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1013 Expect(err).NotTo(HaveOccurred()) 1014 }) 1015 1016 It("patches services with labels and annotations", func() { 1017 svc := corev1.Service{ 1018 ObjectMeta: metav1.ObjectMeta{ 1019 Name: crName + "-proxysql", 1020 Namespace: ns, 1021 }, 1022 } 1023 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1024 Expect(err).NotTo(HaveOccurred()) 1025 1026 orig := svc.DeepCopy() 1027 1028 svc.ObjectMeta.Annotations["notIgnoredAnnotation"] = "true" 1029 svc.ObjectMeta.Annotations["ignoredAnnotation"] = "true" 1030 1031 svc.ObjectMeta.Labels["notIgnoredLabel"] = "true" 1032 svc.ObjectMeta.Labels["ignoredLabel"] = "true" 1033 1034 err = k8sClient.Patch(ctx, &svc, client.MergeFrom(orig)) 1035 Expect(err).NotTo(HaveOccurred()) 1036 }) 1037 1038 It("should reconcile", func() { 1039 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1040 Expect(err).NotTo(HaveOccurred()) 1041 }) 1042 1043 It("check all labels and annotations exist in the service", func() { 1044 svc := corev1.Service{ 1045 ObjectMeta: metav1.ObjectMeta{ 1046 Name: crName + "-proxysql", 1047 Namespace: ns, 1048 }, 1049 } 1050 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1051 Expect(err).NotTo(HaveOccurred()) 1052 1053 Expect(svc.ObjectMeta.Annotations).To(HaveKey("notIgnoredAnnotation")) 1054 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 1055 1056 Expect(svc.ObjectMeta.Labels).To(HaveKey("notIgnoredLabel")) 1057 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 1058 }) 1059 1060 It("should add ignored labels and annotations", func() { 1061 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 1062 Expect(err).NotTo(HaveOccurred()) 1063 1064 orig := cr.DeepCopy() 1065 1066 cr.Spec.IgnoreAnnotations = append(cr.Spec.IgnoreAnnotations, "ignoredAnnotation") 1067 cr.Spec.IgnoreLabels = append(cr.Spec.IgnoreLabels, "ignoredLabel") 1068 1069 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 1070 Expect(err).NotTo(HaveOccurred()) 1071 }) 1072 1073 It("should reconcile", func() { 1074 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1075 Expect(err).NotTo(HaveOccurred()) 1076 }) 1077 1078 It("check all labels and annotations exist in the service", func() { 1079 svc := corev1.Service{ 1080 ObjectMeta: metav1.ObjectMeta{ 1081 Name: crName + "-proxysql", 1082 Namespace: ns, 1083 }, 1084 } 1085 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1086 Expect(err).NotTo(HaveOccurred()) 1087 1088 Expect(svc.ObjectMeta.Annotations).To(HaveKey("notIgnoredAnnotation")) 1089 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 1090 1091 Expect(svc.ObjectMeta.Labels).To(HaveKey("notIgnoredLabel")) 1092 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 1093 }) 1094 1095 It("patches CR with service labels and annotations", func() { 1096 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 1097 Expect(err).NotTo(HaveOccurred()) 1098 1099 orig := cr.DeepCopy() 1100 1101 cr.Spec.ProxySQL.Expose.Annotations = make(map[string]string) 1102 cr.Spec.ProxySQL.Expose.Labels = make(map[string]string) 1103 1104 cr.Spec.ProxySQL.Expose.Annotations["crAnnotation"] = "true" 1105 cr.Spec.ProxySQL.Expose.Labels["crLabel"] = "true" 1106 1107 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 1108 Expect(err).NotTo(HaveOccurred()) 1109 }) 1110 1111 It("should reconcile", func() { 1112 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1113 Expect(err).NotTo(HaveOccurred()) 1114 }) 1115 1116 It("should delete all not ignored labels and annotations from service", func() { 1117 svc := corev1.Service{ 1118 ObjectMeta: metav1.ObjectMeta{ 1119 Name: crName + "-proxysql", 1120 Namespace: ns, 1121 }, 1122 } 1123 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1124 Expect(err).NotTo(HaveOccurred()) 1125 1126 Expect(svc.ObjectMeta.Annotations).To(HaveKey("crAnnotation")) 1127 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 1128 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("notIgnoredAnnotation")) 1129 1130 Expect(svc.ObjectMeta.Labels).To(HaveKey("crLabel")) 1131 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 1132 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("notIgnoredLabel")) 1133 }) 1134 1135 It("deletes service labels and annotations from CR", func() { 1136 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 1137 Expect(err).NotTo(HaveOccurred()) 1138 1139 orig := cr.DeepCopy() 1140 1141 delete(cr.Spec.ProxySQL.Expose.Annotations, "crAnnotation") 1142 delete(cr.Spec.ProxySQL.Expose.Labels, "crLabel") 1143 1144 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 1145 Expect(err).NotTo(HaveOccurred()) 1146 }) 1147 1148 It("should reconcile", func() { 1149 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1150 Expect(err).NotTo(HaveOccurred()) 1151 }) 1152 1153 It("should not delete any labels and annotations from service", func() { 1154 svc := corev1.Service{ 1155 ObjectMeta: metav1.ObjectMeta{ 1156 Name: crName + "-proxysql", 1157 Namespace: ns, 1158 }, 1159 } 1160 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1161 Expect(err).NotTo(HaveOccurred()) 1162 1163 Expect(svc.ObjectMeta.Annotations).To(HaveKey("crAnnotation")) 1164 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 1165 1166 Expect(svc.ObjectMeta.Labels).To(HaveKey("crLabel")) 1167 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 1168 }) 1169 1170 It("patches CR with more service labels and annotations", func() { 1171 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 1172 Expect(err).NotTo(HaveOccurred()) 1173 1174 orig := cr.DeepCopy() 1175 1176 cr.Spec.ProxySQL.Expose.Annotations = make(map[string]string) 1177 cr.Spec.ProxySQL.Expose.Labels = make(map[string]string) 1178 1179 cr.Spec.ProxySQL.Expose.Annotations["secondCrAnnotation"] = "true" 1180 cr.Spec.ProxySQL.Expose.Annotations["thirdCrAnnotation"] = "true" 1181 1182 cr.Spec.ProxySQL.Expose.Labels["secondCrLabel"] = "true" 1183 cr.Spec.ProxySQL.Expose.Labels["thirdCrLabel"] = "true" 1184 1185 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 1186 Expect(err).NotTo(HaveOccurred()) 1187 }) 1188 1189 It("should reconcile", func() { 1190 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1191 Expect(err).NotTo(HaveOccurred()) 1192 }) 1193 1194 It("should delete previous labels and annotations from service", func() { 1195 svc := corev1.Service{ 1196 ObjectMeta: metav1.ObjectMeta{ 1197 Name: crName + "-proxysql", 1198 Namespace: ns, 1199 }, 1200 } 1201 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1202 Expect(err).NotTo(HaveOccurred()) 1203 1204 Expect(svc.ObjectMeta.Annotations).To(HaveKey("secondCrAnnotation")) 1205 Expect(svc.ObjectMeta.Annotations).To(HaveKey("thirdCrAnnotation")) 1206 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 1207 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("crAnnotation")) 1208 1209 Expect(svc.ObjectMeta.Labels).To(HaveKey("secondCrLabel")) 1210 Expect(svc.ObjectMeta.Labels).To(HaveKey("thirdCrLabel")) 1211 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 1212 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("crLabel")) 1213 }) 1214 1215 It("deletes a label and an annotation from CR", func() { 1216 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 1217 Expect(err).NotTo(HaveOccurred()) 1218 1219 orig := cr.DeepCopy() 1220 1221 delete(cr.Spec.ProxySQL.Expose.Annotations, "secondCrAnnotation") 1222 delete(cr.Spec.ProxySQL.Expose.Labels, "secondCrLabel") 1223 1224 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 1225 Expect(err).NotTo(HaveOccurred()) 1226 }) 1227 1228 It("should reconcile", func() { 1229 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1230 Expect(err).NotTo(HaveOccurred()) 1231 }) 1232 1233 It("should delete removed service label and annotation from service", func() { 1234 svc := corev1.Service{ 1235 ObjectMeta: metav1.ObjectMeta{ 1236 Name: crName + "-proxysql", 1237 Namespace: ns, 1238 }, 1239 } 1240 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1241 Expect(err).NotTo(HaveOccurred()) 1242 1243 Expect(svc.ObjectMeta.Annotations).To(HaveKey("thirdCrAnnotation")) 1244 Expect(svc.ObjectMeta.Annotations).To(HaveKey("ignoredAnnotation")) 1245 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("secondCrAnnotation")) 1246 1247 Expect(svc.ObjectMeta.Labels).To(HaveKey("thirdCrLabel")) 1248 Expect(svc.ObjectMeta.Labels).To(HaveKey("ignoredLabel")) 1249 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("secondCrLabel")) 1250 }) 1251 1252 It("deletes ignored labels and annotations from CR", func() { 1253 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(cr), cr) 1254 Expect(err).NotTo(HaveOccurred()) 1255 1256 orig := cr.DeepCopy() 1257 1258 cr.Spec.IgnoreAnnotations = []string{} 1259 cr.Spec.IgnoreLabels = []string{} 1260 1261 err = k8sClient.Patch(ctx, cr, client.MergeFrom(orig)) 1262 Expect(err).NotTo(HaveOccurred()) 1263 }) 1264 1265 It("should reconcile", func() { 1266 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1267 Expect(err).NotTo(HaveOccurred()) 1268 }) 1269 1270 It("should delete unknown labels and annotations from service", func() { 1271 svc := corev1.Service{ 1272 ObjectMeta: metav1.ObjectMeta{ 1273 Name: crName + "-proxysql", 1274 Namespace: ns, 1275 }, 1276 } 1277 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&svc), &svc) 1278 Expect(err).NotTo(HaveOccurred()) 1279 1280 Expect(svc.ObjectMeta.Annotations).To(HaveKey("thirdCrAnnotation")) 1281 Expect(svc.ObjectMeta.Annotations).ToNot(HaveKey("ignoredAnnotation")) 1282 1283 Expect(svc.ObjectMeta.Labels).To(HaveKey("thirdCrLabel")) 1284 Expect(svc.ObjectMeta.Labels).ToNot(HaveKey("ignoredLabel")) 1285 }) 1286 }) 1287 }) 1288 1289 var _ = Describe("PostStart/PreStop lifecycle hooks", Ordered, func() { 1290 ctx := context.Background() 1291 1292 const ns = "lifecycle" 1293 namespace := &corev1.Namespace{ 1294 ObjectMeta: metav1.ObjectMeta{ 1295 Name: ns, 1296 Namespace: ns, 1297 }, 1298 } 1299 1300 BeforeAll(func() { 1301 By("Creating the Namespace to perform the tests") 1302 err := k8sClient.Create(ctx, namespace) 1303 Expect(err).To(Not(HaveOccurred())) 1304 }) 1305 1306 AfterAll(func() { 1307 By("Deleting the Namespace to perform the tests") 1308 _ = k8sClient.Delete(ctx, namespace) 1309 }) 1310 1311 checkLifecycleHooks := func(crName, component string) { 1312 sts := appsv1.StatefulSet{ 1313 ObjectMeta: metav1.ObjectMeta{ 1314 Name: crName + "-" + component, 1315 Namespace: ns, 1316 }, 1317 } 1318 err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&sts), &sts) 1319 Expect(err).NotTo(HaveOccurred()) 1320 1321 for _, c := range sts.Spec.Template.Spec.Containers { 1322 if c.Name == component { 1323 Expect(c.Lifecycle.PostStart).ShouldNot(BeNil()) 1324 Expect(c.Lifecycle.PostStart.Exec).ShouldNot(BeNil()) 1325 Expect(c.Lifecycle.PostStart.Exec.Command).Should(Equal([]string{"echo", "poststart"})) 1326 1327 Expect(c.Lifecycle.PreStop).ShouldNot(BeNil()) 1328 Expect(c.Lifecycle.PreStop.Exec).ShouldNot(BeNil()) 1329 Expect(c.Lifecycle.PreStop.Exec.Command).Should(Equal([]string{"echo", "prestop"})) 1330 } 1331 } 1332 } 1333 1334 Context("Cluster is deployed with ProxySQL", Ordered, func() { 1335 const crName = "proxysql-lifecycle" 1336 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 1337 1338 cr, err := readDefaultCR(crName, ns) 1339 It("should read default cr.yaml", func() { 1340 Expect(err).NotTo(HaveOccurred()) 1341 }) 1342 1343 It("should create PerconaXtraDBCluster with PXC and ProxySQL container lifecycle hooks", func() { 1344 cr.Spec.HAProxy.Enabled = false 1345 cr.Spec.ProxySQL.Enabled = true 1346 1347 cr.Spec.PXC.Lifecycle = corev1.Lifecycle{ 1348 PostStart: &corev1.LifecycleHandler{ 1349 Exec: &corev1.ExecAction{ 1350 Command: []string{"echo", "poststart"}, 1351 }, 1352 }, 1353 PreStop: &corev1.LifecycleHandler{ 1354 Exec: &corev1.ExecAction{ 1355 Command: []string{"echo", "prestop"}, 1356 }, 1357 }, 1358 } 1359 1360 cr.Spec.ProxySQL.Lifecycle = corev1.Lifecycle{ 1361 PostStart: &corev1.LifecycleHandler{ 1362 Exec: &corev1.ExecAction{ 1363 Command: []string{"echo", "poststart"}, 1364 }, 1365 }, 1366 PreStop: &corev1.LifecycleHandler{ 1367 Exec: &corev1.ExecAction{ 1368 Command: []string{"echo", "prestop"}, 1369 }, 1370 }, 1371 } 1372 1373 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 1374 }) 1375 1376 It("should reconcile", func() { 1377 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1378 Expect(err).NotTo(HaveOccurred()) 1379 }) 1380 1381 It("pxc container should have poststart and prestop hooks set", func() { 1382 checkLifecycleHooks(crName, "pxc") 1383 }) 1384 1385 It("proxysql container should have poststart and prestop hooks set", func() { 1386 checkLifecycleHooks(crName, "proxysql") 1387 }) 1388 }) 1389 1390 Context("Cluster is deployed with HAProxy", Ordered, func() { 1391 const crName = "haproxy-lifecycle" 1392 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 1393 1394 cr, err := readDefaultCR(crName, ns) 1395 It("should read default cr.yaml", func() { 1396 Expect(err).NotTo(HaveOccurred()) 1397 }) 1398 1399 It("should create PerconaXtraDBCluster with HAProxy container lifecycle hooks", func() { 1400 cr.Spec.HAProxy.Enabled = true 1401 cr.Spec.ProxySQL.Enabled = false 1402 1403 cr.Spec.HAProxy.Lifecycle = corev1.Lifecycle{ 1404 PostStart: &corev1.LifecycleHandler{ 1405 Exec: &corev1.ExecAction{ 1406 Command: []string{"echo", "poststart"}, 1407 }, 1408 }, 1409 PreStop: &corev1.LifecycleHandler{ 1410 Exec: &corev1.ExecAction{ 1411 Command: []string{"echo", "prestop"}, 1412 }, 1413 }, 1414 } 1415 1416 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 1417 }) 1418 1419 It("should reconcile", func() { 1420 _, err := reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1421 Expect(err).NotTo(HaveOccurred()) 1422 }) 1423 1424 It("haproxy container should have poststart and prestop hooks set", func() { 1425 checkLifecycleHooks(crName, "haproxy") 1426 }) 1427 }) 1428 }) 1429 1430 var _ = Describe("Liveness/Readiness Probes", Ordered, func() { 1431 ctx := context.Background() 1432 1433 const ns = "probes" 1434 namespace := &corev1.Namespace{ 1435 ObjectMeta: metav1.ObjectMeta{ 1436 Name: ns, 1437 Namespace: ns, 1438 }, 1439 } 1440 1441 BeforeAll(func() { 1442 By("Creating the Namespace to perform the tests") 1443 err := k8sClient.Create(ctx, namespace) 1444 Expect(err).To(Not(HaveOccurred())) 1445 }) 1446 1447 AfterAll(func() { 1448 By("Deleting the Namespace to perform the tests") 1449 _ = k8sClient.Delete(ctx, namespace) 1450 }) 1451 1452 defaultReadiness := corev1.Probe{ 1453 ProbeHandler: corev1.ProbeHandler{ 1454 Exec: &corev1.ExecAction{ 1455 Command: []string{ 1456 "/var/lib/mysql/readiness-check.sh", 1457 }, 1458 }, 1459 }, 1460 InitialDelaySeconds: int32(15), 1461 TimeoutSeconds: int32(15), 1462 PeriodSeconds: int32(30), 1463 SuccessThreshold: int32(1), 1464 FailureThreshold: int32(5), 1465 } 1466 defaultLiveness := corev1.Probe{ 1467 ProbeHandler: corev1.ProbeHandler{ 1468 Exec: &corev1.ExecAction{ 1469 Command: []string{ 1470 "/var/lib/mysql/liveness-check.sh", 1471 }, 1472 }, 1473 }, 1474 InitialDelaySeconds: int32(300), 1475 TimeoutSeconds: int32(5), 1476 PeriodSeconds: int32(10), 1477 SuccessThreshold: int32(1), 1478 FailureThreshold: int32(3), 1479 } 1480 1481 DescribeTable("PXC probes", 1482 func(probes func() (corev1.Probe, corev1.Probe)) { 1483 const crName = "probes" 1484 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 1485 1486 cr, err := readDefaultCR(crName, ns) 1487 Expect(err).NotTo(HaveOccurred()) 1488 1489 cr.ObjectMeta.Finalizers = []string{} 1490 1491 readiness, liveness := probes() 1492 cr.Spec.PXC.ReadinessProbes = readiness 1493 cr.Spec.PXC.LivenessProbes = liveness 1494 1495 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 1496 1497 _, err = reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1498 Expect(err).NotTo(HaveOccurred()) 1499 1500 sts := appsv1.StatefulSet{} 1501 err = k8sClient.Get(ctx, types.NamespacedName{Name: "probes-pxc", Namespace: ns}, &sts) 1502 Expect(err).NotTo(HaveOccurred()) 1503 1504 for _, ct := range sts.Spec.Template.Spec.Containers { 1505 if ct.Name != "pxc" { 1506 continue 1507 } 1508 1509 Expect(*ct.ReadinessProbe).To(Equal(readiness)) 1510 Expect(*ct.LivenessProbe).To(Equal(liveness)) 1511 } 1512 1513 Expect(k8sClient.Delete(ctx, cr)).Should(Succeed()) 1514 }, 1515 Entry("[readiness] custom initial delay seconds", func() (corev1.Probe, corev1.Probe) { 1516 readiness := defaultReadiness.DeepCopy() 1517 readiness.InitialDelaySeconds = defaultReadiness.InitialDelaySeconds + 10 1518 1519 return *readiness, defaultLiveness 1520 }), 1521 Entry("[readiness] custom timeout seconds", func() (corev1.Probe, corev1.Probe) { 1522 readiness := defaultReadiness.DeepCopy() 1523 readiness.TimeoutSeconds = defaultReadiness.TimeoutSeconds + 10 1524 1525 return *readiness, defaultLiveness 1526 }), 1527 Entry("[readiness] custom period seconds", func() (corev1.Probe, corev1.Probe) { 1528 readiness := defaultReadiness.DeepCopy() 1529 readiness.PeriodSeconds = defaultReadiness.PeriodSeconds + 10 1530 1531 return *readiness, defaultLiveness 1532 }), 1533 Entry("[readiness] custom success threshold", func() (corev1.Probe, corev1.Probe) { 1534 readiness := defaultReadiness.DeepCopy() 1535 readiness.SuccessThreshold = defaultReadiness.SuccessThreshold + 1 1536 1537 return *readiness, defaultLiveness 1538 }), 1539 Entry("[readiness] custom failure threshold", func() (corev1.Probe, corev1.Probe) { 1540 readiness := defaultReadiness.DeepCopy() 1541 readiness.FailureThreshold = defaultReadiness.FailureThreshold + 1 1542 1543 return *readiness, defaultLiveness 1544 }), 1545 Entry("[liveness] custom initial delay seconds", func() (corev1.Probe, corev1.Probe) { 1546 liveness := defaultLiveness.DeepCopy() 1547 liveness.InitialDelaySeconds = defaultLiveness.InitialDelaySeconds + 10 1548 1549 return defaultReadiness, *liveness 1550 }), 1551 Entry("[liveness] custom timeout seconds", func() (corev1.Probe, corev1.Probe) { 1552 liveness := defaultLiveness.DeepCopy() 1553 liveness.TimeoutSeconds = defaultLiveness.TimeoutSeconds + 10 1554 1555 return defaultReadiness, *liveness 1556 }), 1557 Entry("[liveness] custom period seconds", func() (corev1.Probe, corev1.Probe) { 1558 liveness := defaultLiveness.DeepCopy() 1559 liveness.PeriodSeconds = defaultLiveness.PeriodSeconds + 10 1560 1561 return defaultReadiness, *liveness 1562 }), 1563 Entry("[liveness] custom success threshold", func() (corev1.Probe, corev1.Probe) { 1564 liveness := defaultLiveness.DeepCopy() 1565 liveness.SuccessThreshold = defaultLiveness.SuccessThreshold + 1 1566 1567 return defaultReadiness, *liveness 1568 }), 1569 Entry("[liveness] custom failure threshold", func() (corev1.Probe, corev1.Probe) { 1570 liveness := defaultLiveness.DeepCopy() 1571 liveness.FailureThreshold = defaultLiveness.FailureThreshold + 1 1572 1573 return defaultReadiness, *liveness 1574 }), 1575 ) 1576 1577 defaultHAProxyReadiness := corev1.Probe{ 1578 ProbeHandler: corev1.ProbeHandler{ 1579 Exec: &corev1.ExecAction{ 1580 Command: []string{ 1581 "/usr/local/bin/readiness-check.sh", 1582 }, 1583 }, 1584 }, 1585 InitialDelaySeconds: int32(15), 1586 TimeoutSeconds: int32(1), 1587 PeriodSeconds: int32(5), 1588 SuccessThreshold: int32(1), 1589 FailureThreshold: int32(3), 1590 } 1591 defaultHAProxyLiveness := corev1.Probe{ 1592 ProbeHandler: corev1.ProbeHandler{ 1593 Exec: &corev1.ExecAction{ 1594 Command: []string{ 1595 "/usr/local/bin/liveness-check.sh", 1596 }, 1597 }, 1598 }, 1599 InitialDelaySeconds: int32(60), 1600 TimeoutSeconds: int32(5), 1601 PeriodSeconds: int32(30), 1602 SuccessThreshold: int32(1), 1603 FailureThreshold: int32(4), 1604 } 1605 1606 DescribeTable("HAProxy probes", 1607 func(probes func() (corev1.Probe, corev1.Probe)) { 1608 const crName = "probes" 1609 crNamespacedName := types.NamespacedName{Name: crName, Namespace: ns} 1610 1611 cr, err := readDefaultCR(crName, ns) 1612 Expect(err).NotTo(HaveOccurred()) 1613 1614 cr.ObjectMeta.Finalizers = []string{} 1615 cr.Spec.HAProxy.Enabled = true 1616 cr.Spec.ProxySQL.Enabled = false 1617 1618 readiness, liveness := probes() 1619 cr.Spec.HAProxy.ReadinessProbes = readiness 1620 cr.Spec.HAProxy.LivenessProbes = liveness 1621 1622 Expect(k8sClient.Create(ctx, cr)).Should(Succeed()) 1623 1624 _, err = reconciler().Reconcile(ctx, ctrl.Request{NamespacedName: crNamespacedName}) 1625 Expect(err).NotTo(HaveOccurred()) 1626 1627 sts := appsv1.StatefulSet{} 1628 err = k8sClient.Get(ctx, types.NamespacedName{Name: "probes-haproxy", Namespace: ns}, &sts) 1629 Expect(err).NotTo(HaveOccurred()) 1630 1631 for _, ct := range sts.Spec.Template.Spec.Containers { 1632 if ct.Name != "haproxy" { 1633 continue 1634 } 1635 1636 Expect(*ct.ReadinessProbe).To(Equal(readiness)) 1637 Expect(*ct.LivenessProbe).To(Equal(liveness)) 1638 } 1639 1640 Expect(k8sClient.Delete(ctx, cr)).Should(Succeed()) 1641 }, 1642 Entry("[readiness] custom initial delay seconds", func() (corev1.Probe, corev1.Probe) { 1643 readiness := defaultHAProxyReadiness.DeepCopy() 1644 readiness.InitialDelaySeconds = defaultHAProxyReadiness.InitialDelaySeconds + 10 1645 1646 return *readiness, defaultHAProxyLiveness 1647 }), 1648 Entry("[readiness] custom timeout seconds", func() (corev1.Probe, corev1.Probe) { 1649 readiness := defaultHAProxyReadiness.DeepCopy() 1650 readiness.TimeoutSeconds = defaultHAProxyReadiness.TimeoutSeconds + 10 1651 1652 return *readiness, defaultHAProxyLiveness 1653 }), 1654 Entry("[readiness] custom period seconds", func() (corev1.Probe, corev1.Probe) { 1655 readiness := defaultHAProxyReadiness.DeepCopy() 1656 readiness.PeriodSeconds = defaultHAProxyReadiness.PeriodSeconds + 10 1657 1658 return *readiness, defaultHAProxyLiveness 1659 }), 1660 Entry("[readiness] custom success threshold", func() (corev1.Probe, corev1.Probe) { 1661 readiness := defaultHAProxyReadiness.DeepCopy() 1662 readiness.SuccessThreshold = defaultHAProxyReadiness.SuccessThreshold + 1 1663 1664 return *readiness, defaultHAProxyLiveness 1665 }), 1666 Entry("[readiness] custom failure threshold", func() (corev1.Probe, corev1.Probe) { 1667 readiness := defaultHAProxyReadiness.DeepCopy() 1668 readiness.FailureThreshold = defaultHAProxyReadiness.FailureThreshold + 1 1669 1670 return *readiness, defaultHAProxyLiveness 1671 }), 1672 Entry("[liveness] custom initial delay seconds", func() (corev1.Probe, corev1.Probe) { 1673 liveness := defaultHAProxyLiveness.DeepCopy() 1674 liveness.InitialDelaySeconds = defaultHAProxyLiveness.InitialDelaySeconds + 10 1675 1676 return defaultHAProxyReadiness, *liveness 1677 }), 1678 Entry("[liveness] custom timeout seconds", func() (corev1.Probe, corev1.Probe) { 1679 liveness := defaultHAProxyLiveness.DeepCopy() 1680 liveness.TimeoutSeconds = defaultHAProxyLiveness.TimeoutSeconds + 10 1681 1682 return defaultHAProxyReadiness, *liveness 1683 }), 1684 Entry("[liveness] custom period seconds", func() (corev1.Probe, corev1.Probe) { 1685 liveness := defaultHAProxyLiveness.DeepCopy() 1686 liveness.PeriodSeconds = defaultHAProxyLiveness.PeriodSeconds + 10 1687 1688 return defaultHAProxyReadiness, *liveness 1689 }), 1690 Entry("[liveness] custom success threshold", func() (corev1.Probe, corev1.Probe) { 1691 liveness := defaultHAProxyLiveness.DeepCopy() 1692 liveness.SuccessThreshold = defaultHAProxyLiveness.SuccessThreshold + 1 1693 1694 return defaultHAProxyReadiness, *liveness 1695 }), 1696 Entry("[liveness] custom failure threshold", func() (corev1.Probe, corev1.Probe) { 1697 liveness := defaultHAProxyLiveness.DeepCopy() 1698 liveness.FailureThreshold = defaultHAProxyLiveness.FailureThreshold + 1 1699 1700 return defaultHAProxyReadiness, *liveness 1701 }), 1702 ) 1703 })