mirror of
https://github.com/mariadb-operator/mariadb-operator.git
synced 2025-07-31 21:08:45 +00:00
853 lines
28 KiB
Go
853 lines
28 KiB
Go
package controller
|
|
|
|
import (
|
|
"os"
|
|
"time"
|
|
|
|
mariadbv1alpha1 "github.com/mariadb-operator/mariadb-operator/v25/api/v1alpha1"
|
|
"github.com/mariadb-operator/mariadb-operator/v25/pkg/metadata"
|
|
stsobj "github.com/mariadb-operator/mariadb-operator/v25/pkg/statefulset"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
. "github.com/onsi/gomega/gstruct"
|
|
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
"k8s.io/utils/ptr"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
var _ = Describe("MariaDB spec", Label("basic"), func() {
|
|
It("should default", func() {
|
|
By("Creating MariaDB")
|
|
key := types.NamespacedName{
|
|
Name: "test-mariadb-default",
|
|
Namespace: testNamespace,
|
|
}
|
|
mdb := mariadbv1alpha1.MariaDB{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
},
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
Storage: mariadbv1alpha1.Storage{
|
|
Size: ptr.To(resource.MustParse("300Mi")),
|
|
},
|
|
},
|
|
}
|
|
Expect(k8sClient.Create(testCtx, &mdb)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
deleteMariadb(key, false)
|
|
})
|
|
|
|
By("Expecting to eventually default")
|
|
Eventually(func() bool {
|
|
if err := k8sClient.Get(testCtx, key, &mdb); err != nil {
|
|
return false
|
|
}
|
|
return mdb.Spec.Image != "" && mdb.Spec.TLS != nil && mdb.Spec.TLS.Enabled
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
})
|
|
|
|
DescribeTable("should render default config",
|
|
func(mariadb *mariadbv1alpha1.MariaDB, expectedConfig string) {
|
|
config, err := defaultConfig(mariadb)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(config).To(BeEquivalentTo(expectedConfig))
|
|
},
|
|
Entry(
|
|
"no timezone",
|
|
&mariadbv1alpha1.MariaDB{},
|
|
`[mariadb]
|
|
skip-name-resolve
|
|
temp-pool
|
|
ignore_db_dirs = 'lost+found'
|
|
`,
|
|
),
|
|
Entry(
|
|
"timezone",
|
|
&mariadbv1alpha1.MariaDB{
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
TimeZone: ptr.To("UTC"),
|
|
},
|
|
},
|
|
`[mariadb]
|
|
skip-name-resolve
|
|
temp-pool
|
|
ignore_db_dirs = 'lost+found'
|
|
default_time_zone = UTC
|
|
`,
|
|
),
|
|
)
|
|
})
|
|
|
|
var _ = Describe("MariaDB", Label("basic"), func() {
|
|
BeforeEach(func() {
|
|
By("Waiting for MariaDB to be ready")
|
|
expectMariadbReady(testCtx, k8sClient, testMdbkey)
|
|
})
|
|
|
|
It("should suspend", func() {
|
|
By("Creating MariaDB")
|
|
key := types.NamespacedName{
|
|
Name: "test-mariadb-suspend",
|
|
Namespace: testNamespace,
|
|
}
|
|
mdb := mariadbv1alpha1.MariaDB{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
},
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
Storage: mariadbv1alpha1.Storage{
|
|
Size: ptr.To(resource.MustParse("300Mi")),
|
|
},
|
|
},
|
|
}
|
|
Expect(k8sClient.Create(testCtx, &mdb)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
deleteMariadb(key, false)
|
|
})
|
|
|
|
By("Suspend MariaDB")
|
|
Eventually(func() bool {
|
|
if err := k8sClient.Get(testCtx, key, &mdb); err != nil {
|
|
return false
|
|
}
|
|
mdb.Spec.Suspend = true
|
|
|
|
return k8sClient.Update(testCtx, &mdb) == nil
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting MariaDB to eventually be suspended")
|
|
expectMariadbFn(testCtx, k8sClient, key, func(mdb *mariadbv1alpha1.MariaDB) bool {
|
|
condition := meta.FindStatusCondition(mdb.Status.Conditions, mariadbv1alpha1.ConditionTypeReady)
|
|
if condition == nil {
|
|
return false
|
|
}
|
|
return condition.Status == metav1.ConditionFalse && condition.Reason == mariadbv1alpha1.ConditionReasonSuspended
|
|
})
|
|
})
|
|
|
|
It("should reconcile", func() {
|
|
var testMariaDb mariadbv1alpha1.MariaDB
|
|
By("Getting MariaDB")
|
|
Expect(k8sClient.Get(testCtx, testMdbkey, &testMariaDb)).To(Succeed())
|
|
|
|
By("Expecting to create a ServiceAccount eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var svcAcc corev1.ServiceAccount
|
|
key := testMariaDb.Spec.PodTemplate.ServiceAccountKey(testMariaDb.ObjectMeta)
|
|
g.Expect(k8sClient.Get(testCtx, key, &svcAcc)).To(Succeed())
|
|
|
|
g.Expect(svcAcc.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(svcAcc.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(svcAcc.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(svcAcc.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting to create a default ConfigMap eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var cm corev1.ConfigMap
|
|
key := types.NamespacedName{
|
|
Name: testMariaDb.DefaultConfigMapKeyRef().Name,
|
|
Namespace: testMariaDb.Namespace,
|
|
}
|
|
if err := k8sClient.Get(testCtx, key, &cm); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(cm.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(cm.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(cm.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(cm.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(cm.Data).To(HaveKeyWithValue("0-default.cnf", "[mariadb]\nskip-name-resolve\ntemp-pool\nignore_db_dirs = 'lost+found'\n"))
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting to create a ConfigMap eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
if testMariaDb.Spec.MyCnfConfigMapKeyRef == nil {
|
|
return false
|
|
}
|
|
var cm corev1.ConfigMap
|
|
key := types.NamespacedName{
|
|
Name: testMariaDb.Spec.MyCnfConfigMapKeyRef.Name,
|
|
Namespace: testMariaDb.Namespace,
|
|
}
|
|
if err := k8sClient.Get(testCtx, key, &cm); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(cm.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(cm.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(cm.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(cm.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting to create a StatefulSet eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var sts appsv1.StatefulSet
|
|
if err := k8sClient.Get(testCtx, testMdbkey, &sts); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(sts.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(sts.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(sts.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(sts.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting Pod to have metadata")
|
|
Eventually(func(g Gomega) bool {
|
|
key := types.NamespacedName{
|
|
Name: stsobj.PodName(testMariaDb.ObjectMeta, 0),
|
|
Namespace: testMariaDb.Namespace,
|
|
}
|
|
var pod corev1.Pod
|
|
if err := k8sClient.Get(testCtx, key, &pod); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(pod.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(pod.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(pod.ObjectMeta.Labels).To(HaveKeyWithValue("sidecar.istio.io/inject", "false"))
|
|
g.Expect(pod.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(pod.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return true
|
|
}).WithTimeout(testTimeout).WithPolling(testInterval).Should(BeTrue())
|
|
|
|
By("Expecting to create a Service eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var svc corev1.Service
|
|
if err := k8sClient.Get(testCtx, testMdbkey, &svc); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(svc.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(svc.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(svc.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(svc.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting Connection to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var conn mariadbv1alpha1.Connection
|
|
if err := k8sClient.Get(testCtx, client.ObjectKeyFromObject(&testMariaDb), &conn); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(conn.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(conn.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(conn.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(conn.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return conn.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting to create a exporter Deployment eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var deploy appsv1.Deployment
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MetricsKey(), &deploy); err != nil {
|
|
return false
|
|
}
|
|
expectedImage := os.Getenv("RELATED_IMAGE_EXPORTER")
|
|
g.Expect(expectedImage).ToNot(BeEmpty())
|
|
By("Expecting Deployment to have exporter image")
|
|
g.Expect(deploy.Spec.Template.Spec.Containers).To(ContainElement(MatchFields(IgnoreExtras,
|
|
Fields{
|
|
"Image": Equal(expectedImage),
|
|
})))
|
|
|
|
g.Expect(deploy.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(deploy.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(deploy.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(deploy.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return deploymentReady(&deploy)
|
|
}).WithTimeout(testTimeout).WithPolling(testInterval).Should(BeTrue())
|
|
|
|
By("Expecting to create a ServiceMonitor eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var svcMonitor monitoringv1.ServiceMonitor
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MetricsKey(), &svcMonitor); err != nil {
|
|
return false
|
|
}
|
|
|
|
g.Expect(svcMonitor.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(svcMonitor.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(svcMonitor.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(svcMonitor.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
|
|
g.Expect(svcMonitor.Spec.Selector.MatchLabels).NotTo(BeEmpty())
|
|
g.Expect(svcMonitor.Spec.Selector.MatchLabels).To(HaveKeyWithValue("app.kubernetes.io/name", "exporter"))
|
|
g.Expect(svcMonitor.Spec.Selector.MatchLabels).To(HaveKeyWithValue("app.kubernetes.io/instance", testMariaDb.MetricsKey().Name))
|
|
g.Expect(svcMonitor.Spec.Endpoints).To(HaveLen(1))
|
|
return true
|
|
}).WithTimeout(testTimeout).WithPolling(testInterval).Should(BeTrue())
|
|
})
|
|
|
|
It("should reconcile SQL", func() {
|
|
var testMariaDb mariadbv1alpha1.MariaDB
|
|
By("Getting MariaDB")
|
|
Expect(k8sClient.Get(testCtx, testMdbkey, &testMariaDb)).To(Succeed())
|
|
|
|
By("Expecting initial Database to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var database mariadbv1alpha1.Database
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MariadbDatabaseKey(), &database); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(database.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(database.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(database.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(database.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return database.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting initial User to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var user mariadbv1alpha1.User
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MariadbUserKey(), &user); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(user.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(user.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(user.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(user.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return user.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting initial Grant to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var grant mariadbv1alpha1.Grant
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MariadbGrantKey(), &grant); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(grant.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(grant.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(grant.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(grant.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return grant.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting mariadb.sys User to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var user mariadbv1alpha1.User
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MariadbSysUserKey(), &user); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(user.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(user.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(user.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(user.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return user.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting mariadb.sys Grant to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var grant mariadbv1alpha1.Grant
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MariadbSysGrantKey(), &grant); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(grant.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(grant.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(grant.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(grant.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return grant.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting metrics User to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var user mariadbv1alpha1.User
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MetricsKey(), &user); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(user.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(user.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(user.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(user.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return user.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting metrics Grant to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
var grant mariadbv1alpha1.Grant
|
|
if err := k8sClient.Get(testCtx, testMariaDb.MetricsKey(), &grant); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(grant.ObjectMeta.Labels).NotTo(BeNil())
|
|
g.Expect(grant.ObjectMeta.Labels).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
g.Expect(grant.ObjectMeta.Annotations).NotTo(BeNil())
|
|
g.Expect(grant.ObjectMeta.Annotations).To(HaveKeyWithValue("k8s.mariadb.com/test", "test"))
|
|
return grant.IsReady()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
})
|
|
|
|
It("should reconcile with generated passwords", func() {
|
|
key := types.NamespacedName{
|
|
Name: "mariadb-generate",
|
|
Namespace: testNamespace,
|
|
}
|
|
rootPasswordKey := types.NamespacedName{
|
|
Name: "mariadb-root-generate",
|
|
Namespace: testNamespace,
|
|
}
|
|
|
|
mdb := mariadbv1alpha1.MariaDB{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
},
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
RootPasswordSecretKeyRef: mariadbv1alpha1.GeneratedSecretKeyRef{
|
|
SecretKeySelector: mariadbv1alpha1.SecretKeySelector{
|
|
LocalObjectReference: mariadbv1alpha1.LocalObjectReference{
|
|
Name: rootPasswordKey.Name,
|
|
},
|
|
Key: testPwdSecretKey,
|
|
},
|
|
Generate: true,
|
|
},
|
|
Username: ptr.To("user"),
|
|
PasswordSecretKeyRef: &mariadbv1alpha1.GeneratedSecretKeyRef{
|
|
SecretKeySelector: mariadbv1alpha1.SecretKeySelector{
|
|
LocalObjectReference: mariadbv1alpha1.LocalObjectReference{
|
|
Name: testPwdKey.Name,
|
|
},
|
|
Key: testPwdSecretKey,
|
|
},
|
|
Generate: true,
|
|
},
|
|
Storage: mariadbv1alpha1.Storage{
|
|
Size: ptr.To(resource.MustParse("300Mi")),
|
|
},
|
|
},
|
|
}
|
|
applyMariadbTestConfig(&mdb)
|
|
|
|
By("Creating MariaDB")
|
|
Expect(k8sClient.Create(testCtx, &mdb)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
deleteMariadb(key, false)
|
|
})
|
|
|
|
By("Expecting MariaDB to be ready eventually")
|
|
expectMariadbReady(testCtx, k8sClient, key)
|
|
|
|
By("Expecting to create a root Secret eventually")
|
|
expectSecretToExist(testCtx, k8sClient, rootPasswordKey, testPwdSecretKey)
|
|
|
|
By("Expecting to create a password Secret eventually")
|
|
expectSecretToExist(testCtx, k8sClient, testPwdKey, testPwdSecretKey)
|
|
})
|
|
|
|
It("should get an update when my.cnf is updated", func() {
|
|
By("Creating MariaDB")
|
|
key := types.NamespacedName{
|
|
Name: "test-mariadb-mycnf",
|
|
Namespace: testNamespace,
|
|
}
|
|
mdb := mariadbv1alpha1.MariaDB{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
},
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
Storage: mariadbv1alpha1.Storage{
|
|
Size: ptr.To(resource.MustParse("300Mi")),
|
|
},
|
|
UpdateStrategy: mariadbv1alpha1.UpdateStrategy{
|
|
Type: mariadbv1alpha1.OnDeleteUpdateType,
|
|
},
|
|
MyCnf: ptr.To(`[mariadb]
|
|
bind-address=*
|
|
default_storage_engine=InnoDB
|
|
binlog_format=row
|
|
innodb_autoinc_lock_mode=2
|
|
innodb_buffer_pool_size=1024M
|
|
max_allowed_packet=256M
|
|
`),
|
|
TLS: &mariadbv1alpha1.TLS{
|
|
Enabled: true,
|
|
Required: ptr.To(true),
|
|
},
|
|
},
|
|
}
|
|
applyMariadbTestConfig(&mdb)
|
|
|
|
By("Creating MariaDB")
|
|
Expect(k8sClient.Create(testCtx, &mdb)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
deleteMariadb(key, false)
|
|
})
|
|
|
|
By("Expecting MariaDB to be ready eventually")
|
|
expectMariadbReady(testCtx, k8sClient, key)
|
|
|
|
By("Updating innodb_buffer_pool_size in my.cnf")
|
|
Eventually(func(g Gomega) bool {
|
|
g.Expect(k8sClient.Get(testCtx, key, &mdb)).To(Succeed())
|
|
mdb.Spec.MyCnf = ptr.To(`[mariadb]
|
|
bind-address=*
|
|
default_storage_engine=InnoDB
|
|
binlog_format=row
|
|
innodb_autoinc_lock_mode=2
|
|
innodb_buffer_pool_size=2048M
|
|
max_allowed_packet=256M
|
|
`)
|
|
g.Expect(k8sClient.Update(testCtx, &mdb)).To(Succeed())
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting MariaDB to have a pending update eventually")
|
|
expectMariadbFn(testCtx, k8sClient, key, func(mdb *mariadbv1alpha1.MariaDB) bool {
|
|
return mdb.HasPendingUpdate()
|
|
})
|
|
})
|
|
|
|
It("should get an update when my.cnf ConfigMap is updated", func() {
|
|
key := types.NamespacedName{
|
|
Name: "test-mariadb-mycnf-configmap",
|
|
Namespace: testNamespace,
|
|
}
|
|
|
|
By("Creating ConfigMap")
|
|
configMapKey := "my.cnf"
|
|
configMap := corev1.ConfigMap{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
Labels: map[string]string{
|
|
metadata.WatchLabel: "",
|
|
},
|
|
},
|
|
Data: map[string]string{
|
|
configMapKey: `[mariadb]
|
|
bind-address=*
|
|
default_storage_engine=InnoDB
|
|
binlog_format=row
|
|
innodb_autoinc_lock_mode=2
|
|
innodb_buffer_pool_size=1024M
|
|
max_allowed_packet=256M
|
|
`,
|
|
},
|
|
}
|
|
Expect(k8sClient.Create(testCtx, &configMap)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
Expect(k8sClient.Delete(testCtx, &configMap)).To(Succeed())
|
|
})
|
|
|
|
By("Creating MariaDB")
|
|
mdb := mariadbv1alpha1.MariaDB{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
},
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
Storage: mariadbv1alpha1.Storage{
|
|
Size: ptr.To(resource.MustParse("300Mi")),
|
|
},
|
|
UpdateStrategy: mariadbv1alpha1.UpdateStrategy{
|
|
Type: mariadbv1alpha1.OnDeleteUpdateType,
|
|
},
|
|
MyCnfConfigMapKeyRef: &mariadbv1alpha1.ConfigMapKeySelector{
|
|
LocalObjectReference: mariadbv1alpha1.LocalObjectReference{
|
|
Name: configMap.Name,
|
|
},
|
|
Key: configMapKey,
|
|
},
|
|
TLS: &mariadbv1alpha1.TLS{
|
|
Enabled: true,
|
|
Required: ptr.To(true),
|
|
},
|
|
},
|
|
}
|
|
applyMariadbTestConfig(&mdb)
|
|
|
|
By("Creating MariaDB")
|
|
Expect(k8sClient.Create(testCtx, &mdb)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
deleteMariadb(key, false)
|
|
})
|
|
|
|
By("Expecting MariaDB to be ready eventually")
|
|
expectMariadbReady(testCtx, k8sClient, key)
|
|
|
|
By("Updating innodb_buffer_pool_size in my.cnf ConfigMap")
|
|
Eventually(func(g Gomega) bool {
|
|
g.Expect(k8sClient.Get(testCtx, key, &configMap)).To(Succeed())
|
|
configMap.Data[configMapKey] = `[mariadb]
|
|
bind-address=*
|
|
default_storage_engine=InnoDB
|
|
binlog_format=row
|
|
innodb_autoinc_lock_mode=2
|
|
innodb_buffer_pool_size=2048M
|
|
max_allowed_packet=256M
|
|
`
|
|
g.Expect(k8sClient.Update(testCtx, &configMap)).To(Succeed())
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting MariaDB to have a pending update eventually")
|
|
expectMariadbFn(testCtx, k8sClient, key, func(mdb *mariadbv1alpha1.MariaDB) bool {
|
|
return mdb.HasPendingUpdate()
|
|
})
|
|
})
|
|
|
|
It("should update metrics password", func() {
|
|
var mdb mariadbv1alpha1.MariaDB
|
|
By("Getting MariaDB")
|
|
Expect(k8sClient.Get(testCtx, testMdbkey, &mdb)).To(Succeed())
|
|
|
|
var deploy appsv1.Deployment
|
|
By("Expecting exporter Deployment to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
if err := k8sClient.Get(testCtx, mdb.MetricsKey(), &deploy); err != nil {
|
|
return false
|
|
}
|
|
return deploymentReady(&deploy)
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Getting config hash")
|
|
configHash := deploy.Spec.Template.Annotations[metadata.ConfigAnnotation]
|
|
|
|
By("Updating password Secret")
|
|
Eventually(func(g Gomega) bool {
|
|
var secret corev1.Secret
|
|
g.Expect(k8sClient.Get(testCtx, testPwdKey, &secret)).To(Succeed())
|
|
secret.Data[testPwdMetricsSecretKey] = []byte("MariaDB12!")
|
|
g.Expect(k8sClient.Update(testCtx, &secret)).To(Succeed())
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting config hash to be updated")
|
|
Eventually(func(g Gomega) bool {
|
|
if err := k8sClient.Get(testCtx, mdb.MetricsKey(), &deploy); err != nil {
|
|
return false
|
|
}
|
|
g.Expect(deploy.Spec.Template.Annotations[metadata.ConfigAnnotation]).NotTo(Equal(configHash))
|
|
return true
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting exporter Deployment to be ready eventually")
|
|
Eventually(func(g Gomega) bool {
|
|
if err := k8sClient.Get(testCtx, mdb.MetricsKey(), &deploy); err != nil {
|
|
return false
|
|
}
|
|
return deploymentReady(&deploy)
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
})
|
|
|
|
DescribeTable("should bootstrap from logical backup",
|
|
func(backup *mariadbv1alpha1.Backup, bootstrapFrom mariadbv1alpha1.BootstrapFrom,
|
|
mariadbKey types.NamespacedName) {
|
|
backupKey := client.ObjectKeyFromObject(backup)
|
|
|
|
By("Creating Backup")
|
|
Expect(k8sClient.Create(testCtx, backup)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
Expect(k8sClient.Delete(testCtx, backup)).To(Succeed())
|
|
})
|
|
|
|
By("Expecting Backup to complete eventually")
|
|
Eventually(func() bool {
|
|
if err := k8sClient.Get(testCtx, backupKey, backup); err != nil {
|
|
return false
|
|
}
|
|
return backup.IsComplete()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Bootstrapping MariaDB from Backup")
|
|
testMariadbBootstrap(mariadbKey, &bootstrapFrom)
|
|
},
|
|
Entry(
|
|
"Backup",
|
|
getBackupWithS3Storage(
|
|
types.NamespacedName{
|
|
Name: "test-backup",
|
|
Namespace: testNamespace,
|
|
},
|
|
"test-mariadb",
|
|
"",
|
|
),
|
|
newBootstrapFromRestoreSource(mariadbv1alpha1.RestoreSource{
|
|
BackupRef: &mariadbv1alpha1.LocalObjectReference{
|
|
Name: "test-backup",
|
|
},
|
|
TargetRecoveryTime: &metav1.Time{Time: time.Now()},
|
|
}),
|
|
types.NamespacedName{
|
|
Name: "test-mariadb-from-backup",
|
|
Namespace: testNamespace,
|
|
},
|
|
),
|
|
Entry(
|
|
"Backup S3",
|
|
getBackupWithS3Storage(
|
|
types.NamespacedName{
|
|
Name: "test-backup-from-s3",
|
|
Namespace: testNamespace,
|
|
},
|
|
"test-mariadb",
|
|
"",
|
|
),
|
|
newBootstrapFromRestoreSource(mariadbv1alpha1.RestoreSource{
|
|
S3: getS3WithBucket("test-mariadb", ""),
|
|
StagingStorage: &mariadbv1alpha1.BackupStagingStorage{
|
|
PersistentVolumeClaim: &mariadbv1alpha1.PersistentVolumeClaimSpec{
|
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
|
corev1.ReadWriteOnce,
|
|
},
|
|
Resources: corev1.VolumeResourceRequirements{
|
|
Requests: corev1.ResourceList{
|
|
"storage": resource.MustParse("500Mi"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
TargetRecoveryTime: &metav1.Time{Time: time.Now()},
|
|
}),
|
|
types.NamespacedName{
|
|
Name: "test-mariadb-from-s3",
|
|
Namespace: testNamespace,
|
|
},
|
|
),
|
|
)
|
|
|
|
DescribeTable("should bootstrap from physical backup",
|
|
func(backup *mariadbv1alpha1.PhysicalBackup, bootstrapFrom mariadbv1alpha1.BootstrapFrom,
|
|
mariadbKey types.NamespacedName) {
|
|
backupKey := client.ObjectKeyFromObject(backup)
|
|
|
|
By("Creating PhysicalBackup")
|
|
Expect(k8sClient.Create(testCtx, backup)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
Expect(k8sClient.Delete(testCtx, backup)).To(Succeed())
|
|
})
|
|
|
|
By("Expecting PhysicalBackup to complete eventually")
|
|
Eventually(func() bool {
|
|
if err := k8sClient.Get(testCtx, backupKey, backup); err != nil {
|
|
return false
|
|
}
|
|
return backup.IsComplete()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Bootstrapping MariaDB from PhysicalBackup")
|
|
testMariadbBootstrap(mariadbKey, &bootstrapFrom)
|
|
},
|
|
Entry(
|
|
"PhysicalBackup",
|
|
buildPhysicalBackupWithS3Storage(
|
|
testMdbkey,
|
|
"test-mariadb-physical",
|
|
"",
|
|
)(
|
|
types.NamespacedName{
|
|
Name: "test-physicalbackup",
|
|
Namespace: testNamespace,
|
|
},
|
|
),
|
|
mariadbv1alpha1.BootstrapFrom{
|
|
BackupRef: &mariadbv1alpha1.TypedLocalObjectReference{
|
|
Name: "test-physicalbackup",
|
|
Kind: mariadbv1alpha1.PhysicalBackupKind,
|
|
},
|
|
TargetRecoveryTime: &metav1.Time{Time: time.Now()},
|
|
},
|
|
types.NamespacedName{
|
|
Name: "test-mariadb-from-physicalbackup",
|
|
Namespace: testNamespace,
|
|
},
|
|
),
|
|
Entry(
|
|
"PhysicalBackup VolumeSnapshot",
|
|
buildPhysicalBackupWithVolumeSnapshotStorage(testMdbkey)(
|
|
types.NamespacedName{
|
|
Name: "test-physicalbackup-volumesnapshot",
|
|
Namespace: testNamespace,
|
|
},
|
|
),
|
|
mariadbv1alpha1.BootstrapFrom{
|
|
BackupRef: &mariadbv1alpha1.TypedLocalObjectReference{
|
|
Name: "test-physicalbackup-volumesnapshot",
|
|
Kind: mariadbv1alpha1.PhysicalBackupKind,
|
|
},
|
|
TargetRecoveryTime: &metav1.Time{Time: time.Now()},
|
|
},
|
|
types.NamespacedName{
|
|
Name: "test-mariadb-from-physicalbackup-volumesnapshot",
|
|
Namespace: testNamespace,
|
|
},
|
|
),
|
|
)
|
|
})
|
|
|
|
func testMariadbBootstrap(key types.NamespacedName, bootstrapFrom *mariadbv1alpha1.BootstrapFrom) {
|
|
mdb := mariadbv1alpha1.MariaDB{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: key.Name,
|
|
Namespace: key.Namespace,
|
|
},
|
|
Spec: mariadbv1alpha1.MariaDBSpec{
|
|
RootPasswordSecretKeyRef: mariadbv1alpha1.GeneratedSecretKeyRef{
|
|
SecretKeySelector: mariadbv1alpha1.SecretKeySelector{
|
|
LocalObjectReference: mariadbv1alpha1.LocalObjectReference{
|
|
Name: testPwdKey.Name,
|
|
},
|
|
Key: testPwdSecretKey,
|
|
},
|
|
},
|
|
BootstrapFrom: bootstrapFrom,
|
|
Storage: mariadbv1alpha1.Storage{
|
|
Size: ptr.To(resource.MustParse("100Mi")),
|
|
},
|
|
TLS: &mariadbv1alpha1.TLS{
|
|
Enabled: true,
|
|
Required: ptr.To(true),
|
|
},
|
|
},
|
|
}
|
|
applyMariadbTestConfig(&mdb)
|
|
|
|
By("Creating MariaDB")
|
|
Expect(k8sClient.Create(testCtx, &mdb)).To(Succeed())
|
|
DeferCleanup(func() {
|
|
deleteMariadb(key, false)
|
|
})
|
|
|
|
By("Expecting MariaDB to be ready eventually")
|
|
Eventually(func() bool {
|
|
if err := k8sClient.Get(testCtx, key, &mdb); err != nil {
|
|
return false
|
|
}
|
|
return mdb.IsReady()
|
|
}, testHighTimeout, testInterval).Should(BeTrue())
|
|
|
|
By("Expecting MariaDB to eventually have restored backup")
|
|
Eventually(func() bool {
|
|
if err := k8sClient.Get(testCtx, key, &mdb); err != nil {
|
|
return false
|
|
}
|
|
return mdb.HasRestoredBackup()
|
|
}, testTimeout, testInterval).Should(BeTrue())
|
|
}
|
|
|
|
func newBootstrapFromRestoreSource(source mariadbv1alpha1.RestoreSource) mariadbv1alpha1.BootstrapFrom {
|
|
var typedBackupRef *mariadbv1alpha1.TypedLocalObjectReference
|
|
if source.BackupRef != nil {
|
|
typedBackupRef = &mariadbv1alpha1.TypedLocalObjectReference{
|
|
Name: source.BackupRef.Name,
|
|
Kind: mariadbv1alpha1.BackupKind,
|
|
}
|
|
}
|
|
return mariadbv1alpha1.BootstrapFrom{
|
|
BackupRef: typedBackupRef,
|
|
S3: source.S3,
|
|
Volume: source.Volume,
|
|
TargetRecoveryTime: source.TargetRecoveryTime,
|
|
StagingStorage: source.StagingStorage,
|
|
}
|
|
}
|