@@ -28,15 +28,20 @@ import (
28
28
"os/exec"
29
29
"strconv"
30
30
"strings"
31
+ "time"
31
32
33
+ "github.com/go-logr/logr"
32
34
corev1 "k8s.io/api/core/v1"
35
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
36
+ "k8s.io/apimachinery/pkg/api/errors"
33
37
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34
38
"k8s.io/apimachinery/pkg/runtime"
35
39
"k8s.io/apimachinery/pkg/types"
36
40
"k8s.io/client-go/kubernetes"
37
41
"k8s.io/client-go/rest"
38
42
"k8s.io/client-go/tools/clientcmd"
39
43
"k8s.io/client-go/tools/remotecommand"
44
+ "sigs.k8s.io/controller-runtime/pkg/client"
40
45
)
41
46
42
47
const (
@@ -207,3 +212,126 @@ func NewConfig() (*rest.Config, error) {
207
212
return clientcmd .NewNonInteractiveDeferredLoadingClientConfig (
208
213
loader , & clientcmd.ConfigOverrides {}).ClientConfig ()
209
214
}
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
+ crd .Spec .Conversion = & apiextensionsv1.CustomResourceConversion {
290
+ Strategy : apiextensionsv1 .WebhookConverter ,
291
+ Webhook : & apiextensionsv1.WebhookConversion {
292
+ ClientConfig : & apiextensionsv1.WebhookClientConfig {
293
+ CABundle : []byte (cert ),
294
+ Service : & apiextensionsv1.ServiceReference {
295
+ Namespace : ns ,
296
+ Name : func () string {
297
+ if oldCrd .Spec .Conversion != nil && oldCrd .Spec .Conversion .Webhook != nil && oldCrd .Spec .Conversion .Webhook .ClientConfig != nil {
298
+ return oldCrd .Spec .Conversion .Webhook .ClientConfig .Service .Name
299
+ } else {
300
+ return "radondb-mysql-webhook"
301
+ }
302
+ }(),
303
+ },
304
+ },
305
+ ConversionReviewVersions : []string {"v1" },
306
+ },
307
+ }
308
+ //log.Info("covert crd", "value", crd.Spec.Conversion)
309
+ } else {
310
+ return nil
311
+ }
312
+ errCRD = cli .Patch (ctx , crd , client .MergeFrom (oldCrd ))
313
+ if errCRD != nil {
314
+ return errCRD
315
+ }
316
+
317
+ return nil
318
+ }
319
+
320
+ func RunUpdeteCRD (cli client.Client , log * logr.Logger ) {
321
+ go func () {
322
+ // 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
323
+ // if this process failed, just need to restart the operetor pod
324
+ for i := 0 ; i < 100 ; i ++ {
325
+ time .Sleep (time .Second * 5 )
326
+ err := UpdateforCRD ("mysqlclusters.mysql.radondb.com" , cli , log )
327
+ if err != nil {
328
+ log .Info ("update CRD failed" , "error" , err )
329
+ }
330
+ err = UpdateforCRD ("backups.mysql.radondb.com" , cli , log )
331
+ if err != nil {
332
+ log .Info ("update CRD failed" , "error" , err )
333
+ }
334
+ }
335
+ log .Info ("check the crd about 8 minutes, now exit." )
336
+ }()
337
+ }
0 commit comments