Skip to content

Commit 2ad209c

Browse files
committed
mysqlcluster: when storage size shrink, and change replicas, It will reconcile fail forever. #436
1 parent e5bc8b4 commit 2ad209c

20 files changed

+463
-63
lines changed

PROJECT

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ resources:
1313
kind: MysqlCluster
1414
path: github.com/radondb/radondb-mysql-kubernetes/api/v1alpha1
1515
version: v1alpha1
16+
webhooks:
17+
defaulting: true
18+
validation: true
19+
webhookVersion: v1
1620
- controller: true
1721
domain: radondb.com
1822
group: mysql

api/v1alpha1/mysqlcluster_webhook.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
Copyright 2021 RadonDB.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
import (
20+
"fmt"
21+
22+
"k8s.io/apimachinery/pkg/api/resource"
23+
"k8s.io/apimachinery/pkg/runtime"
24+
ctrl "sigs.k8s.io/controller-runtime"
25+
logf "sigs.k8s.io/controller-runtime/pkg/log"
26+
"sigs.k8s.io/controller-runtime/pkg/webhook"
27+
)
28+
29+
// log is for logging in this package.
30+
var mysqlclusterlog = logf.Log.WithName("mysqlcluster-resource")
31+
32+
func (r *MysqlCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
33+
return ctrl.NewWebhookManagedBy(mgr).
34+
For(r).
35+
Complete()
36+
}
37+
38+
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
39+
40+
//+kubebuilder:webhook:path=/mutate-mysql-radondb-com-v1alpha1-mysqlcluster,mutating=true,failurePolicy=fail,sideEffects=None,groups=mysql.radondb.com,resources=mysqlclusters,verbs=create;update,versions=v1alpha1,name=mmysqlcluster.kb.io,admissionReviewVersions={v1,v1beta1}
41+
42+
var _ webhook.Defaulter = &MysqlCluster{}
43+
44+
// Default implements webhook.Defaulter so a webhook will be registered for the type
45+
func (r *MysqlCluster) Default() {
46+
mysqlclusterlog.Info("default", "name", r.Name)
47+
48+
// TODO(user): fill in your defaulting logic.
49+
}
50+
51+
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
52+
//+kubebuilder:webhook:path=/validate-mysql-radondb-com-v1alpha1-mysqlcluster,mutating=false,failurePolicy=fail,sideEffects=None,groups=mysql.radondb.com,resources=mysqlclusters,verbs=create;update,versions=v1alpha1,name=vmysqlcluster.kb.io,admissionReviewVersions={v1,v1beta1}
53+
54+
var _ webhook.Validator = &MysqlCluster{}
55+
56+
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
57+
func (r *MysqlCluster) ValidateCreate() error {
58+
mysqlclusterlog.Info("validate create", "name", r.Name)
59+
60+
// TODO(user): fill in your validation logic upon object creation.
61+
return nil
62+
}
63+
64+
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
65+
func (r *MysqlCluster) ValidateUpdate(old runtime.Object) error {
66+
mysqlclusterlog.Info("validate update", "name", r.Name)
67+
oldCluster := old.(*MysqlCluster)
68+
oldStorageSize, err := resource.ParseQuantity(oldCluster.Spec.Persistence.Size)
69+
if err != nil {
70+
return err
71+
}
72+
newStorageSize, err := resource.ParseQuantity(r.Spec.Persistence.Size)
73+
if err != nil {
74+
return err
75+
}
76+
// =1 means that old storage size is greater then new
77+
if oldStorageSize.Cmp(newStorageSize) == 1 {
78+
return fmt.Errorf("storage size cannot be changed to smaller than current size")
79+
}
80+
// TODO(user): fill in your validation logic upon object update.
81+
return nil
82+
}
83+
84+
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
85+
func (r *MysqlCluster) ValidateDelete() error {
86+
mysqlclusterlog.Info("validate delete", "name", r.Name)
87+
88+
// TODO(user): fill in your validation logic upon object deletion.
89+
return nil
90+
}

api/v1alpha1/webhook_suite_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
Copyright 2021 RadonDB.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
import (
20+
"context"
21+
"crypto/tls"
22+
"fmt"
23+
"net"
24+
"path/filepath"
25+
"testing"
26+
"time"
27+
28+
. "github.com/onsi/ginkgo"
29+
. "github.com/onsi/gomega"
30+
31+
admissionv1beta1 "k8s.io/api/admission/v1beta1"
32+
//+kubebuilder:scaffold:imports
33+
"k8s.io/apimachinery/pkg/runtime"
34+
"k8s.io/client-go/rest"
35+
ctrl "sigs.k8s.io/controller-runtime"
36+
"sigs.k8s.io/controller-runtime/pkg/client"
37+
"sigs.k8s.io/controller-runtime/pkg/envtest"
38+
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
39+
logf "sigs.k8s.io/controller-runtime/pkg/log"
40+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
41+
)
42+
43+
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
44+
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
45+
46+
var cfg *rest.Config
47+
var k8sClient client.Client
48+
var testEnv *envtest.Environment
49+
var ctx context.Context
50+
var cancel context.CancelFunc
51+
52+
func TestAPIs(t *testing.T) {
53+
RegisterFailHandler(Fail)
54+
55+
RunSpecsWithDefaultAndCustomReporters(t,
56+
"Webhook Suite",
57+
[]Reporter{printer.NewlineReporter{}})
58+
}
59+
60+
var _ = BeforeSuite(func() {
61+
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
62+
63+
ctx, cancel = context.WithCancel(context.TODO())
64+
65+
By("bootstrapping test environment")
66+
testEnv = &envtest.Environment{
67+
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
68+
ErrorIfCRDPathMissing: false,
69+
WebhookInstallOptions: envtest.WebhookInstallOptions{
70+
Paths: []string{filepath.Join("..", "..", "config", "webhook")},
71+
},
72+
}
73+
74+
cfg, err := testEnv.Start()
75+
Expect(err).NotTo(HaveOccurred())
76+
Expect(cfg).NotTo(BeNil())
77+
78+
scheme := runtime.NewScheme()
79+
err = AddToScheme(scheme)
80+
Expect(err).NotTo(HaveOccurred())
81+
82+
err = admissionv1beta1.AddToScheme(scheme)
83+
Expect(err).NotTo(HaveOccurred())
84+
85+
//+kubebuilder:scaffold:scheme
86+
87+
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
88+
Expect(err).NotTo(HaveOccurred())
89+
Expect(k8sClient).NotTo(BeNil())
90+
91+
// start webhook server using Manager
92+
webhookInstallOptions := &testEnv.WebhookInstallOptions
93+
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
94+
Scheme: scheme,
95+
Host: webhookInstallOptions.LocalServingHost,
96+
Port: webhookInstallOptions.LocalServingPort,
97+
CertDir: webhookInstallOptions.LocalServingCertDir,
98+
LeaderElection: false,
99+
MetricsBindAddress: "0",
100+
})
101+
Expect(err).NotTo(HaveOccurred())
102+
103+
err = (&MysqlCluster{}).SetupWebhookWithManager(mgr)
104+
Expect(err).NotTo(HaveOccurred())
105+
106+
//+kubebuilder:scaffold:webhook
107+
108+
go func() {
109+
err = mgr.Start(ctx)
110+
if err != nil {
111+
Expect(err).NotTo(HaveOccurred())
112+
}
113+
}()
114+
115+
// wait for the webhook server to get ready
116+
dialer := &net.Dialer{Timeout: time.Second}
117+
addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
118+
Eventually(func() error {
119+
conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true})
120+
if err != nil {
121+
return err
122+
}
123+
conn.Close()
124+
return nil
125+
}).Should(Succeed())
126+
127+
}, 60)
128+
129+
var _ = AfterSuite(func() {
130+
cancel()
131+
By("tearing down the test environment")
132+
err := testEnv.Stop()
133+
Expect(err).NotTo(HaveOccurred())
134+
})

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/manager/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ func main() {
116116
setupLog.Error(err, "unable to create controller", "controller", "MysqlUser")
117117
os.Exit(1)
118118
}
119+
if os.Getenv("ENABLE_WEBHOOKS") != "false" {
120+
if err = (&mysqlv1alpha1.MysqlCluster{}).SetupWebhookWithManager(mgr); err != nil {
121+
setupLog.Error(err, "unable to create webhook", "webhook", "MysqlCluster")
122+
os.Exit(1)
123+
}
124+
}
119125
//+kubebuilder:scaffold:builder
120126

121127
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {

config/certmanager/certificate.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# The following manifests contain a self-signed issuer CR and a certificate CR.
2+
# More document can be found at https://docs.cert-manager.io
3+
# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
4+
apiVersion: cert-manager.io/v1
5+
kind: Issuer
6+
metadata:
7+
name: selfsigned-issuer
8+
namespace: system
9+
spec:
10+
selfSigned: {}
11+
---
12+
apiVersion: cert-manager.io/v1
13+
kind: Certificate
14+
metadata:
15+
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
16+
namespace: system
17+
spec:
18+
# $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
19+
dnsNames:
20+
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
21+
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
22+
issuerRef:
23+
kind: Issuer
24+
name: selfsigned-issuer
25+
secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize

config/certmanager/kustomization.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resources:
2+
- certificate.yaml
3+
4+
configurations:
5+
- kustomizeconfig.yaml
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This configuration is for teaching kustomize how to update name ref and var substitution
2+
nameReference:
3+
- kind: Issuer
4+
group: cert-manager.io
5+
fieldSpecs:
6+
- kind: Certificate
7+
group: cert-manager.io
8+
path: spec/issuerRef/name
9+
10+
varReference:
11+
- kind: Certificate
12+
group: cert-manager.io
13+
path: spec/commonName
14+
- kind: Certificate
15+
group: cert-manager.io
16+
path: spec/dnsNames

config/default/kustomization.yaml

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ bases:
1818
- ../manager
1919
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
2020
# crd/kustomization.yaml
21-
#- ../webhook
21+
- ../webhook
2222
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
23-
#- ../certmanager
23+
- ../certmanager
2424
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
2525
#- ../prometheus
2626

@@ -36,39 +36,39 @@ patchesStrategicMerge:
3636

3737
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
3838
# crd/kustomization.yaml
39-
#- manager_webhook_patch.yaml
39+
- manager_webhook_patch.yaml
4040

4141
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
4242
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
4343
# 'CERTMANAGER' needs to be enabled to use ca injection
44-
#- webhookcainjection_patch.yaml
44+
- webhookcainjection_patch.yaml
4545

4646
# the following config is for teaching kustomize how to do var substitution
4747
vars:
4848
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
49-
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
50-
# objref:
51-
# kind: Certificate
52-
# group: cert-manager.io
53-
# version: v1
54-
# name: serving-cert # this name should match the one in certificate.yaml
55-
# fieldref:
56-
# fieldpath: metadata.namespace
57-
#- name: CERTIFICATE_NAME
58-
# objref:
59-
# kind: Certificate
60-
# group: cert-manager.io
61-
# version: v1
62-
# name: serving-cert # this name should match the one in certificate.yaml
63-
#- name: SERVICE_NAMESPACE # namespace of the service
64-
# objref:
65-
# kind: Service
66-
# version: v1
67-
# name: webhook-service
68-
# fieldref:
69-
# fieldpath: metadata.namespace
70-
#- name: SERVICE_NAME
71-
# objref:
72-
# kind: Service
73-
# version: v1
74-
# name: webhook-service
49+
- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
50+
objref:
51+
kind: Certificate
52+
group: cert-manager.io
53+
version: v1
54+
name: serving-cert # this name should match the one in certificate.yaml
55+
fieldref:
56+
fieldpath: metadata.namespace
57+
- name: CERTIFICATE_NAME
58+
objref:
59+
kind: Certificate
60+
group: cert-manager.io
61+
version: v1
62+
name: serving-cert # this name should match the one in certificate.yaml
63+
- name: SERVICE_NAMESPACE # namespace of the service
64+
objref:
65+
kind: Service
66+
version: v1
67+
name: webhook-service
68+
fieldref:
69+
fieldpath: metadata.namespace
70+
- name: SERVICE_NAME
71+
objref:
72+
kind: Service
73+
version: v1
74+
name: webhook-service

0 commit comments

Comments
 (0)