in pkg/controllers/nodeclass/controller.go [165:201]
func (c *Controller) finalize(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error) {
stored := nodeClass.DeepCopy()
if !controllerutil.ContainsFinalizer(nodeClass, v1.TerminationFinalizer) {
return reconcile.Result{}, nil
}
nodeClaims := &karpv1.NodeClaimList{}
if err := c.kubeClient.List(ctx, nodeClaims, nodeclaimutils.ForNodeClass(nodeClass)); err != nil {
return reconcile.Result{}, fmt.Errorf("listing nodeclaims that are using nodeclass, %w", err)
}
if len(nodeClaims.Items) > 0 {
c.recorder.Publish(WaitingOnNodeClaimTerminationEvent(nodeClass, lo.Map(nodeClaims.Items, func(nc karpv1.NodeClaim, _ int) string { return nc.Name })))
return reconcile.Result{RequeueAfter: time.Minute * 10}, nil // periodically fire the event
}
if nodeClass.Spec.Role != "" {
if err := c.instanceProfileProvider.Delete(ctx, nodeClass.InstanceProfileName(options.FromContext(ctx).ClusterName, c.region)); err != nil {
return reconcile.Result{}, fmt.Errorf("deleting instance profile, %w", err)
}
}
if err := c.launchTemplateProvider.DeleteAll(ctx, nodeClass); err != nil {
return reconcile.Result{}, fmt.Errorf("deleting launch templates, %w", err)
}
controllerutil.RemoveFinalizer(nodeClass, v1.TerminationFinalizer)
if !equality.Semantic.DeepEqual(stored, nodeClass) {
// We use client.MergeFromWithOptimisticLock because patching a list with a JSON merge patch
// can cause races due to the fact that it fully replaces the list on a change
// Here, we are updating the finalizer list
// https://github.com/kubernetes/kubernetes/issues/111643#issuecomment-2016489732
if err := c.kubeClient.Patch(ctx, nodeClass, client.MergeFromWithOptions(stored, client.MergeFromWithOptimisticLock{})); err != nil {
if errors.IsConflict(err) {
return reconcile.Result{Requeue: true}, nil
}
return reconcile.Result{}, client.IgnoreNotFound(fmt.Errorf("removing termination finalizer, %w", err))
}
}
c.validation.clearCacheEntries(nodeClass)
return reconcile.Result{}, nil
}