diff --git a/controllers/azurecluster_controller.go b/controllers/azurecluster_controller.go index 7614ff2890f..ae4a12df8d9 100644 --- a/controllers/azurecluster_controller.go +++ b/controllers/azurecluster_controller.go @@ -36,7 +36,6 @@ import ( "sigs.k8s.io/cluster-api/util/predicates" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -44,6 +43,7 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha4" "sigs.k8s.io/cluster-api-provider-azure/azure/scope" + "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -76,12 +76,20 @@ func NewAzureClusterReconciler(client client.Client, log logr.Logger, recorder r } // SetupWithManager initializes this controller with a manager. -func (r *AzureClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { - log := r.Log.WithValues("controller", "AzureCluster") +func (acr *AzureClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options Options) error { + ctx, span := tele.Tracer().Start(ctx, "controllers.AzureClusterReconciler.SetupWithManager") + defer span.End() + + log := acr.Log.WithValues("controller", "AzureCluster") + var r reconcile.Reconciler = acr + if options.Cache != nil { + r = coalescing.NewReconciler(acr, options.Cache, log) + } + c, err := ctrl.NewControllerManagedBy(mgr). - WithOptions(options). + WithOptions(options.Options). For(&infrav1.AzureCluster{}). - WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)). + WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), acr.WatchFilterValue)). WithEventFilter(predicates.ResourceIsNotExternallyManaged(ctrl.LoggerFrom(ctx))). Build(r) if err != nil { @@ -93,7 +101,7 @@ func (r *AzureClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl. &source.Kind{Type: &clusterv1.Cluster{}}, handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(infrav1.GroupVersion.WithKind("AzureCluster"))), predicates.ClusterUnpaused(log), - predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue), + predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), acr.WatchFilterValue), ); err != nil { return errors.Wrap(err, "failed adding a watch for ready clusters") } @@ -108,10 +116,10 @@ func (r *AzureClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl. // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureclusteridentities;azureclusteridentities/status,verbs=get;list;watch;create;update;patch;delete // Reconcile idempotently gets, creates, and updates a cluster. -func (r *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) +func (acr *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(acr.ReconcileTimeout)) defer cancel() - log := r.Log.WithValues("namespace", req.Namespace, "azureCluster", req.Name) + log := acr.Log.WithValues("namespace", req.Namespace, "azureCluster", req.Name) ctx, span := tele.Tracer().Start(ctx, "controllers.AzureClusterReconciler.Reconcile", trace.WithAttributes( @@ -123,10 +131,10 @@ func (r *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request // Fetch the AzureCluster instance azureCluster := &infrav1.AzureCluster{} - err := r.Get(ctx, req.NamespacedName, azureCluster) + err := acr.Get(ctx, req.NamespacedName, azureCluster) if err != nil { if apierrors.IsNotFound(err) { - r.Recorder.Eventf(azureCluster, corev1.EventTypeNormal, "AzureClusterObjectNotFound", err.Error()) + acr.Recorder.Eventf(azureCluster, corev1.EventTypeNormal, "AzureClusterObjectNotFound", err.Error()) log.Info("object was not found") return reconcile.Result{}, nil } @@ -134,12 +142,12 @@ func (r *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request } // Fetch the Cluster. - cluster, err := util.GetOwnerCluster(ctx, r.Client, azureCluster.ObjectMeta) + cluster, err := util.GetOwnerCluster(ctx, acr.Client, azureCluster.ObjectMeta) if err != nil { return reconcile.Result{}, err } if cluster == nil { - r.Recorder.Eventf(azureCluster, corev1.EventTypeNormal, "OwnerRefNotSet", "Cluster Controller has not yet set OwnerRef") + acr.Recorder.Eventf(azureCluster, corev1.EventTypeNormal, "OwnerRefNotSet", "Cluster Controller has not yet set OwnerRef") log.Info("Cluster Controller has not yet set OwnerRef") return reconcile.Result{}, nil } @@ -148,35 +156,35 @@ func (r *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request // Return early if the object or Cluster is paused. if annotations.IsPaused(cluster, azureCluster) { - r.Recorder.Eventf(azureCluster, corev1.EventTypeNormal, "ClusterPaused", "AzureCluster or linked Cluster is marked as paused. Won't reconcile") + acr.Recorder.Eventf(azureCluster, corev1.EventTypeNormal, "ClusterPaused", "AzureCluster or linked Cluster is marked as paused. Won't reconcile") log.Info("AzureCluster or linked Cluster is marked as paused. Won't reconcile") return ctrl.Result{}, nil } if azureCluster.Spec.IdentityRef != nil { - identity, err := GetClusterIdentityFromRef(ctx, r.Client, azureCluster.Namespace, azureCluster.Spec.IdentityRef) + identity, err := GetClusterIdentityFromRef(ctx, acr.Client, azureCluster.Namespace, azureCluster.Spec.IdentityRef) if err != nil { return reconcile.Result{}, err } - if !scope.IsClusterNamespaceAllowed(ctx, r.Client, identity.Spec.AllowedNamespaces, azureCluster.Namespace) { + if !scope.IsClusterNamespaceAllowed(ctx, acr.Client, identity.Spec.AllowedNamespaces, azureCluster.Namespace) { conditions.MarkFalse(azureCluster, infrav1.NetworkInfrastructureReadyCondition, infrav1.NamespaceNotAllowedByIdentity, clusterv1.ConditionSeverityError, "") return reconcile.Result{}, errors.New("AzureClusterIdentity list of allowed namespaces doesn't include current cluster namespace") } } else { log.Info(fmt.Sprintf("WARNING, %s", deprecatedManagerCredsWarning)) - r.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "AzureClusterIdentity", deprecatedManagerCredsWarning) + acr.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "AzureClusterIdentity", deprecatedManagerCredsWarning) } // Create the scope. clusterScope, err := scope.NewClusterScope(ctx, scope.ClusterScopeParams{ - Client: r.Client, + Client: acr.Client, Logger: log, Cluster: cluster, AzureCluster: azureCluster, }) if err != nil { err = errors.Errorf("failed to create scope: %+v", err) - r.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "CreateClusterScopeFailed", err.Error()) + acr.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "CreateClusterScopeFailed", err.Error()) return reconcile.Result{}, err } @@ -189,14 +197,14 @@ func (r *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request // Handle deleted clusters if !azureCluster.DeletionTimestamp.IsZero() { - return r.reconcileDelete(ctx, clusterScope) + return acr.reconcileDelete(ctx, clusterScope) } // Handle non-deleted clusters - return r.reconcileNormal(ctx, clusterScope) + return acr.reconcileNormal(ctx, clusterScope) } -func (r *AzureClusterReconciler) reconcileNormal(ctx context.Context, clusterScope *scope.ClusterScope) (reconcile.Result, error) { +func (acr *AzureClusterReconciler) reconcileNormal(ctx context.Context, clusterScope *scope.ClusterScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureClusterReconciler.reconcileNormal") defer span.End() @@ -210,14 +218,14 @@ func (r *AzureClusterReconciler) reconcileNormal(ctx context.Context, clusterSco return reconcile.Result{}, err } - acr, err := r.createAzureClusterService(clusterScope) + acs, err := acr.createAzureClusterService(clusterScope) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create a new AzureClusterReconciler") } - if err := acr.Reconcile(ctx); err != nil { + if err := acs.Reconcile(ctx); err != nil { wrappedErr := errors.Wrap(err, "failed to reconcile cluster services") - r.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "ClusterReconcilerNormalFailed", wrappedErr.Error()) + acr.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "ClusterReconcilerNormalFailed", wrappedErr.Error()) return reconcile.Result{}, wrappedErr } @@ -234,7 +242,7 @@ func (r *AzureClusterReconciler) reconcileNormal(ctx context.Context, clusterSco return reconcile.Result{}, nil } -func (r *AzureClusterReconciler) reconcileDelete(ctx context.Context, clusterScope *scope.ClusterScope) (reconcile.Result, error) { +func (acr *AzureClusterReconciler) reconcileDelete(ctx context.Context, clusterScope *scope.ClusterScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureClusterReconciler.reconcileDelete") defer span.End() @@ -246,14 +254,14 @@ func (r *AzureClusterReconciler) reconcileDelete(ctx context.Context, clusterSco return reconcile.Result{}, err } - acr, err := r.createAzureClusterService(clusterScope) + acs, err := acr.createAzureClusterService(clusterScope) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create a new AzureClusterReconciler") } - if err := acr.Delete(ctx); err != nil { + if err := acs.Delete(ctx); err != nil { wrappedErr := errors.Wrapf(err, "error deleting AzureCluster %s/%s", azureCluster.Namespace, azureCluster.Name) - r.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "ClusterReconcilerDeleteFailed", wrappedErr.Error()) + acr.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "ClusterReconcilerDeleteFailed", wrappedErr.Error()) conditions.MarkFalse(azureCluster, infrav1.NetworkInfrastructureReadyCondition, clusterv1.DeletionFailedReason, clusterv1.ConditionSeverityWarning, err.Error()) return reconcile.Result{}, wrappedErr } diff --git a/controllers/azuremachine_controller.go b/controllers/azuremachine_controller.go index 7afe5800a6d..00fb4fe2b6e 100644 --- a/controllers/azuremachine_controller.go +++ b/controllers/azuremachine_controller.go @@ -35,7 +35,6 @@ import ( "sigs.k8s.io/cluster-api/util/predicates" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -44,6 +43,7 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha4" "sigs.k8s.io/cluster-api-provider-azure/azure" "sigs.k8s.io/cluster-api-provider-azure/azure/scope" + "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -76,18 +76,26 @@ func NewAzureMachineReconciler(client client.Client, log logr.Logger, recorder r } // SetupWithManager initializes this controller with a manager. -func (r *AzureMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { - log := r.Log.WithValues("controller", "AzureMachine") +func (amr *AzureMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options Options) error { + ctx, span := tele.Tracer().Start(ctx, "controllers.AzureMachineReconciler.SetupWithManager") + defer span.End() + + log := amr.Log.WithValues("controller", "AzureMachine") + var r reconcile.Reconciler = amr + if options.Cache != nil { + r = coalescing.NewReconciler(amr, options.Cache, log) + } + // create mapper to transform incoming AzureClusters into AzureMachine requests - azureClusterToAzureMachinesMapper, err := AzureClusterToAzureMachinesMapper(ctx, r.Client, &infrav1.AzureMachineList{}, mgr.GetScheme(), log) + azureClusterToAzureMachinesMapper, err := AzureClusterToAzureMachinesMapper(ctx, amr.Client, &infrav1.AzureMachineList{}, mgr.GetScheme(), log) if err != nil { return errors.Wrap(err, "failed to create AzureCluster to AzureMachines mapper") } c, err := ctrl.NewControllerManagedBy(mgr). - WithOptions(options). + WithOptions(options.Options). For(&infrav1.AzureMachine{}). - WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)). + WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), amr.WatchFilterValue)). // watch for changes in CAPI Machine resources Watches( &source.Kind{Type: &clusterv1.Machine{}}, @@ -103,7 +111,7 @@ func (r *AzureMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl. return errors.Wrap(err, "error creating controller") } - azureMachineMapper, err := util.ClusterToObjectsMapper(r.Client, &infrav1.AzureMachineList{}, mgr.GetScheme()) + azureMachineMapper, err := util.ClusterToObjectsMapper(amr.Client, &infrav1.AzureMachineList{}, mgr.GetScheme()) if err != nil { return errors.Wrap(err, "failed to create mapper for Cluster to AzureMachines") } @@ -113,7 +121,7 @@ func (r *AzureMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl. &source.Kind{Type: &clusterv1.Cluster{}}, handler.EnqueueRequestsFromMapFunc(azureMachineMapper), predicates.ClusterUnpausedAndInfrastructureReady(log), - predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue), + predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), amr.WatchFilterValue), ); err != nil { return errors.Wrap(err, "failed adding a watch for ready clusters") } @@ -128,10 +136,10 @@ func (r *AzureMachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl. // +kubebuilder:rbac:groups="",resources=secrets;,verbs=get;list;watch // Reconcile idempotently gets, creates, and updates a machine. -func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) +func (amr *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(amr.ReconcileTimeout)) defer cancel() - logger := r.Log.WithValues("namespace", req.Namespace, "azureMachine", req.Name) + logger := amr.Log.WithValues("namespace", req.Namespace, "azureMachine", req.Name) ctx, span := tele.Tracer().Start(ctx, "controllers.AzureMachineReconciler.Reconcile", trace.WithAttributes( @@ -144,7 +152,7 @@ func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request // Fetch the AzureMachine VM. azureMachine := &infrav1.AzureMachine{} - err := r.Get(ctx, req.NamespacedName, azureMachine) + err := amr.Get(ctx, req.NamespacedName, azureMachine) if err != nil { if apierrors.IsNotFound(err) { return reconcile.Result{}, nil @@ -153,12 +161,12 @@ func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request } // Fetch the Machine. - machine, err := util.GetOwnerMachine(ctx, r.Client, azureMachine.ObjectMeta) + machine, err := util.GetOwnerMachine(ctx, amr.Client, azureMachine.ObjectMeta) if err != nil { return reconcile.Result{}, err } if machine == nil { - r.Recorder.Eventf(azureMachine, corev1.EventTypeNormal, "Machine controller dependency not yet met", "Machine Controller has not yet set OwnerRef") + amr.Recorder.Eventf(azureMachine, corev1.EventTypeNormal, "Machine controller dependency not yet met", "Machine Controller has not yet set OwnerRef") logger.Info("Machine Controller has not yet set OwnerRef") return reconcile.Result{}, nil } @@ -166,9 +174,9 @@ func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request logger = logger.WithValues("machine", machine.Name) // Fetch the Cluster. - cluster, err := util.GetClusterFromMetadata(ctx, r.Client, machine.ObjectMeta) + cluster, err := util.GetClusterFromMetadata(ctx, amr.Client, machine.ObjectMeta) if err != nil { - r.Recorder.Eventf(azureMachine, corev1.EventTypeNormal, "Unable to get cluster from metadata", "Machine is missing cluster label or cluster does not exist") + amr.Recorder.Eventf(azureMachine, corev1.EventTypeNormal, "Unable to get cluster from metadata", "Machine is missing cluster label or cluster does not exist") logger.Info("Machine is missing cluster label or cluster does not exist") return reconcile.Result{}, nil } @@ -186,8 +194,8 @@ func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request Name: cluster.Spec.InfrastructureRef.Name, } azureCluster := &infrav1.AzureCluster{} - if err := r.Client.Get(ctx, azureClusterName, azureCluster); err != nil { - r.Recorder.Eventf(azureMachine, corev1.EventTypeNormal, "AzureCluster unavailable", "AzureCluster is not available yet") + if err := amr.Client.Get(ctx, azureClusterName, azureCluster); err != nil { + amr.Recorder.Eventf(azureMachine, corev1.EventTypeNormal, "AzureCluster unavailable", "AzureCluster is not available yet") logger.Info("AzureCluster is not available yet") return reconcile.Result{}, nil } @@ -196,26 +204,26 @@ func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request // Create the cluster scope clusterScope, err := scope.NewClusterScope(ctx, scope.ClusterScopeParams{ - Client: r.Client, + Client: amr.Client, Logger: logger, Cluster: cluster, AzureCluster: azureCluster, }) if err != nil { - r.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "Error creating the cluster scope", err.Error()) + amr.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "Error creating the cluster scope", err.Error()) return reconcile.Result{}, err } // Create the machine scope machineScope, err := scope.NewMachineScope(scope.MachineScopeParams{ Logger: logger, - Client: r.Client, + Client: amr.Client, Machine: machine, AzureMachine: azureMachine, ClusterScope: clusterScope, }) if err != nil { - r.Recorder.Eventf(azureMachine, corev1.EventTypeWarning, "Error creating the machine scope", err.Error()) + amr.Recorder.Eventf(azureMachine, corev1.EventTypeWarning, "Error creating the machine scope", err.Error()) return reconcile.Result{}, errors.Errorf("failed to create scope: %+v", err) } @@ -228,14 +236,14 @@ func (r *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request // Handle deleted machines if !azureMachine.ObjectMeta.DeletionTimestamp.IsZero() { - return r.reconcileDelete(ctx, machineScope, clusterScope) + return amr.reconcileDelete(ctx, machineScope, clusterScope) } // Handle non-deleted machines - return r.reconcileNormal(ctx, machineScope, clusterScope) + return amr.reconcileNormal(ctx, machineScope, clusterScope) } -func (r *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineScope *scope.MachineScope, clusterScope *scope.ClusterScope) (reconcile.Result, error) { +func (amr *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineScope *scope.MachineScope, clusterScope *scope.ClusterScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureMachineReconciler.reconcileNormal") defer span.End() @@ -266,7 +274,7 @@ func (r *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineSco return reconcile.Result{}, nil } - ams, err := r.createAzureMachineService(machineScope) + ams, err := amr.createAzureMachineService(machineScope) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create azure machine service") } @@ -275,7 +283,7 @@ func (r *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineSco // This means that a VM was created and managed by this controller, but is not present anymore. // In this case, we mark it as failed and leave it to MHC for remediation if errors.As(err, &azure.VMDeletedError{}) { - r.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "VMDeleted", errors.Wrap(err, "failed to reconcile AzureMachine").Error()) + amr.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "VMDeleted", errors.Wrap(err, "failed to reconcile AzureMachine").Error()) conditions.MarkFalse(machineScope.AzureMachine, infrav1.VMRunningCondition, infrav1.VMProvisionFailedReason, clusterv1.ConditionSeverityError, err.Error()) machineScope.SetFailureReason(capierrors.UpdateMachineError) machineScope.SetFailureMessage(err) @@ -287,7 +295,7 @@ func (r *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineSco var reconcileError azure.ReconcileError if errors.As(err, &reconcileError) { if reconcileError.IsTerminal() { - r.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "ReconcileError", errors.Wrapf(err, "failed to reconcile AzureMachine").Error()) + amr.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "ReconcileError", errors.Wrapf(err, "failed to reconcile AzureMachine").Error()) machineScope.Error(err, "failed to reconcile AzureMachine", "name", machineScope.Name()) machineScope.SetFailureReason(capierrors.CreateMachineError) machineScope.SetFailureMessage(err) @@ -302,7 +310,7 @@ func (r *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineSco return reconcile.Result{RequeueAfter: reconcileError.RequeueAfter()}, nil } } - r.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "ReconcileError", errors.Wrapf(err, "failed to reconcile AzureMachine").Error()) + amr.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "ReconcileError", errors.Wrapf(err, "failed to reconcile AzureMachine").Error()) conditions.MarkFalse(machineScope.AzureMachine, infrav1.VMRunningCondition, infrav1.VMProvisionFailedReason, clusterv1.ConditionSeverityError, err.Error()) return reconcile.Result{}, errors.Wrap(err, "failed to reconcile AzureMachine") } @@ -312,7 +320,7 @@ func (r *AzureMachineReconciler) reconcileNormal(ctx context.Context, machineSco return reconcile.Result{}, nil } -func (r *AzureMachineReconciler) reconcileDelete(ctx context.Context, machineScope *scope.MachineScope, clusterScope *scope.ClusterScope) (_ reconcile.Result, reterr error) { +func (amr *AzureMachineReconciler) reconcileDelete(ctx context.Context, machineScope *scope.MachineScope, clusterScope *scope.ClusterScope) (_ reconcile.Result, reterr error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureMachineReconciler.reconcileDelete") defer span.End() @@ -332,14 +340,14 @@ func (r *AzureMachineReconciler) reconcileDelete(ctx context.Context, machineSco if ShouldDeleteIndividualResources(ctx, clusterScope) { machineScope.Info("Deleting AzureMachine") - ams, err := r.createAzureMachineService(machineScope) + ams, err := amr.createAzureMachineService(machineScope) if err != nil { reterr = errors.Wrap(err, "failed to create azure machine service") return } if err := ams.Delete(ctx); err != nil { - r.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "Error deleting AzureMachine", errors.Wrapf(err, "error deleting AzureMachine %s/%s", clusterScope.Namespace(), clusterScope.ClusterName()).Error()) + amr.Recorder.Eventf(machineScope.AzureMachine, corev1.EventTypeWarning, "Error deleting AzureMachine", errors.Wrapf(err, "error deleting AzureMachine %s/%s", clusterScope.Namespace(), clusterScope.ClusterName()).Error()) conditions.MarkFalse(machineScope.AzureMachine, infrav1.VMRunningCondition, clusterv1.DeletionFailedReason, clusterv1.ConditionSeverityWarning, err.Error()) reterr = errors.Wrapf(err, "error deleting AzureMachine %s/%s", clusterScope.Namespace(), clusterScope.ClusterName()) return diff --git a/controllers/suite_test.go b/controllers/suite_test.go index dd43a030e00..c6301409413 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -51,10 +51,10 @@ var _ = BeforeSuite(func(done Done) { testEnv = env.NewTestEnvironment() Expect(NewAzureClusterReconciler(testEnv, testEnv.Log, testEnv.GetEventRecorderFor("azurecluster-reconciler"), reconciler.DefaultLoopTimeout, ""). - SetupWithManager(context.Background(), testEnv.Manager, controller.Options{MaxConcurrentReconciles: 1})).To(Succeed()) + SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect(NewAzureMachineReconciler(testEnv, testEnv.Log, testEnv.GetEventRecorderFor("azuremachine-reconciler"), reconciler.DefaultLoopTimeout, ""). - SetupWithManager(context.Background(), testEnv.Manager, controller.Options{MaxConcurrentReconciles: 1})).To(Succeed()) + SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) // +kubebuilder:scaffold:scheme diff --git a/exp/controllers/azuremanagedcluster_controller.go b/exp/controllers/azuremanagedcluster_controller.go index 4387f4bb948..cf69fd2d1f7 100644 --- a/exp/controllers/azuremanagedcluster_controller.go +++ b/exp/controllers/azuremanagedcluster_controller.go @@ -34,12 +34,13 @@ import ( "sigs.k8s.io/cluster-api/util/predicates" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" + infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers" infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha4" + "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -54,20 +55,27 @@ type AzureManagedClusterReconciler struct { } // SetupWithManager initializes this controller with a manager. -func (r *AzureManagedClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { - log := r.Log.WithValues("controller", "AzureManagedCluster") - azManagedCluster := &infrav1exp.AzureManagedCluster{} +func (amcr *AzureManagedClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options infracontroller.Options) error { + ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedClusterReconciler.SetupWithManager") + defer span.End() + log := amcr.Log.WithValues("controller", "AzureManagedCluster") + var r reconcile.Reconciler = amcr + if options.Cache != nil { + r = coalescing.NewReconciler(amcr, options.Cache, log) + } + + azManagedCluster := &infrav1exp.AzureManagedCluster{} // create mapper to transform incoming AzureManagedControlPlanes into AzureManagedCluster requests - azureManagedControlPlaneMapper, err := AzureManagedControlPlaneToAzureManagedClusterMapper(ctx, r.Client, log) + azureManagedControlPlaneMapper, err := AzureManagedControlPlaneToAzureManagedClusterMapper(ctx, amcr.Client, log) if err != nil { return errors.Wrap(err, "failed to create AzureManagedControlPlane to AzureManagedClusters mapper") } c, err := ctrl.NewControllerManagedBy(mgr). - WithOptions(options). + WithOptions(options.Options). For(azManagedCluster). - WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)). + WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), amcr.WatchFilterValue)). // watch AzureManagedControlPlane resources Watches( &source.Kind{Type: &infrav1exp.AzureManagedControlPlane{}}, @@ -83,7 +91,7 @@ func (r *AzureManagedClusterReconciler) SetupWithManager(ctx context.Context, mg &source.Kind{Type: &clusterv1.Cluster{}}, handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(infrav1exp.GroupVersion.WithKind("AzureManagedCluster"))), predicates.ClusterUnpaused(log), - predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue), + predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), amcr.WatchFilterValue), ); err != nil { return errors.Wrap(err, "failed adding a watch for ready clusters") } @@ -96,10 +104,10 @@ func (r *AzureManagedClusterReconciler) SetupWithManager(ctx context.Context, mg // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete // Reconcile idempotently gets, creates, and updates a managed cluster. -func (r *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) +func (amcr *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(amcr.ReconcileTimeout)) defer cancel() - log := r.Log.WithValues("namespace", req.Namespace, "azureManagedCluster", req.Name) + log := amcr.Log.WithValues("namespace", req.Namespace, "azureManagedCluster", req.Name) ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedClusterReconciler.Reconcile", trace.WithAttributes( @@ -111,7 +119,7 @@ func (r *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl. // Fetch the AzureManagedCluster instance aksCluster := &infrav1exp.AzureManagedCluster{} - err := r.Get(ctx, req.NamespacedName, aksCluster) + err := amcr.Get(ctx, req.NamespacedName, aksCluster) if err != nil { if apierrors.IsNotFound(err) { return reconcile.Result{}, nil @@ -120,7 +128,7 @@ func (r *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl. } // Fetch the Cluster. - cluster, err := util.GetOwnerCluster(ctx, r.Client, aksCluster.ObjectMeta) + cluster, err := util.GetOwnerCluster(ctx, amcr.Client, aksCluster.ObjectMeta) if err != nil { return reconcile.Result{}, err } @@ -143,13 +151,13 @@ func (r *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl. return ctrl.Result{}, nil } - if err := r.Get(ctx, controlPlaneRef, controlPlane); err != nil { + if err := amcr.Get(ctx, controlPlaneRef, controlPlane); err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to get control plane ref") } log = log.WithValues("controlPlane", controlPlaneRef.Name) - patchhelper, err := patch.NewHelper(aksCluster, r.Client) + patchhelper, err := patch.NewHelper(aksCluster, amcr.Client) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to init patch helper") } diff --git a/exp/controllers/azuremanagedcontrolplane_controller.go b/exp/controllers/azuremanagedcontrolplane_controller.go index 14c4fccd8db..875b09faeba 100644 --- a/exp/controllers/azuremanagedcontrolplane_controller.go +++ b/exp/controllers/azuremanagedcontrolplane_controller.go @@ -35,7 +35,6 @@ import ( "sigs.k8s.io/cluster-api/util/predicates" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -45,6 +44,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/scope" infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers" infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha4" + "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -59,22 +59,30 @@ type AzureManagedControlPlaneReconciler struct { } // SetupWithManager initializes this controller with a manager. -func (r *AzureManagedControlPlaneReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { - log := r.Log.WithValues("controller", "AzureManagedControlPlane") +func (amcpr *AzureManagedControlPlaneReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options infracontroller.Options) error { + ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedControlPlaneReconciler.SetupWithManager") + defer span.End() + + log := amcpr.Log.WithValues("controller", "AzureManagedControlPlane") + var r reconcile.Reconciler = amcpr + if options.Cache != nil { + r = coalescing.NewReconciler(amcpr, options.Cache, log) + } + azManagedControlPlane := &infrav1exp.AzureManagedControlPlane{} // create mapper to transform incoming AzureManagedClusters into AzureManagedControlPlane requests - azureManagedClusterMapper, err := AzureManagedClusterToAzureManagedControlPlaneMapper(ctx, r.Client, log) + azureManagedClusterMapper, err := AzureManagedClusterToAzureManagedControlPlaneMapper(ctx, amcpr.Client, log) if err != nil { return errors.Wrap(err, "failed to create AzureManagedCluster to AzureManagedControlPlane mapper") } // map requests for machine pools corresponding to AzureManagedControlPlane's defaultPool back to the corresponding AzureManagedControlPlane. - azureManagedMachinePoolMapper := MachinePoolToAzureManagedControlPlaneMapFunc(ctx, r.Client, infrav1exp.GroupVersion.WithKind("AzureManagedControlPlane"), log) + azureManagedMachinePoolMapper := MachinePoolToAzureManagedControlPlaneMapFunc(ctx, amcpr.Client, infrav1exp.GroupVersion.WithKind("AzureManagedControlPlane"), log) c, err := ctrl.NewControllerManagedBy(mgr). - WithOptions(options). + WithOptions(options.Options). For(azManagedControlPlane). - WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)). + WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), amcpr.WatchFilterValue)). // watch AzureManagedCluster resources Watches( &source.Kind{Type: &infrav1exp.AzureManagedCluster{}}, @@ -95,7 +103,7 @@ func (r *AzureManagedControlPlaneReconciler) SetupWithManager(ctx context.Contex &source.Kind{Type: &clusterv1.Cluster{}}, handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(infrav1exp.GroupVersion.WithKind("AzureManagedControlPlane"))), predicates.ClusterUnpausedAndInfrastructureReady(log), - predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue), + predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), amcpr.WatchFilterValue), ); err != nil { return errors.Wrap(err, "failed adding a watch for ready clusters") } @@ -108,10 +116,10 @@ func (r *AzureManagedControlPlaneReconciler) SetupWithManager(ctx context.Contex // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch // Reconcile idempotently gets, creates, and updates a managed control plane. -func (r *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) +func (amcpr *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(amcpr.ReconcileTimeout)) defer cancel() - log := r.Log.WithValues("namespace", req.Namespace, "azureManagedControlPlane", req.Name) + log := amcpr.Log.WithValues("namespace", req.Namespace, "azureManagedControlPlane", req.Name) ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedControlPlaneReconciler.Reconcile", trace.WithAttributes( @@ -123,7 +131,7 @@ func (r *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req // Fetch the AzureManagedControlPlane instance azureControlPlane := &infrav1exp.AzureManagedControlPlane{} - err := r.Get(ctx, req.NamespacedName, azureControlPlane) + err := amcpr.Get(ctx, req.NamespacedName, azureControlPlane) if err != nil { if apierrors.IsNotFound(err) { return reconcile.Result{}, nil @@ -132,7 +140,7 @@ func (r *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req } // Fetch the Cluster. - cluster, err := util.GetOwnerCluster(ctx, r.Client, azureControlPlane.ObjectMeta) + cluster, err := util.GetOwnerCluster(ctx, amcpr.Client, azureControlPlane.ObjectMeta) if err != nil { return reconcile.Result{}, err } @@ -151,11 +159,11 @@ func (r *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req // check if the control plane's namespace is allowed for this identity and update owner references for the identity. if azureControlPlane.Spec.IdentityRef != nil { - identity, err := infracontroller.GetClusterIdentityFromRef(ctx, r.Client, azureControlPlane.Namespace, azureControlPlane.Spec.IdentityRef) + identity, err := infracontroller.GetClusterIdentityFromRef(ctx, amcpr.Client, azureControlPlane.Namespace, azureControlPlane.Spec.IdentityRef) if err != nil { return reconcile.Result{}, err } - if !scope.IsClusterNamespaceAllowed(ctx, r.Client, identity.Spec.AllowedNamespaces, azureControlPlane.Namespace) { + if !scope.IsClusterNamespaceAllowed(ctx, amcpr.Client, identity.Spec.AllowedNamespaces, azureControlPlane.Namespace) { return reconcile.Result{}, errors.New("AzureClusterIdentity list of allowed namespaces doesn't include current azure managed control plane namespace") } } else { @@ -163,12 +171,12 @@ func (r *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req warningMessage += ("Using Azure credentials from the manager environment is deprecated and will be removed in future releases. ") warningMessage += ("Please specify an AzureClusterIdentity for the AzureManagedControlPlane instead, see: https://capz.sigs.k8s.io/topics/multitenancy.html ") log.Info(fmt.Sprintf("WARNING, %s", warningMessage)) - r.Recorder.Eventf(azureControlPlane, corev1.EventTypeWarning, "AzureClusterIdentity", warningMessage) + amcpr.Recorder.Eventf(azureControlPlane, corev1.EventTypeWarning, "AzureClusterIdentity", warningMessage) } // Create the scope. mcpScope, err := scope.NewManagedControlPlaneScope(ctx, scope.ManagedControlPlaneScopeParams{ - Client: r.Client, + Client: amcpr.Client, Logger: log, Cluster: cluster, ControlPlane: azureControlPlane, @@ -187,13 +195,13 @@ func (r *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req // Handle deleted clusters if !azureControlPlane.DeletionTimestamp.IsZero() { - return r.reconcileDelete(ctx, mcpScope) + return amcpr.reconcileDelete(ctx, mcpScope) } // Handle non-deleted clusters - return r.reconcileNormal(ctx, mcpScope) + return amcpr.reconcileNormal(ctx, mcpScope) } -func (r *AzureManagedControlPlaneReconciler) reconcileNormal(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { +func (amcpr *AzureManagedControlPlaneReconciler) reconcileNormal(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedControlPlaneReconciler.reconcileNormal") defer span.End() @@ -217,7 +225,7 @@ func (r *AzureManagedControlPlaneReconciler) reconcileNormal(ctx context.Context return reconcile.Result{}, nil } -func (r *AzureManagedControlPlaneReconciler) reconcileDelete(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { +func (amcpr *AzureManagedControlPlaneReconciler) reconcileDelete(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedControlPlaneReconciler.reconcileDelete") defer span.End() diff --git a/exp/controllers/azuremanagedmachinepool_controller.go b/exp/controllers/azuremanagedmachinepool_controller.go index ac6f8a26370..d4c40fd7175 100644 --- a/exp/controllers/azuremanagedmachinepool_controller.go +++ b/exp/controllers/azuremanagedmachinepool_controller.go @@ -33,7 +33,6 @@ import ( "sigs.k8s.io/cluster-api/util/predicates" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -43,6 +42,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/scope" infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers" infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha4" + "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -75,19 +75,27 @@ func NewAzureManagedMachinePoolReconciler(client client.Client, log logr.Logger, } // SetupWithManager initializes this controller with a manager. -func (r *AzureManagedMachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { - log := r.Log.WithValues("controller", "AzureManagedMachinePool") +func (ammpr *AzureManagedMachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options infracontroller.Options) error { + ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedMachinePoolReconciler.SetupWithManager") + defer span.End() + + log := ammpr.Log.WithValues("controller", "AzureManagedMachinePool") + var r reconcile.Reconciler = ammpr + if options.Cache != nil { + r = coalescing.NewReconciler(ammpr, options.Cache, log) + } + azManagedMachinePool := &infrav1exp.AzureManagedMachinePool{} // create mapper to transform incoming AzureManagedControlPlanes into AzureManagedMachinePool requests - azureManagedControlPlaneMapper, err := AzureManagedControlPlaneToAzureManagedMachinePoolsMapper(ctx, r.Client, mgr.GetScheme(), log) + azureManagedControlPlaneMapper, err := AzureManagedControlPlaneToAzureManagedMachinePoolsMapper(ctx, ammpr.Client, mgr.GetScheme(), log) if err != nil { return errors.Wrap(err, "failed to create AzureManagedControlPlane to AzureManagedMachinePools mapper") } c, err := ctrl.NewControllerManagedBy(mgr). - WithOptions(options). + WithOptions(options.Options). For(azManagedMachinePool). - WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)). + WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), ammpr.WatchFilterValue)). // watch for changes in CAPI MachinePool resources Watches( &source.Kind{Type: &clusterv1exp.MachinePool{}}, @@ -108,7 +116,7 @@ func (r *AzureManagedMachinePoolReconciler) SetupWithManager(ctx context.Context &source.Kind{Type: &clusterv1.Cluster{}}, handler.EnqueueRequestsFromMapFunc(util.ClusterToInfrastructureMapFunc(infrav1exp.GroupVersion.WithKind("AzureManagedMachinePool"))), predicates.ClusterUnpausedAndInfrastructureReady(log), - predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue), + predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), ammpr.WatchFilterValue), ); err != nil { return errors.Wrap(err, "failed adding a watch for ready clusters") } @@ -122,10 +130,10 @@ func (r *AzureManagedMachinePoolReconciler) SetupWithManager(ctx context.Context // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=machinepools;machinepools/status,verbs=get;list;watch // Reconcile idempotently gets, creates, and updates a machine pool. -func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) +func (ammpr *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(ammpr.ReconcileTimeout)) defer cancel() - log := r.Log.WithValues("namespace", req.Namespace, "azureManagedMachinePool", req.Name) + log := ammpr.Log.WithValues("namespace", req.Namespace, "azureManagedMachinePool", req.Name) ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedMachinePoolReconciler.Reconcile", trace.WithAttributes( @@ -137,7 +145,7 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req c // Fetch the AzureManagedMachinePool instance infraPool := &infrav1exp.AzureManagedMachinePool{} - err := r.Get(ctx, req.NamespacedName, infraPool) + err := ammpr.Get(ctx, req.NamespacedName, infraPool) if err != nil { if apierrors.IsNotFound(err) { return reconcile.Result{}, nil @@ -146,7 +154,7 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req c } // Fetch the owning MachinePool. - ownerPool, err := infracontroller.GetOwnerMachinePool(ctx, r.Client, infraPool.ObjectMeta) + ownerPool, err := infracontroller.GetOwnerMachinePool(ctx, ammpr.Client, infraPool.ObjectMeta) if err != nil { return reconcile.Result{}, err } @@ -156,7 +164,7 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req c } // Fetch the Cluster. - ownerCluster, err := util.GetOwnerCluster(ctx, r.Client, ownerPool.ObjectMeta) + ownerCluster, err := util.GetOwnerCluster(ctx, ammpr.Client, ownerPool.ObjectMeta) if err != nil { return reconcile.Result{}, err } @@ -179,7 +187,7 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req c Namespace: ownerCluster.Spec.ControlPlaneRef.Namespace, Name: ownerCluster.Spec.ControlPlaneRef.Name, } - if err := r.Client.Get(ctx, controlPlaneName, controlPlane); err != nil { + if err := ammpr.Client.Get(ctx, controlPlaneName, controlPlane); err != nil { return reconcile.Result{}, err } @@ -193,7 +201,7 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req c // Create the scope. mcpScope, err := scope.NewManagedControlPlaneScope(ctx, scope.ManagedControlPlaneScopeParams{ - Client: r.Client, + Client: ammpr.Client, Logger: log, ControlPlane: controlPlane, Cluster: ownerCluster, @@ -214,14 +222,14 @@ func (r *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req c // Handle deleted clusters if !infraPool.DeletionTimestamp.IsZero() { - return r.reconcileDelete(ctx, mcpScope) + return ammpr.reconcileDelete(ctx, mcpScope) } // Handle non-deleted clusters - return r.reconcileNormal(ctx, mcpScope) + return ammpr.reconcileNormal(ctx, mcpScope) } -func (r *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { +func (ammpr *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedMachinePoolReconciler.reconcileNormal") defer span.End() @@ -234,7 +242,7 @@ func (r *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Context, return reconcile.Result{}, err } - if err := r.createAzureManagedMachinePoolService(scope).Reconcile(ctx); err != nil { + if err := ammpr.createAzureManagedMachinePoolService(scope).Reconcile(ctx); err != nil { if IsAgentPoolVMSSNotFoundError(err) { // if the underlying VMSS is not yet created, requeue for 30s in the future return reconcile.Result{ @@ -250,7 +258,7 @@ func (r *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Context, return reconcile.Result{}, nil } -func (r *AzureManagedMachinePoolReconciler) reconcileDelete(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { +func (ammpr *AzureManagedMachinePoolReconciler) reconcileDelete(ctx context.Context, scope *scope.ManagedControlPlaneScope) (reconcile.Result, error) { ctx, span := tele.Tracer().Start(ctx, "controllers.AzureManagedMachinePoolReconciler.reconcileDelete") defer span.End() @@ -261,7 +269,7 @@ func (r *AzureManagedMachinePoolReconciler) reconcileDelete(ctx context.Context, // So, remove the finalizer. controllerutil.RemoveFinalizer(scope.InfraMachinePool, infrav1.ClusterFinalizer) } else { - if err := r.createAzureManagedMachinePoolService(scope).Delete(ctx); err != nil { + if err := ammpr.createAzureManagedMachinePoolService(scope).Delete(ctx); err != nil { return reconcile.Result{}, errors.Wrapf(err, "error deleting AzureManagedMachinePool %s/%s", scope.InfraMachinePool.Namespace, scope.InfraMachinePool.Name) } // Machine pool successfully deleted, remove the finalizer. diff --git a/exp/controllers/suite_test.go b/exp/controllers/suite_test.go index c908a62d886..0f5add3d1a4 100644 --- a/exp/controllers/suite_test.go +++ b/exp/controllers/suite_test.go @@ -55,16 +55,16 @@ var _ = BeforeSuite(func(done Done) { Client: testEnv, Log: testEnv.Log, Recorder: testEnv.GetEventRecorderFor("azuremanagedcluster-reconciler"), - }).SetupWithManager(context.Background(), testEnv.Manager, controller.Options{MaxConcurrentReconciles: 1})).To(Succeed()) + }).SetupWithManager(context.Background(), testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect((&AzureManagedControlPlaneReconciler{ Client: testEnv, Log: testEnv.Log, Recorder: testEnv.GetEventRecorderFor("azuremanagedcontrolplane-reconciler"), - }).SetupWithManager(context.Background(), testEnv.Manager, controller.Options{MaxConcurrentReconciles: 1})).To(Succeed()) + }).SetupWithManager(context.Background(), testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect(NewAzureManagedMachinePoolReconciler(testEnv, testEnv.Log, testEnv.GetEventRecorderFor("azuremanagedmachinepool-reconciler"), - reconciler.DefaultLoopTimeout, "").SetupWithManager(context.Background(), testEnv.Manager, controller.Options{MaxConcurrentReconciles: 1})).To(Succeed()) + reconciler.DefaultLoopTimeout, "").SetupWithManager(context.Background(), testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect(NewAzureMachinePoolReconciler(testEnv, testEnv.Log, testEnv.GetEventRecorderFor("azuremachinepool-reconciler"), reconciler.DefaultLoopTimeout, "").SetupWithManager(context.Background(), testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) diff --git a/main.go b/main.go index 2297219ab82..ac5df902985 100644 --- a/main.go +++ b/main.go @@ -103,6 +103,7 @@ var ( azureMachineConcurrency int azureMachinePoolConcurrency int azureMachinePoolMachineConcurrency int + debouncingTimer time.Duration syncPeriod time.Duration healthAddr string webhookPort int @@ -197,6 +198,12 @@ func InitFlags(fs *pflag.FlagSet) { 10, "Number of AzureMachinePoolMachines to process simultaneously") + fs.DurationVar(&debouncingTimer, + "debouncing-timer", + 10*time.Second, + "The minimum interval the controller should wait after a successful reconciliation of a particular object before reconciling it again", + ) + fs.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, @@ -296,18 +303,10 @@ func main() { } registerControllers(ctx, mgr) - // +kubebuilder:scaffold:builder - if err := mgr.AddReadyzCheck("webhook", mgr.GetWebhookServer().StartedChecker()); err != nil { - setupLog.Error(err, "unable to create ready check") - os.Exit(1) - } - - if err := mgr.AddHealthzCheck("webhook", mgr.GetWebhookServer().StartedChecker()); err != nil { - setupLog.Error(err, "unable to create health check") - os.Exit(1) - } + registerWebhooks(ctx, mgr) + // +kubebuilder:scaffold:builder setupLog.Info("starting manager", "version", version.Get().String()) if err := mgr.Start(ctx); err != nil { setupLog.Error(err, "problem running manager") @@ -316,22 +315,30 @@ func main() { } func registerControllers(ctx context.Context, mgr manager.Manager) { + machineCache, err := coalescing.NewRequestCache(debouncingTimer) + if err != nil { + setupLog.Error(err, "failed to build machineCache ReconcileCache") + } if err := controllers.NewAzureMachineReconciler(mgr.GetClient(), ctrl.Log.WithName("controllers").WithName("AzureMachine"), mgr.GetEventRecorderFor("azuremachine-reconciler"), reconcileTimeout, watchFilterValue, - ).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}); err != nil { + ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}, Cache: machineCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureMachine") os.Exit(1) } + clusterCache, err := coalescing.NewRequestCache(debouncingTimer) + if err != nil { + setupLog.Error(err, "failed to build clusterCache ReconcileCache") + } if err := controllers.NewAzureClusterReconciler( mgr.GetClient(), ctrl.Log.WithName("controllers").WithName("AzureCluster"), mgr.GetEventRecorderFor("azurecluster-reconciler"), reconcileTimeout, watchFilterValue, - ).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { + ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}, Cache: clusterCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureCluster") os.Exit(1) } @@ -372,7 +379,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { // just use CAPI MachinePool feature flag rather than create a new one setupLog.V(1).Info(fmt.Sprintf("%+v\n", feature.Gates)) if feature.Gates.Enabled(capifeature.MachinePool) { - mpCache, err := coalescing.NewRequestCache(20 * time.Second) + mpCache, err := coalescing.NewRequestCache(debouncingTimer) if err != nil { setupLog.Error(err, "failed to build mpCache ReconcileCache") } @@ -388,7 +395,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { os.Exit(1) } - mpmCache, err := coalescing.NewRequestCache(10 * time.Second) + mpmCache, err := coalescing.NewRequestCache(debouncingTimer) if err != nil { setupLog.Error(err, "failed to build mpmCache ReconcileCache") } @@ -414,42 +421,60 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { setupLog.Error(err, "unable to create controller", "controller", "AzureJSONMachinePool") os.Exit(1) } + if feature.Gates.Enabled(feature.AKS) { + mmpmCache, err := coalescing.NewRequestCache(debouncingTimer) + if err != nil { + setupLog.Error(err, "failed to build mmpmCache ReconcileCache") + } + if err := infrav1controllersexp.NewAzureManagedMachinePoolReconciler( mgr.GetClient(), ctrl.Log.WithName("controllers").WithName("AzureManagedMachinePool"), - mgr.GetEventRecorderFor("azuremachine-reconciler"), + mgr.GetEventRecorderFor("azuremanagedmachinepoolmachine-reconciler"), reconcileTimeout, watchFilterValue, - ).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}); err != nil { + ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureMachinePoolConcurrency}, Cache: mmpmCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureManagedMachinePool") os.Exit(1) } + mcCache, err := coalescing.NewRequestCache(debouncingTimer) + if err != nil { + setupLog.Error(err, "failed to build mcCache ReconcileCache") + } + if err := (&infrav1controllersexp.AzureManagedClusterReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("AzureManagedCluster"), Recorder: mgr.GetEventRecorderFor("azuremanagedcluster-reconciler"), ReconcileTimeout: reconcileTimeout, WatchFilterValue: watchFilterValue, - }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { + }).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}, Cache: mcCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureManagedCluster") os.Exit(1) } + mcpCache, err := coalescing.NewRequestCache(debouncingTimer) + if err != nil { + setupLog.Error(err, "failed to build mcpCache ReconcileCache") + } + if err := (&infrav1controllersexp.AzureManagedControlPlaneReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("AzureManagedControlPlane"), Recorder: mgr.GetEventRecorderFor("azuremanagedcontrolplane-reconciler"), ReconcileTimeout: reconcileTimeout, WatchFilterValue: watchFilterValue, - }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { + }).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}, Cache: mcpCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureManagedControlPlane") os.Exit(1) } } } +} +func registerWebhooks(ctx context.Context, mgr manager.Manager) { if err := (&infrav1alpha4.AzureCluster{}).SetupWebhookWithManager(mgr); err != nil { setupLog.Error(err, "unable to create webhook", "webhook", "AzureCluster") os.Exit(1) @@ -508,11 +533,4 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { setupLog.Error(err, "unable to create health check") os.Exit(1) } - - // +kubebuilder:scaffold:builder - setupLog.Info("starting manager", "version", version.Get().String()) - if err := mgr.Start(ctx); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } }