github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/configconstraint_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 configuration 21 22 import ( 23 "context" 24 "time" 25 26 corev1 "k8s.io/api/core/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/client-go/tools/record" 29 ctrl "sigs.k8s.io/controller-runtime" 30 "sigs.k8s.io/controller-runtime/pkg/client" 31 "sigs.k8s.io/controller-runtime/pkg/log" 32 33 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 34 cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core" 35 "github.com/1aal/kubeblocks/pkg/constant" 36 intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 37 ) 38 39 // ConfigConstraintReconciler reconciles a ConfigConstraint object 40 type ConfigConstraintReconciler struct { 41 client.Client 42 Scheme *runtime.Scheme 43 Recorder record.EventRecorder 44 } 45 46 // +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=configconstraints,verbs=get;list;watch;create;update;patch;delete 47 // +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=configconstraints/status,verbs=get;update;patch 48 // +kubebuilder:rbac:groups=apps.kubeblocks.io,resources=configconstraints/finalizers,verbs=update 49 50 // Reconcile is part of the main kubernetes reconciliation loop which aims to 51 // move the current state of the cluster closer to the desired state. 52 // TODO(user): Modify the Reconcile function to compare the state specified by 53 // the ConfigConstraint object against the actual cluster state, and then 54 // perform operations to make the cluster state reflect the state specified by 55 // the user. 56 // 57 // For more details, check Reconcile and its Result here: 58 // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.2/pkg/reconcile 59 func (r *ConfigConstraintReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 60 reqCtx := intctrlutil.RequestCtx{ 61 Ctx: ctx, 62 Req: req, 63 Log: log.FromContext(ctx).WithName("ConfigConstraintReconcile").WithValues("ConfigConstraint", req.NamespacedName.Name), 64 Recorder: r.Recorder, 65 } 66 67 configConstraint := &appsv1alpha1.ConfigConstraint{} 68 if err := r.Client.Get(reqCtx.Ctx, reqCtx.Req.NamespacedName, configConstraint); err != nil { 69 return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "") 70 } 71 72 res, err := intctrlutil.HandleCRDeletion(reqCtx, r, configConstraint, constant.ConfigurationTemplateFinalizerName, func() (*ctrl.Result, error) { 73 recordEvent := func() { 74 r.Recorder.Event(configConstraint, corev1.EventTypeWarning, "ExistsReferencedResources", 75 "cannot be deleted because of existing referencing of ClusterDefinition or ClusterVersion.") 76 } 77 if configConstraint.Status.Phase != appsv1alpha1.CCDeletingPhase { 78 err := updateConfigConstraintStatus(r.Client, reqCtx, configConstraint, appsv1alpha1.CCDeletingPhase) 79 // if fail to update ConfigConstraint status, return error, 80 // so that it can be retried 81 if err != nil { 82 return nil, err 83 } 84 } 85 if res, err := intctrlutil.ValidateReferenceCR(reqCtx, r.Client, configConstraint, 86 cfgcore.GenerateConstraintsUniqLabelKeyWithConfig(configConstraint.GetName()), 87 recordEvent, &appsv1alpha1.ClusterDefinitionList{}, 88 &appsv1alpha1.ClusterVersionList{}); res != nil || err != nil { 89 return res, err 90 } 91 return nil, nil 92 }) 93 if res != nil { 94 return *res, err 95 } 96 97 if configConstraint.Status.ObservedGeneration == configConstraint.Generation && configConstraint.Status.IsConfigConstraintTerminalPhases() { 98 return intctrlutil.Reconciled() 99 } 100 101 if ok, err := checkConfigConstraint(reqCtx, configConstraint); !ok || err != nil { 102 return intctrlutil.RequeueAfter(time.Second, reqCtx.Log, "ValidateConfigurationTemplate") 103 } 104 105 // Automatically convert cue to openAPISchema. 106 if err := updateConfigSchema(configConstraint, r.Client, ctx); err != nil { 107 return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "failed to generate openAPISchema") 108 } 109 110 err = updateConfigConstraintStatus(r.Client, reqCtx, configConstraint, appsv1alpha1.CCAvailablePhase) 111 if err != nil { 112 return intctrlutil.CheckedRequeueWithError(err, reqCtx.Log, "") 113 } 114 intctrlutil.RecordCreatedEvent(r.Recorder, configConstraint) 115 return ctrl.Result{}, nil 116 } 117 118 // SetupWithManager sets up the controller with the Manager. 119 func (r *ConfigConstraintReconciler) SetupWithManager(mgr ctrl.Manager) error { 120 return ctrl.NewControllerManagedBy(mgr). 121 For(&appsv1alpha1.ConfigConstraint{}). 122 // for other resource 123 Owns(&corev1.ConfigMap{}). 124 Complete(r) 125 }