github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/clusterdefinition_controller.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package apps 21 22 import ( 23 "context" 24 "runtime" 25 "time" 26 27 "golang.org/x/exp/slices" 28 corev1 "k8s.io/api/core/v1" 29 k8sruntime "k8s.io/apimachinery/pkg/runtime" 30 "k8s.io/client-go/tools/record" 31 ctrl "sigs.k8s.io/controller-runtime" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 "sigs.k8s.io/controller-runtime/pkg/controller" 34 "sigs.k8s.io/controller-runtime/pkg/log" 35 36 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 37 appsconfig "github.com/1aal/kubeblocks/controllers/apps/configuration" 38 "github.com/1aal/kubeblocks/pkg/constant" 39 intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 40 viper "github.com/1aal/kubeblocks/pkg/viperx" 41 ) 42 43 // +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=clusterdefinitions,verbs=get;list;watch;create;update;patch;delete 44 // +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=clusterdefinitions/status,verbs=get;update;patch 45 // +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=clusterdefinitions/finalizers,verbs=update 46 47 // ClusterDefinitionReconciler reconciles a ClusterDefinition object 48 type ClusterDefinitionReconciler struct { 49 client.Client 50 Scheme *k8sruntime.Scheme 51 Recorder record.EventRecorder 52 } 53 54 var clusterDefUpdateHandlers = map[string]func(client client.Client, ctx context.Context, clusterDef *appsv1alpha1.ClusterDefinition) error{} 55 56 func init() { 57 viper.SetDefault(maxConcurReconClusterDefKey, runtime.NumCPU()) 58 } 59 60 // Reconcile is part of the main kubernetes reconciliation loop which aims to 61 // move the current state of the cluster closer to the desired state. 62 // 63 // For more details, check Reconcile and its Result here: 64 // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.4/pkg/reconcile 65 func (r *ClusterDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 66 reqCtx := intctrlutil.RequestCtx{ 67 Ctx: ctx, 68 Req: req, 69 Log: log.FromContext(ctx).WithValues("clusterDefinition", req.NamespacedName), 70 Recorder: r.Recorder, 71 } 72 73 dbClusterDef := &appsv1alpha1.ClusterDefinition{} 74 if err := r.Client.Get(reqCtx.Ctx, reqCtx.Req.NamespacedName, dbClusterDef); err != nil { 75 return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "") 76 } 77 78 res, err := intctrlutil.HandleCRDeletion(reqCtx, r, dbClusterDef, dbClusterDefFinalizerName, func() (*ctrl.Result, error) { 79 recordEvent := func() { 80 r.Recorder.Event(dbClusterDef, corev1.EventTypeWarning, "ExistsReferencedResources", 81 "cannot be deleted because of existing referencing Cluster or ClusterVersion.") 82 } 83 if res, err := intctrlutil.ValidateReferenceCR(reqCtx, r.Client, dbClusterDef, 84 constant.ClusterDefLabelKey, recordEvent, &appsv1alpha1.ClusterList{}, 85 &appsv1alpha1.ClusterVersionList{}); res != nil || err != nil { 86 return res, err 87 } 88 return nil, r.deleteExternalResources(reqCtx, dbClusterDef) 89 }) 90 if res != nil { 91 return *res, err 92 } 93 94 if dbClusterDef.Status.ObservedGeneration == dbClusterDef.Generation && 95 slices.Contains(dbClusterDef.Status.GetTerminalPhases(), dbClusterDef.Status.Phase) { 96 return intctrlutil.Reconciled() 97 } 98 99 if err := appsconfig.ReconcileConfigSpecsForReferencedCR(r.Client, reqCtx, dbClusterDef); err != nil { 100 return intctrlutil.RequeueAfter(time.Second, reqCtx.Log, err.Error()) 101 } 102 103 for _, handler := range clusterDefUpdateHandlers { 104 if err := handler(r.Client, reqCtx.Ctx, dbClusterDef); err != nil { 105 return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "") 106 } 107 } 108 109 statusPatch := client.MergeFrom(dbClusterDef.DeepCopy()) 110 dbClusterDef.Status.ObservedGeneration = dbClusterDef.Generation 111 dbClusterDef.Status.Phase = appsv1alpha1.AvailablePhase 112 if err = r.Client.Status().Patch(reqCtx.Ctx, dbClusterDef, statusPatch); err != nil { 113 return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "") 114 } 115 intctrlutil.RecordCreatedEvent(r.Recorder, dbClusterDef) 116 return intctrlutil.Reconciled() 117 } 118 119 // SetupWithManager sets up the controller with the Manager. 120 func (r *ClusterDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { 121 return ctrl.NewControllerManagedBy(mgr). 122 For(&appsv1alpha1.ClusterDefinition{}). 123 WithOptions(controller.Options{ 124 MaxConcurrentReconciles: viper.GetInt(maxConcurReconClusterDefKey), 125 }). 126 Complete(r) 127 } 128 129 func (r *ClusterDefinitionReconciler) deleteExternalResources(reqCtx intctrlutil.RequestCtx, clusterDef *appsv1alpha1.ClusterDefinition) error { 130 // 131 // delete any external resources associated with the cronJob 132 // 133 // Ensure that delete implementation is idempotent and safe to invoke 134 // multiple times for same object. 135 return appsconfig.DeleteConfigMapFinalizer(r.Client, reqCtx, clusterDef) 136 }