sigs.k8s.io/cluster-api-provider-azure@v1.14.3/controllers/azuremanagedcluster_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 "k8s.io/apimachinery/pkg/types" 25 "k8s.io/client-go/tools/record" 26 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 27 "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" 28 "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" 29 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 30 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 31 "sigs.k8s.io/cluster-api/util" 32 "sigs.k8s.io/cluster-api/util/annotations" 33 "sigs.k8s.io/cluster-api/util/patch" 34 "sigs.k8s.io/cluster-api/util/predicates" 35 ctrl "sigs.k8s.io/controller-runtime" 36 "sigs.k8s.io/controller-runtime/pkg/client" 37 "sigs.k8s.io/controller-runtime/pkg/handler" 38 "sigs.k8s.io/controller-runtime/pkg/reconcile" 39 "sigs.k8s.io/controller-runtime/pkg/source" 40 ) 41 42 // AzureManagedClusterReconciler reconciles an AzureManagedCluster object. 43 type AzureManagedClusterReconciler struct { 44 client.Client 45 Recorder record.EventRecorder 46 Timeouts reconciler.Timeouts 47 WatchFilterValue string 48 } 49 50 // SetupWithManager initializes this controller with a manager. 51 func (amcr *AzureManagedClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options Options) error { 52 ctx, log, done := tele.StartSpanWithLogger(ctx, 53 "controllers.AzureManagedClusterReconciler.SetupWithManager", 54 tele.KVP("controller", "AzureManagedCluster"), 55 ) 56 defer done() 57 58 var r reconcile.Reconciler = amcr 59 if options.Cache != nil { 60 r = coalescing.NewReconciler(amcr, options.Cache, log) 61 } 62 63 azManagedCluster := &infrav1.AzureManagedCluster{} 64 // create mapper to transform incoming AzureManagedControlPlanes into AzureManagedCluster requests 65 azureManagedControlPlaneMapper, err := AzureManagedControlPlaneToAzureManagedClusterMapper(ctx, amcr.Client, log) 66 if err != nil { 67 return errors.Wrap(err, "failed to create AzureManagedControlPlane to AzureManagedClusters mapper") 68 } 69 70 c, err := ctrl.NewControllerManagedBy(mgr). 71 WithOptions(options.Options). 72 For(azManagedCluster). 73 WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(log, amcr.WatchFilterValue)). 74 // watch AzureManagedControlPlane resources 75 Watches( 76 &infrav1.AzureManagedControlPlane{}, 77 handler.EnqueueRequestsFromMapFunc(azureManagedControlPlaneMapper), 78 ). 79 Build(r) 80 if err != nil { 81 return errors.Wrap(err, "error creating controller") 82 } 83 84 // Add a watch on clusterv1.Cluster object for unpause notifications. 85 if err = c.Watch( 86 source.Kind(mgr.GetCache(), &clusterv1.Cluster{}), 87 handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(ctx, infrav1.GroupVersion.WithKind(infrav1.AzureManagedClusterKind), mgr.GetClient(), &infrav1.AzureManagedCluster{})), 88 predicates.ClusterUnpaused(log), 89 predicates.ResourceNotPausedAndHasFilterLabel(log, amcr.WatchFilterValue), 90 ); err != nil { 91 return errors.Wrap(err, "failed adding a watch for ready clusters") 92 } 93 return nil 94 } 95 96 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedclusters,verbs=get;list;watch;create;update;patch;delete 97 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedclusters/status,verbs=get;update;patch 98 // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch 99 // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete 100 101 // Reconcile idempotently gets, creates, and updates a managed cluster. 102 func (amcr *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { 103 ctx, cancel := context.WithTimeout(ctx, amcr.Timeouts.DefaultedLoopTimeout()) 104 defer cancel() 105 106 ctx, log, done := tele.StartSpanWithLogger( 107 ctx, 108 "controllers.AzureManagedClusterReconciler.Reconcile", 109 tele.KVP("namespace", req.Namespace), 110 tele.KVP("name", req.Name), 111 tele.KVP("kind", infrav1.AzureManagedClusterKind), 112 ) 113 defer done() 114 115 // Fetch the AzureManagedCluster instance 116 aksCluster := &infrav1.AzureManagedCluster{} 117 err := amcr.Get(ctx, req.NamespacedName, aksCluster) 118 if err != nil { 119 if apierrors.IsNotFound(err) { 120 return reconcile.Result{}, nil 121 } 122 return reconcile.Result{}, err 123 } 124 125 // Fetch the Cluster. 126 cluster, err := util.GetOwnerCluster(ctx, amcr.Client, aksCluster.ObjectMeta) 127 if err != nil { 128 return reconcile.Result{}, err 129 } 130 if cluster == nil { 131 log.Info("Cluster Controller has not yet set OwnerRef") 132 return reconcile.Result{}, nil 133 } 134 135 controlPlane := &infrav1.AzureManagedControlPlane{} 136 controlPlaneRef := types.NamespacedName{ 137 Name: cluster.Spec.ControlPlaneRef.Name, 138 Namespace: cluster.Namespace, 139 } 140 141 log = log.WithValues("cluster", cluster.Name) 142 143 // Return early if the object or Cluster is paused. 144 if annotations.IsPaused(cluster, aksCluster) { 145 log.Info("AzureManagedCluster or linked Cluster is marked as paused. Won't reconcile") 146 return ctrl.Result{}, nil 147 } 148 149 if err := amcr.Get(ctx, controlPlaneRef, controlPlane); err != nil { 150 return reconcile.Result{}, errors.Wrap(err, "failed to get control plane ref") 151 } 152 153 log = log.WithValues("controlPlane", controlPlaneRef.Name) 154 155 patchhelper, err := patch.NewHelper(aksCluster, amcr.Client) 156 if err != nil { 157 return reconcile.Result{}, errors.Wrap(err, "failed to init patch helper") 158 } 159 160 // Infrastructure must be ready before control plane. We should also enqueue 161 // requests from control plane to infra cluster to keep control plane endpoint accurate. 162 aksCluster.Status.Ready = true 163 aksCluster.Spec.ControlPlaneEndpoint = controlPlane.Spec.ControlPlaneEndpoint 164 165 if err := patchhelper.Patch(ctx, aksCluster); err != nil { 166 return reconcile.Result{}, err 167 } 168 169 log.Info("Successfully reconciled") 170 171 return reconcile.Result{}, nil 172 }