sigs.k8s.io/cluster-api-provider-azure@v1.17.0/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/builder" 37 "sigs.k8s.io/controller-runtime/pkg/client" 38 "sigs.k8s.io/controller-runtime/pkg/handler" 39 "sigs.k8s.io/controller-runtime/pkg/reconcile" 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 return 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 // Add a watch on clusterv1.Cluster object for unpause notifications. 80 Watches( 81 &clusterv1.Cluster{}, 82 handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(ctx, infrav1.GroupVersion.WithKind(infrav1.AzureManagedClusterKind), mgr.GetClient(), &infrav1.AzureManagedCluster{})), 83 builder.WithPredicates( 84 predicates.ClusterUnpaused(log), 85 predicates.ResourceNotPausedAndHasFilterLabel(log, amcr.WatchFilterValue), 86 ), 87 ). 88 Complete(r) 89 } 90 91 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedclusters,verbs=get;list;watch;create;update;patch;delete 92 // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedclusters/status,verbs=get;update;patch 93 // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch 94 // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete 95 96 // Reconcile idempotently gets, creates, and updates a managed cluster. 97 func (amcr *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { 98 ctx, cancel := context.WithTimeout(ctx, amcr.Timeouts.DefaultedLoopTimeout()) 99 defer cancel() 100 101 ctx, log, done := tele.StartSpanWithLogger( 102 ctx, 103 "controllers.AzureManagedClusterReconciler.Reconcile", 104 tele.KVP("namespace", req.Namespace), 105 tele.KVP("name", req.Name), 106 tele.KVP("kind", infrav1.AzureManagedClusterKind), 107 ) 108 defer done() 109 110 // Fetch the AzureManagedCluster instance 111 aksCluster := &infrav1.AzureManagedCluster{} 112 err := amcr.Get(ctx, req.NamespacedName, aksCluster) 113 if err != nil { 114 if apierrors.IsNotFound(err) { 115 return reconcile.Result{}, nil 116 } 117 return reconcile.Result{}, err 118 } 119 120 // Fetch the Cluster. 121 cluster, err := util.GetOwnerCluster(ctx, amcr.Client, aksCluster.ObjectMeta) 122 if err != nil { 123 return reconcile.Result{}, err 124 } 125 if cluster == nil { 126 log.Info("Cluster Controller has not yet set OwnerRef") 127 return reconcile.Result{}, nil 128 } 129 130 controlPlane := &infrav1.AzureManagedControlPlane{} 131 controlPlaneRef := types.NamespacedName{ 132 Name: cluster.Spec.ControlPlaneRef.Name, 133 Namespace: cluster.Namespace, 134 } 135 136 log = log.WithValues("cluster", cluster.Name) 137 138 // Return early if the object or Cluster is paused. 139 if annotations.IsPaused(cluster, aksCluster) { 140 log.Info("AzureManagedCluster or linked Cluster is marked as paused. Won't reconcile") 141 return ctrl.Result{}, nil 142 } 143 144 if err := amcr.Get(ctx, controlPlaneRef, controlPlane); err != nil { 145 return reconcile.Result{}, errors.Wrap(err, "failed to get control plane ref") 146 } 147 148 log = log.WithValues("controlPlane", controlPlaneRef.Name) 149 150 patchhelper, err := patch.NewHelper(aksCluster, amcr.Client) 151 if err != nil { 152 return reconcile.Result{}, errors.Wrap(err, "failed to init patch helper") 153 } 154 155 // Infrastructure must be ready before control plane. We should also enqueue 156 // requests from control plane to infra cluster to keep control plane endpoint accurate. 157 aksCluster.Status.Ready = true 158 aksCluster.Spec.ControlPlaneEndpoint = controlPlane.Spec.ControlPlaneEndpoint 159 160 if err := patchhelper.Patch(ctx, aksCluster); err != nil { 161 return reconcile.Result{}, err 162 } 163 164 log.Info("Successfully reconciled") 165 166 return reconcile.Result{}, nil 167 }