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  })