...

Source file src/sigs.k8s.io/controller-runtime/pkg/finalizer/finalizer.go

Documentation: sigs.k8s.io/controller-runtime/pkg/finalizer

     1  /*
     2  Copyright 2021 The Kubernetes Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6      http://www.apache.org/licenses/LICENSE-2.0
     7  Unless required by applicable law or agreed to in writing, software
     8  distributed under the License is distributed on an "AS IS" BASIS,
     9  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  See the License for the specific language governing permissions and
    11  limitations under the License.
    12  */
    13  
    14  package finalizer
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  
    20  	kerrors "k8s.io/apimachinery/pkg/util/errors"
    21  	"sigs.k8s.io/controller-runtime/pkg/client"
    22  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    23  )
    24  
    25  type finalizers map[string]Finalizer
    26  
    27  // Result struct holds information about what parts of an object were updated by finalizer(s).
    28  type Result struct {
    29  	// Updated will be true if at least one of the object's non-status field
    30  	// was updated by some registered finalizer.
    31  	Updated bool
    32  	// StatusUpdated will be true if at least one of the object's status' fields
    33  	// was updated by some registered finalizer.
    34  	StatusUpdated bool
    35  }
    36  
    37  // NewFinalizers returns the Finalizers interface.
    38  func NewFinalizers() Finalizers {
    39  	return finalizers{}
    40  }
    41  
    42  func (f finalizers) Register(key string, finalizer Finalizer) error {
    43  	if _, ok := f[key]; ok {
    44  		return fmt.Errorf("finalizer for key %q already registered", key)
    45  	}
    46  	f[key] = finalizer
    47  	return nil
    48  }
    49  
    50  func (f finalizers) Finalize(ctx context.Context, obj client.Object) (Result, error) {
    51  	var (
    52  		res     Result
    53  		errList []error
    54  	)
    55  	res.Updated = false
    56  	for key, finalizer := range f {
    57  		if dt := obj.GetDeletionTimestamp(); dt.IsZero() && !controllerutil.ContainsFinalizer(obj, key) {
    58  			controllerutil.AddFinalizer(obj, key)
    59  			res.Updated = true
    60  		} else if !dt.IsZero() && controllerutil.ContainsFinalizer(obj, key) {
    61  			finalizerRes, err := finalizer.Finalize(ctx, obj)
    62  			if err != nil {
    63  				// Even when the finalizer fails, it may need to signal to update the primary
    64  				// object (e.g. it may set a condition and need a status update).
    65  				res.Updated = res.Updated || finalizerRes.Updated
    66  				res.StatusUpdated = res.StatusUpdated || finalizerRes.StatusUpdated
    67  				errList = append(errList, fmt.Errorf("finalizer %q failed: %w", key, err))
    68  			} else {
    69  				// If the finalizer succeeds, we remove the finalizer from the primary
    70  				// object's metadata, so we know it will need an update.
    71  				res.Updated = true
    72  				controllerutil.RemoveFinalizer(obj, key)
    73  				// The finalizer may have updated the status too.
    74  				res.StatusUpdated = res.StatusUpdated || finalizerRes.StatusUpdated
    75  			}
    76  		}
    77  	}
    78  	return res, kerrors.NewAggregate(errList)
    79  }
    80  

View as plain text