Files
mariadb-operator/api/v1alpha1/maxscale_webhook_test.go
2024-08-23 16:40:18 +02:00

572 lines
12 KiB
Go

package v1alpha1
import (
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var _ = Describe("MaxScale webhook", func() {
Context("When creating a MaxScale", func() {
meta := metav1.ObjectMeta{
Name: "maxscale-create-webhook",
Namespace: testNamespace,
}
DescribeTable(
"Should validate",
func(mxs *MaxScale, wantErr bool) {
_ = k8sClient.Delete(testCtx, mxs)
err := k8sClient.Create(testCtx, mxs)
if wantErr {
Expect(err).To(HaveOccurred())
} else {
Expect(err).ToNot(HaveOccurred())
}
},
Entry(
"Invalid server names",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
{
Name: "mariadb-0",
Address: "mariadb-repl-1.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
},
},
true,
),
Entry(
"Invalid server addresses",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
{
Name: "mariadb-1",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
},
},
true,
),
Entry(
"No server sources",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
},
},
true,
),
Entry(
"Multiple server sources",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
MariaDBRef: &MariaDBRef{
ObjectReference: corev1.ObjectReference{
Name: "mariadb",
},
},
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
},
},
true,
),
Entry(
"No monitor",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
},
},
true,
),
Entry(
"Invalid monitor",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
MariaDBRef: &MariaDBRef{
ObjectReference: corev1.ObjectReference{
Name: "mariadb",
},
},
Monitor: MaxScaleMonitor{
Module: "foo",
},
},
},
true,
),
Entry(
"Invalid service names",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
{
Name: "rw-router",
Router: ServiceRouterReadConnRoute,
Listener: MaxScaleListener{
Port: 3307,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
},
},
true,
),
Entry(
"Invalid service ports",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
{
Name: "conn-router",
Router: ServiceRouterReadConnRoute,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
},
},
true,
),
Entry(
"Invalid auth generate",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
Auth: MaxScaleAuth{
Generate: ptr.To(true),
},
},
},
true,
),
Entry(
"Invalid PodDisruptionBudget",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
PodDisruptionBudget: &PodDisruptionBudget{
MaxUnavailable: ptr.To(intstr.FromString("50%")),
MinAvailable: ptr.To(intstr.FromString("50%")),
},
},
},
true,
),
Entry(
"Valid with MariaDB reference",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
MariaDBRef: &MariaDBRef{
ObjectReference: corev1.ObjectReference{
Name: "mariadb",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
PodDisruptionBudget: &PodDisruptionBudget{
MaxUnavailable: ptr.To(intstr.FromString("50%")),
},
},
},
false,
),
Entry(
"Valid with servers",
&MaxScale{
ObjectMeta: meta,
Spec: MaxScaleSpec{
Servers: []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
},
Monitor: MaxScaleMonitor{
Module: MonitorModuleMariadb,
},
PodDisruptionBudget: &PodDisruptionBudget{
MaxUnavailable: ptr.To(intstr.FromString("50%")),
},
},
},
false,
),
)
})
Context("When updating a MaxScale", Ordered, func() {
key := types.NamespacedName{
Name: "maxscale-update-webhook",
Namespace: testNamespace,
}
BeforeAll(func() {
mxs := MaxScale{
ObjectMeta: metav1.ObjectMeta{
Name: key.Name,
Namespace: key.Namespace,
},
Spec: MaxScaleSpec{
MariaDBRef: &MariaDBRef{
ObjectReference: corev1.ObjectReference{
Name: "mariadb",
},
},
Services: []MaxScaleService{
{
Name: "rw-router",
Router: ServiceRouterReadWriteSplit,
Listener: MaxScaleListener{
Port: 3306,
},
},
{
Name: "rconn-master-router",
Router: ServiceRouterReadConnRoute,
Listener: MaxScaleListener{
Port: 3307,
Params: map[string]string{
"router_options": "master",
},
},
},
{
Name: "rconn-slave-router",
Router: ServiceRouterReadConnRoute,
Listener: MaxScaleListener{
Port: 3308,
Params: map[string]string{
"router_options": "slave",
},
},
},
},
Admin: MaxScaleAdmin{
Port: 8989,
},
Auth: MaxScaleAuth{
Generate: ptr.To(true),
AdminUsername: "foo",
},
KubernetesService: &ServiceTemplate{
Type: corev1.ServiceTypeLoadBalancer,
Metadata: &Metadata{
Annotations: map[string]string{
"metallb.universe.tf/loadBalancerIPs": "172.18.0.214",
},
},
},
},
}
Expect(k8sClient.Create(testCtx, &mxs)).To(Succeed())
})
DescribeTable(
"Should validate",
func(patchFn func(mxs *MaxScale), wantErr bool) {
var mxs MaxScale
Expect(k8sClient.Get(testCtx, key, &mxs)).To(Succeed())
patch := client.MergeFrom(mxs.DeepCopy())
patchFn(&mxs)
err := k8sClient.Patch(testCtx, &mxs, patch)
if wantErr {
Expect(err).To(HaveOccurred())
} else {
Expect(err).ToNot(HaveOccurred())
}
},
Entry(
"Updating Image",
func(mxs *MaxScale) {
mxs.Spec.Image = "mariadb/maxscale:23.07"
},
false,
),
Entry(
"Adding Servers",
func(mxs *MaxScale) {
servers := []MaxScaleServer{
{
Name: "mariadb-0",
Address: "mariadb-repl-0.mariadb-repl-internal.default.svc.cluster.local",
},
{
Name: "mariadb-1",
Address: "mariadb-repl-1.mariadb-repl-internal.default.svc.cluster.local",
},
{
Name: "mariadb-2",
Address: "mariadb-repl-2.mariadb-repl-internal.default.svc.cluster.local",
},
}
mxs.Spec.Servers = append(mxs.Spec.Servers, servers...)
},
false,
),
Entry(
"Adding Service",
func(mxs *MaxScale) {
mxs.Spec.Services = append(mxs.Spec.Services, MaxScaleService{
Name: "rconn-router",
Router: ServiceRouterReadConnRoute,
Listener: MaxScaleListener{
Port: 3309,
}},
)
},
false,
),
Entry(
"Updating Service",
func(mxs *MaxScale) {
mxs.Spec.Services[0].Listener.Port = 1111
},
true,
),
Entry(
"Updating Monitor interval",
func(mxs *MaxScale) {
mxs.Spec.Monitor.Interval = metav1.Duration{Duration: 1 * time.Second}
},
false,
),
Entry(
"Updating Monitor module",
func(mxs *MaxScale) {
mxs.Spec.Monitor.Module = MonitorModuleMariadb
},
false,
),
Entry(
"Updating Admin",
func(mxs *MaxScale) {
mxs.Spec.Admin.Port = 9090
},
false,
),
Entry(
"Updating Config",
func(mxs *MaxScale) {
mxs.Spec.Config.Params = map[string]string{
"foo": "bar",
}
},
false,
),
Entry(
"Updating Auth generate",
func(mxs *MaxScale) {
mxs.Spec.Auth.Generate = ptr.To(false)
},
true,
),
Entry(
"Updating Auth",
func(mxs *MaxScale) {
mxs.Spec.Auth.AdminUsername = "bar"
},
true,
),
Entry(
"Updating Replicas",
func(mxs *MaxScale) {
mxs.Spec.Replicas = 3
},
false,
),
Entry(
"Updating Resources",
func(mxs *MaxScale) {
mxs.Spec.Resources = &corev1.ResourceRequirements{
Requests: corev1.ResourceList{
"cpu": resource.MustParse("200m"),
},
}
},
false,
),
)
})
})