github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/operators/labeller/rbac.go (about)

     1  package labeller
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver"
     9  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/queueinformer"
    10  	"github.com/sirupsen/logrus"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"k8s.io/apimachinery/pkg/labels"
    13  )
    14  
    15  func hasHashLabel(obj metav1.Object) bool {
    16  	_, ok := obj.GetLabels()[resolver.ContentHashLabelKey]
    17  	return ok
    18  }
    19  
    20  func ContentHashLabeler[T metav1.Object, A ApplyConfig[A]](
    21  	ctx context.Context,
    22  	logger *logrus.Logger,
    23  	check func(metav1.Object) bool,
    24  	hasher func(object T) (string, error),
    25  	list func(options labels.Selector) ([]T, error),
    26  	applyConfigFor func(name, namespace string) A,
    27  	apply func(namespace string, ctx context.Context, cfg A, opts metav1.ApplyOptions) (T, error),
    28  ) func(done func() bool) queueinformer.LegacySyncHandler {
    29  	return func(done func() bool) queueinformer.LegacySyncHandler {
    30  		return func(obj interface{}) error {
    31  			cast, ok := obj.(T)
    32  			if !ok {
    33  				err := fmt.Errorf("wrong type %T, expected %T: %#v", obj, new(T), obj)
    34  				logger.WithError(err).Error("casting failed")
    35  				return fmt.Errorf("casting failed: %w", err)
    36  			}
    37  
    38  			if !check(cast) || hasHashLabel(cast) {
    39  				// if the object we're processing does not need us to label it, it's possible that every object that requires
    40  				// the label already has it; in which case we should exit the process, so the Pod that succeeds us can filter
    41  				// the informers used to drive the controller and stop having to track extraneous objects
    42  				items, err := list(labels.Everything())
    43  				if err != nil {
    44  					logger.WithError(err).Warn("failed to list all objects to check for labelling completion")
    45  					return nil
    46  				}
    47  				gvrFullyLabelled := true
    48  				for _, item := range items {
    49  					gvrFullyLabelled = gvrFullyLabelled && (!check(item) || hasLabel(item))
    50  				}
    51  				if gvrFullyLabelled {
    52  					allObjectsLabelled := done()
    53  					if allObjectsLabelled {
    54  						logrus.Info("detected that every object is labelled, exiting to re-start the process...")
    55  						os.Exit(0)
    56  					}
    57  				}
    58  				return nil
    59  			}
    60  
    61  			hash, err := hasher(cast)
    62  			if err != nil {
    63  				return fmt.Errorf("failed to calculate hash: %w", err)
    64  			}
    65  
    66  			logger.WithFields(logrus.Fields{"namespace": cast.GetNamespace(), "name": cast.GetName()}).Info("applying content hash label")
    67  			cfg := applyConfigFor(cast.GetName(), cast.GetNamespace())
    68  			cfg.WithLabels(map[string]string{
    69  				resolver.ContentHashLabelKey: hash,
    70  			})
    71  			_, err = apply(cast.GetNamespace(), ctx, cfg, metav1.ApplyOptions{FieldManager: "olm-hash-labeller"})
    72  			return err
    73  		}
    74  	}
    75  }