Skip to content

Commit d305a6e

Browse files
committed
add the crd update for DMP reinstall
1 parent 9d503a3 commit d305a6e

File tree

6 files changed

+149
-2
lines changed

6 files changed

+149
-2
lines changed

charts/mysql-operator/templates/cluster_rbac.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ metadata:
99
release: {{ .Release.Name | quote }}
1010
heritage: {{ .Release.Service | quote }}
1111
rules:
12+
- apiGroups:
13+
- apiextensions.k8s.io
14+
resources:
15+
- customresourcedefinitions
16+
verbs:
17+
- get
18+
- list
19+
- patch
20+
- update
21+
- watch
1222
- apiGroups:
1323
- apps
1424
resources:

cmd/manager/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
2626
// to ensure that exec-entrypoint and run can make use of them.
27+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2728
_ "k8s.io/client-go/plugin/pkg/client/auth"
2829

2930
"k8s.io/apimachinery/pkg/runtime"
@@ -44,6 +45,7 @@ import (
4445
"github.com/radondb/radondb-mysql-kubernetes/controllers"
4546
"github.com/radondb/radondb-mysql-kubernetes/controllers/backup"
4647
"github.com/radondb/radondb-mysql-kubernetes/internal"
48+
"github.com/radondb/radondb-mysql-kubernetes/utils"
4749
//+kubebuilder:scaffold:imports
4850
)
4951

@@ -58,6 +60,7 @@ func init() {
5860
utilruntime.Must(mysqlv1alpha1.AddToScheme(scheme))
5961
utilruntime.Must(mysqlv1beta1.AddToScheme(scheme))
6062
//+kubebuilder:scaffold:scheme
63+
utilruntime.Must(apiextensionsv1.AddToScheme(scheme))
6164
}
6265

6366
func main() {
@@ -171,10 +174,12 @@ func main() {
171174
setupLog.Error(err, "unable to set up ready check")
172175
os.Exit(1)
173176
}
174-
177+
// check crds
178+
utils.RunUpdeteCRD(mgr.GetClient(), &setupLog)
175179
setupLog.Info("starting manager")
176180
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
177181
setupLog.Error(err, "problem running manager")
178182
os.Exit(1)
179183
}
184+
180185
}

config/rbac/role.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ metadata:
66
creationTimestamp: null
77
name: manager-role
88
rules:
9+
- apiGroups:
10+
- apiextensions.k8s.io
11+
resources:
12+
- customresourcedefinitions
13+
verbs:
14+
- get
15+
- list
16+
- patch
17+
- update
18+
- watch
919
- apiGroups:
1020
- apps
1121
resources:

config/samples/mysql_v1beta1_mysqlcluster.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ spec:
2424
# path: host
2525

2626
image: percona/percona-server:8.0.25
27-
imagePullPolicy: Always
27+
imagePullPolicy: IfNotPresent
2828
logOpts:
2929
resources:
3030
requests:

controllers/mysqlcluster_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type MysqlClusterReconciler struct {
5555
internal.XenonExecutor
5656
}
5757

58+
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;update;patch
5859
// +kubebuilder:rbac:groups=mysql.radondb.com,resources=mysqlclusters,verbs=get;list;watch;create;update;patch;delete
5960
// +kubebuilder:rbac:groups=mysql.radondb.com,resources=mysqlclusters/status,verbs=get;update;patch
6061
// +kubebuilder:rbac:groups=mysql.radondb.com,resources=mysqlclusters/finalizers,verbs=update

utils/incluster.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,20 @@ import (
2828
"os/exec"
2929
"strconv"
3030
"strings"
31+
"time"
3132

33+
"github.com/go-logr/logr"
3234
corev1 "k8s.io/api/core/v1"
35+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
36+
"k8s.io/apimachinery/pkg/api/errors"
3337
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3438
"k8s.io/apimachinery/pkg/runtime"
3539
"k8s.io/apimachinery/pkg/types"
3640
"k8s.io/client-go/kubernetes"
3741
"k8s.io/client-go/rest"
3842
"k8s.io/client-go/tools/clientcmd"
3943
"k8s.io/client-go/tools/remotecommand"
44+
"sigs.k8s.io/controller-runtime/pkg/client"
4045
)
4146

4247
const (
@@ -207,3 +212,119 @@ func NewConfig() (*rest.Config, error) {
207212
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
208213
loader, &clientcmd.ConfigOverrides{}).ClientConfig()
209214
}
215+
216+
func UpdateforCRD(crdName string, cli client.Client, log *logr.Logger) error {
217+
// TODO: update CRD
218+
219+
// MYNS=extension-dmp
220+
// CRD1=mysqlclusters.mysql.radondb.com
221+
// CRD2=backups.mysql.radondb.com
222+
// SEC=radondb-mysql-webhook-certs
223+
// CERT=$(kubectl -n $MYNS get secrets $SEC -ojsonpath='{.data.tls\.crt}')
224+
// kubectl patch CustomResourceDefinition $CRD1 --type=merge -p '{"spec":{"conversion":{"webhook":{"clientConfig":{"caBundle":"'$CERT'","service":{"namespace":"'$MYNS'"}}}}}}'
225+
// kubectl patch CustomResourceDefinition $CRD2 --type=merge -p '{"spec":{"conversion":{"webhook":{"clientConfig":{"caBundle":"'$CERT'","service":{"namespace":"'$MYNS'"}}}}}}'
226+
// echo $CERT
227+
// fetch a secret in dmp-extension namespace which is named radondb-mysql-webhook-certs
228+
// 1. first get os environment value MY_NAMESPACE, if not set, use default namespace ,"dmp-extension"
229+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
230+
defer cancel()
231+
ns := os.Getenv("MY_NAMESPACE")
232+
if len(ns) == 0 {
233+
ns = "extension-dmp"
234+
}
235+
//2. get os environment value CERT_NAME, if not set, use default namespace "radondb-mysql-webhook-certs"
236+
certName := os.Getenv("CERT_NAME")
237+
if len(certName) == 0 {
238+
certName = "radondb-mysql-webhook-certs"
239+
}
240+
secret := &corev1.Secret{
241+
TypeMeta: metav1.TypeMeta{
242+
Kind: "Secret",
243+
APIVersion: "v1",
244+
},
245+
ObjectMeta: metav1.ObjectMeta{
246+
Name: certName,
247+
Namespace: ns,
248+
},
249+
}
250+
err := cli.Get(ctx, types.NamespacedName{Name: secret.Name, Namespace: secret.Namespace}, secret)
251+
// if err is not found, return error
252+
if errors.IsNotFound(err) {
253+
return fmt.Errorf("secret %s not found", certName)
254+
}
255+
cert := secret.Data["tls.crt"]
256+
257+
//fetch the CustomResourceDefinition ,which name is mysqlclusters.mysql.radondb.com
258+
// 创建 CRD 实例
259+
//apiextensionsv1.AddToScheme(scheme)
260+
//CustomResourceDefinition
261+
crd := &apiextensionsv1.CustomResourceDefinition{
262+
TypeMeta: metav1.TypeMeta{
263+
APIVersion: "v1",
264+
Kind: "CustomResourceDefinition",
265+
},
266+
ObjectMeta: metav1.ObjectMeta{
267+
Name: crdName,
268+
},
269+
}
270+
// 使用客户端获取 CRD 资源
271+
errCRD := cli.Get(ctx, types.NamespacedName{Name: crdName}, crd)
272+
if errCRD != nil {
273+
return errCRD
274+
}
275+
hasBetaVersion := false
276+
for _, v := range crd.Spec.Versions {
277+
if v.Name == "v1beta1" {
278+
hasBetaVersion = true
279+
}
280+
}
281+
if !hasBetaVersion {
282+
return fmt.Errorf("has not v1beta1 version")
283+
}
284+
285+
oldCrd := crd.DeepCopy()
286+
// if CustomResourceConversion's CABundle of Webhook is not equal to cert, update it
287+
if oldCrd.Spec.Conversion == nil || oldCrd.Spec.Conversion.Webhook == nil || oldCrd.Spec.Conversion.Webhook.ClientConfig == nil ||
288+
oldCrd.Spec.Conversion.Webhook.ClientConfig.CABundle == nil || !bytes.Equal(oldCrd.Spec.Conversion.Webhook.ClientConfig.CABundle, cert) {
289+
log.Info("covert crd", "value", !bytes.Equal(oldCrd.Spec.Conversion.Webhook.ClientConfig.CABundle, cert))
290+
crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{
291+
Strategy: apiextensionsv1.WebhookConverter,
292+
Webhook: &apiextensionsv1.WebhookConversion{
293+
ClientConfig: &apiextensionsv1.WebhookClientConfig{
294+
CABundle: []byte(cert),
295+
Service: &apiextensionsv1.ServiceReference{
296+
Namespace: ns,
297+
},
298+
},
299+
ConversionReviewVersions: []string{"v1"},
300+
},
301+
}
302+
} else {
303+
return nil
304+
}
305+
errCRD = cli.Patch(ctx, crd, client.MergeFrom(oldCrd))
306+
if errCRD != nil {
307+
return errCRD
308+
}
309+
310+
return nil
311+
}
312+
313+
func RunUpdeteCRD(cli client.Client, log *logr.Logger) {
314+
go func() {
315+
// Just run in the first 500 seconds,almost eight minutes, because the crd webhook's CABundle is not correct just in the DMP reinstall period
316+
// if this process failed, just need to restart the operetor pod
317+
for i := 0; i < 100; i++ {
318+
time.Sleep(time.Second * 5)
319+
err := UpdateforCRD("mysqlclusters.mysql.radondb.com", cli, log)
320+
if err != nil {
321+
log.Info("update CRD failed", "error", err)
322+
}
323+
err = UpdateforCRD("backups.mysql.radondb.com", cli, log)
324+
if err != nil {
325+
log.Info("update CRD failed", "error", err)
326+
}
327+
}
328+
log.Info("check the crd about 8 minutes, now exit.")
329+
}()
330+
}

0 commit comments

Comments
 (0)