@@ -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,119 @@ 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 = "dmp-extension"
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