sigs.k8s.io/cluster-api@v1.7.1/exp/addons/internal/controllers/clusterresourcesetbinding_controller.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package controllers 18 19 import ( 20 "context" 21 22 "github.com/pkg/errors" 23 apierrors "k8s.io/apimachinery/pkg/api/errors" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 ctrl "sigs.k8s.io/controller-runtime" 26 "sigs.k8s.io/controller-runtime/pkg/client" 27 "sigs.k8s.io/controller-runtime/pkg/controller" 28 "sigs.k8s.io/controller-runtime/pkg/handler" 29 "sigs.k8s.io/controller-runtime/pkg/reconcile" 30 31 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 32 addonsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1" 33 "sigs.k8s.io/cluster-api/feature" 34 "sigs.k8s.io/cluster-api/internal/hooks" 35 "sigs.k8s.io/cluster-api/util" 36 "sigs.k8s.io/cluster-api/util/patch" 37 "sigs.k8s.io/cluster-api/util/predicates" 38 ) 39 40 // +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=*,verbs=get;list;watch;create;update;patch;delete 41 42 // ClusterResourceSetBindingReconciler reconciles a ClusterResourceSetBinding object. 43 type ClusterResourceSetBindingReconciler struct { 44 Client client.Client 45 46 // WatchFilterValue is the label value used to filter events prior to reconciliation. 47 WatchFilterValue string 48 } 49 50 func (r *ClusterResourceSetBindingReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { 51 err := ctrl.NewControllerManagedBy(mgr). 52 For(&addonsv1.ClusterResourceSetBinding{}). 53 Watches( 54 &clusterv1.Cluster{}, 55 handler.EnqueueRequestsFromMapFunc(r.clusterToClusterResourceSetBinding), 56 ). 57 WithOptions(options). 58 WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)). 59 Complete(r) 60 if err != nil { 61 return errors.Wrap(err, "failed setting up with a controller manager") 62 } 63 64 return nil 65 } 66 67 func (r *ClusterResourceSetBindingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { 68 log := ctrl.LoggerFrom(ctx) 69 70 // Fetch the ClusterResourceSetBinding instance. 71 binding := &addonsv1.ClusterResourceSetBinding{} 72 if err := r.Client.Get(ctx, req.NamespacedName, binding); err != nil { 73 if apierrors.IsNotFound(err) { 74 // Object not found, return. Created objects are automatically garbage collected. 75 // For additional cleanup logic use finalizers. 76 return ctrl.Result{}, nil 77 } 78 // Error reading the object - requeue the request. 79 return ctrl.Result{}, err 80 } 81 if err := r.updateClusterReference(ctx, binding); err != nil { 82 return ctrl.Result{}, err 83 } 84 cluster, err := util.GetClusterByName(ctx, r.Client, req.Namespace, binding.Spec.ClusterName) 85 if err != nil { 86 if apierrors.IsNotFound(err) { 87 // If the owner cluster is already deleted, delete its ClusterResourceSetBinding 88 log.Info("deleting ClusterResourceSetBinding because the owner Cluster no longer exists") 89 return ctrl.Result{}, r.Client.Delete(ctx, binding) 90 } 91 return ctrl.Result{}, err 92 } 93 // If the owner cluster is in deletion process, delete its ClusterResourceSetBinding 94 if !cluster.DeletionTimestamp.IsZero() { 95 if feature.Gates.Enabled(feature.RuntimeSDK) && feature.Gates.Enabled(feature.ClusterTopology) { 96 if cluster.Spec.Topology != nil && !hooks.IsOkToDelete(cluster) { 97 // If the Cluster is not yet ready to be deleted then do not delete the ClusterResourceSetBinding. 98 return ctrl.Result{}, nil 99 } 100 } 101 log.Info("deleting ClusterResourceSetBinding because the owner Cluster is currently being deleted") 102 return ctrl.Result{}, r.Client.Delete(ctx, binding) 103 } 104 105 return ctrl.Result{}, nil 106 } 107 108 // clusterToClusterResourceSetBinding is mapper function that maps clusters to ClusterResourceSetBinding. 109 func (r *ClusterResourceSetBindingReconciler) clusterToClusterResourceSetBinding(_ context.Context, o client.Object) []ctrl.Request { 110 return []reconcile.Request{ 111 { 112 NamespacedName: client.ObjectKey{ 113 Namespace: o.GetNamespace(), 114 Name: o.GetName(), 115 }, 116 }, 117 } 118 } 119 120 // updateClusterReference updates how the ClusterResourceSetBinding references the Cluster. 121 // Before 1.4 cluster name was stored as an ownerReference. This function migrates the cluster name to the spec.clusterName and removes the Cluster OwnerReference. 122 // Ref: https://github.com/kubernetes-sigs/cluster-api/issues/7669. 123 func (r *ClusterResourceSetBindingReconciler) updateClusterReference(ctx context.Context, binding *addonsv1.ClusterResourceSetBinding) error { 124 patchHelper, err := patch.NewHelper(binding, r.Client) 125 if err != nil { 126 return err 127 } 128 129 // If the `.spec.clusterName` is not set, take the value from the ownerReference. 130 if binding.Spec.ClusterName == "" { 131 // Update the clusterName field of the existing ClusterResourceSetBindings with ownerReferences. 132 // More details please refer to: https://github.com/kubernetes-sigs/cluster-api/issues/7669. 133 clusterName, err := getClusterNameFromOwnerRef(binding.ObjectMeta) 134 if err != nil { 135 return err 136 } 137 binding.Spec.ClusterName = clusterName 138 } 139 140 // Remove the Cluster OwnerReference if it exists. This is a no-op if the OwnerReference does not exist. 141 // TODO: (killianmuldoon) This can be removed in CAPI v1beta2. 142 binding.OwnerReferences = util.RemoveOwnerRef(binding.OwnerReferences, metav1.OwnerReference{ 143 APIVersion: clusterv1.GroupVersion.String(), 144 Kind: "Cluster", 145 Name: binding.Spec.ClusterName, 146 }) 147 148 return patchHelper.Patch(ctx, binding) 149 }