@@ -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
4247const (
@@ -207,3 +212,138 @@ 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+ // sometime the path and port are missing, I don't know why
288+ if oldCrd .Spec .Conversion == nil || oldCrd .Spec .Conversion .Webhook == nil || oldCrd .Spec .Conversion .Webhook .ClientConfig == nil ||
289+ oldCrd .Spec .Conversion .Webhook .ClientConfig .CABundle == nil ||
290+ oldCrd .Spec .Conversion .Webhook .ClientConfig .Service .Path == nil ||
291+ oldCrd .Spec .Conversion .Webhook .ClientConfig .Service .Port == nil ||
292+ ! bytes .Equal (oldCrd .Spec .Conversion .Webhook .ClientConfig .CABundle , cert ) {
293+ crd .Spec .Conversion = & apiextensionsv1.CustomResourceConversion {
294+ Strategy : apiextensionsv1 .WebhookConverter ,
295+ Webhook : & apiextensionsv1.WebhookConversion {
296+ ClientConfig : & apiextensionsv1.WebhookClientConfig {
297+ CABundle : []byte (cert ),
298+ Service : & apiextensionsv1.ServiceReference {
299+ Namespace : ns ,
300+ Name : func () string {
301+ if oldCrd .Spec .Conversion != nil && oldCrd .Spec .Conversion .Webhook != nil && oldCrd .Spec .Conversion .Webhook .ClientConfig != nil {
302+ return oldCrd .Spec .Conversion .Webhook .ClientConfig .Service .Name
303+ } else {
304+ return "radondb-mysql-webhook"
305+ }
306+ }(),
307+ Path : func () * string {
308+ var p string = "/convert"
309+ return & p
310+ }(),
311+ Port : func () * int32 {
312+ var serverPort int32 = 443
313+ return & serverPort
314+ }(),
315+ },
316+ },
317+ ConversionReviewVersions : []string {"v1" },
318+ },
319+ }
320+ log .Info ("covert crd" , "value" , crd .Spec .Conversion )
321+ } else {
322+ return nil
323+ }
324+ errCRD = cli .Patch (ctx , crd , client .MergeFrom (oldCrd ))
325+ if errCRD != nil {
326+ return errCRD
327+ }
328+
329+ return nil
330+ }
331+
332+ func RunUpdeteCRD (cli client.Client , log * logr.Logger ) {
333+ go func () {
334+ // 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
335+ // if this process failed, just need to restart the operetor pod
336+ for i := 0 ; i < 100 ; i ++ {
337+ time .Sleep (time .Second * 5 )
338+ err := UpdateforCRD ("mysqlclusters.mysql.radondb.com" , cli , log )
339+ if err != nil {
340+ log .Info ("update CRD failed" , "error" , err )
341+ }
342+ err = UpdateforCRD ("backups.mysql.radondb.com" , cli , log )
343+ if err != nil {
344+ log .Info ("update CRD failed" , "error" , err )
345+ }
346+ }
347+ log .Info ("check the crd about 8 minutes, now exit." )
348+ }()
349+ }
0 commit comments