@@ -68,10 +68,16 @@ type ProviderAdapter interface {
6868// ClaimHandler knows how to allocate and release IP addresses for a specific provider.
6969type ClaimHandler interface {
7070 // FetchPool is called to fetch the pool referenced by the claim. The pool needs to be stored by the handler.
71+ // This method is called before EnsureAddress and ReleaseAddress.
72+ // Note that the ClaimReconciler will call the ReleaseAddress method regardless whether fetching the pool was
73+ // successful or not.
7174 FetchPool (ctx context.Context ) (client.Object , * ctrl.Result , error )
7275 // EnsureAddress is called to make sure that the IPAddress.Spec is correct and the address is allocated.
76+ // It will only be called when FetchPool was successful.
7377 EnsureAddress (ctx context.Context , address * ipamv1.IPAddress ) (* ctrl.Result , error )
7478 // ReleaseAddress is called to release the ip address that was allocated for the claim.
79+ // It will be called even if FetchPool was not successful when reconciling a deleted claim, so there is no guarantee
80+ // that the claim is available in the handler.
7581 ReleaseAddress (ctx context.Context ) (* ctrl.Result , error )
7682}
7783
@@ -138,24 +144,18 @@ func (r *ClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ct
138144 cluster , err = clusterutil .GetClusterFromMetadata (ctx , r .Client , claim .ObjectMeta )
139145 }
140146 if err != nil {
141- if apierrors .IsNotFound (err ) {
142- if ! claim .DeletionTimestamp .IsZero () {
143- patch := client .MergeFrom (claim .DeepCopy ())
144- if err := r .reconcileDelete (ctx , claim ); err != nil {
145- return ctrl.Result {}, fmt .Errorf ("reconcile delete: %w" , err )
146- }
147- // we'll need to explicitly patch the claim here since we haven't set up a patch helper yet.
148- if err := r .Patch (ctx , claim , patch ); err != nil {
149- return ctrl.Result {}, fmt .Errorf ("patch after reconciling delete: %w" , err )
150- }
151- return ctrl.Result {}, nil
152- }
147+ if ! apierrors .IsNotFound (err ) {
148+ log .Error (err , "error fetching cluster linked to IPAddressClaim" )
149+ return ctrl.Result {}, err
150+ }
151+ if ! claim .ObjectMeta .DeletionTimestamp .IsZero () {
152+ // In case the claim is deleted, we'll process it even when we can't find the cluster. During cluster deletion it
153+ // can happen that the Cluster object is released before all claims are cleaned up, which would block the claims indefinitely.
154+ log .Info ("IPAddressClaim linked to a cluster that is not found, unable to determine cluster's paused state, proceeding with deletion" )
155+ } else {
153156 log .Info ("IPAddressClaim linked to a cluster that is not found, unable to determine cluster's paused state, skipping reconciliation" )
154157 return ctrl.Result {}, nil
155158 }
156-
157- log .Error (err , "error fetching cluster linked to IPAddressClaim" )
158- return ctrl.Result {}, err
159159 }
160160 if cluster != nil {
161161 if annotations .IsPaused (cluster , cluster ) {
@@ -189,8 +189,8 @@ func (r *ClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ct
189189 if apierrors .IsNotFound (err ) {
190190 err := errors .New ("pool not found" )
191191 log .Error (err , "the referenced pool could not be found" )
192- if ! claim .DeletionTimestamp .IsZero () {
193- return ctrl. Result {}, r .reconcileDelete (ctx , claim )
192+ if ! claim .ObjectMeta . DeletionTimestamp .IsZero () {
193+ return r .reconcileDelete (ctx , claim , handler )
194194 }
195195 return ctrl.Result {}, nil
196196 }
@@ -208,12 +208,8 @@ func (r *ClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ct
208208 return ctrl.Result {}, nil
209209 }
210210
211- // If the claim is marked for deletion, release the address.
212- if ! claim .DeletionTimestamp .IsZero () {
213- if res , err := handler .ReleaseAddress (ctx ); err != nil {
214- return unwrapResult (res ), err
215- }
216- return ctrl.Result {}, r .reconcileDelete (ctx , claim )
211+ if ! claim .ObjectMeta .DeletionTimestamp .IsZero () {
212+ return r .reconcileDelete (ctx , claim , handler )
217213 }
218214
219215 // We always ensure there is a valid address object passed to the handler.
@@ -263,34 +259,38 @@ func (r *ClaimReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ct
263259 return ctrl.Result {}, nil
264260}
265261
266- func (r * ClaimReconciler ) reconcileDelete (ctx context.Context , claim * ipamv1.IPAddressClaim ) error {
262+ func (r * ClaimReconciler ) reconcileDelete (ctx context.Context , claim * ipamv1.IPAddressClaim , handler ClaimHandler ) (ctrl.Result , error ) {
263+ if res , err := handler .ReleaseAddress (ctx ); err != nil {
264+ return unwrapResult (res ), fmt .Errorf ("release address: %w" , err )
265+ }
266+
267267 address := & ipamv1.IPAddress {}
268268 namespacedName := types.NamespacedName {
269269 Namespace : claim .Namespace ,
270270 Name : claim .Name ,
271271 }
272- if err := r .Get (ctx , namespacedName , address ); err != nil && ! apierrors .IsNotFound (err ) {
273- return errors .Wrap (err , "failed to fetch address" )
272+ if err := r .Client . Get (ctx , namespacedName , address ); err != nil && ! apierrors .IsNotFound (err ) {
273+ return ctrl. Result {}, errors .Wrap (err , "failed to fetch address" )
274274 }
275275
276276 if address .Name != "" {
277277 var err error
278- patch := client .MergeFrom (address .DeepCopy ())
278+ p := client .MergeFrom (address .DeepCopy ())
279279 if controllerutil .RemoveFinalizer (address , ProtectAddressFinalizer ) {
280- if err = r .Patch (ctx , address , patch ); err != nil && ! apierrors .IsNotFound (err ) {
281- return errors .Wrap (err , "failed to remove address finalizer" )
280+ if err = r .Client . Patch (ctx , address , p ); err != nil && ! apierrors .IsNotFound (err ) {
281+ return ctrl. Result {}, errors .Wrap (err , "failed to remove address finalizer" )
282282 }
283283 }
284284
285285 if err == nil {
286- if err := r .Delete (ctx , address ); err != nil && ! apierrors .IsNotFound (err ) {
287- return err
286+ if err := r .Client . Delete (ctx , address ); err != nil && ! apierrors .IsNotFound (err ) {
287+ return ctrl. Result {}, err
288288 }
289289 }
290290 }
291291
292292 controllerutil .RemoveFinalizer (claim , ReleaseAddressFinalizer )
293- return nil
293+ return ctrl. Result {}, nil
294294}
295295
296296func (r * ClaimReconciler ) clusterToIPClaims (_ context.Context , a client.Object ) []reconcile.Request {
0 commit comments