knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/controller/controller.go (about)

     1  /*
     2  Copyright 2018 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package controller
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/google/uuid"
    27  	"golang.org/x/sync/errgroup"
    28  
    29  	"go.uber.org/zap"
    30  	"go.uber.org/zap/zapcore"
    31  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/runtime/schema"
    34  	"k8s.io/apimachinery/pkg/types"
    35  	"k8s.io/apimachinery/pkg/util/runtime"
    36  	"k8s.io/apimachinery/pkg/util/wait"
    37  	"k8s.io/client-go/tools/cache"
    38  	"k8s.io/client-go/tools/record"
    39  	"k8s.io/client-go/util/workqueue"
    40  
    41  	"knative.dev/pkg/kmeta"
    42  	kle "knative.dev/pkg/leaderelection"
    43  	"knative.dev/pkg/logging"
    44  	"knative.dev/pkg/logging/logkey"
    45  	"knative.dev/pkg/reconciler"
    46  	"knative.dev/pkg/tracker"
    47  )
    48  
    49  const (
    50  	// DefaultResyncPeriod is the default duration that is used when no
    51  	// resync period is associated with a controllers initialization context.
    52  	DefaultResyncPeriod = 10 * time.Hour
    53  )
    54  
    55  // DefaultThreadsPerController is the number of threads to use
    56  // when processing the controller's workqueue.  Controller binaries
    57  // may adjust this process-wide default.  For finer control, invoke
    58  // Run on the controller directly.
    59  // TODO rename the const to Concurrency and deprecated this
    60  var DefaultThreadsPerController = 2
    61  
    62  // Reconciler is the interface that controller implementations are expected
    63  // to implement, so that the shared controller.Impl can drive work through it.
    64  type Reconciler interface {
    65  	Reconcile(ctx context.Context, key string) error
    66  }
    67  
    68  // PassNew makes it simple to create an UpdateFunc for use with
    69  // cache.ResourceEventHandlerFuncs that can delegate the same methods
    70  // as AddFunc/DeleteFunc but passing through only the second argument
    71  // (which is the "new" object).
    72  func PassNew(f func(interface{})) func(interface{}, interface{}) {
    73  	return func(first, second interface{}) {
    74  		f(second)
    75  	}
    76  }
    77  
    78  // HandleAll wraps the provided handler function into a cache.ResourceEventHandler
    79  // that sends all events to the given handler.  For Updates, only the new object
    80  // is forwarded.
    81  func HandleAll(h func(interface{})) cache.ResourceEventHandler {
    82  	return cache.ResourceEventHandlerFuncs{
    83  		AddFunc:    h,
    84  		UpdateFunc: PassNew(h),
    85  		DeleteFunc: h,
    86  	}
    87  }
    88  
    89  // Filter makes it simple to create FilterFunc's for use with
    90  // cache.FilteringResourceEventHandler that filter based on the
    91  // schema.GroupVersionKind of the controlling resources.
    92  //
    93  // Deprecated: Use FilterGroupVersionKind or FilterGroupKind instead
    94  func Filter(gvk schema.GroupVersionKind) func(obj interface{}) bool {
    95  	return FilterGroupVersionKind(gvk)
    96  }
    97  
    98  // FilterGroupVersionKind makes it simple to create FilterFunc's for use with
    99  // cache.FilteringResourceEventHandler that filter based on the
   100  // schema.GroupVersionKind of the controlling resources.
   101  //
   102  // Deprecated: Use FilterControllerGVK instead.
   103  func FilterGroupVersionKind(gvk schema.GroupVersionKind) func(obj interface{}) bool {
   104  	return FilterControllerGVK(gvk)
   105  }
   106  
   107  // FilterControllerGVK makes it simple to create FilterFunc's for use with
   108  // cache.FilteringResourceEventHandler that filter based on the
   109  // schema.GroupVersionKind of the controlling resources.
   110  func FilterControllerGVK(gvk schema.GroupVersionKind) func(obj interface{}) bool {
   111  	return func(obj interface{}) bool {
   112  		object, ok := obj.(metav1.Object)
   113  		if !ok {
   114  			return false
   115  		}
   116  
   117  		owner := metav1.GetControllerOf(object)
   118  		return owner != nil &&
   119  			owner.APIVersion == gvk.GroupVersion().String() &&
   120  			owner.Kind == gvk.Kind
   121  	}
   122  }
   123  
   124  // FilterGroupKind makes it simple to create FilterFunc's for use with
   125  // cache.FilteringResourceEventHandler that filter based on the
   126  // schema.GroupKind of the controlling resources.
   127  //
   128  // Deprecated: Use FilterControllerGK instead
   129  func FilterGroupKind(gk schema.GroupKind) func(obj interface{}) bool {
   130  	return FilterControllerGK(gk)
   131  }
   132  
   133  // FilterControllerGK makes it simple to create FilterFunc's for use with
   134  // cache.FilteringResourceEventHandler that filter based on the
   135  // schema.GroupKind of the controlling resources.
   136  func FilterControllerGK(gk schema.GroupKind) func(obj interface{}) bool {
   137  	return func(obj interface{}) bool {
   138  		object, ok := obj.(metav1.Object)
   139  		if !ok {
   140  			return false
   141  		}
   142  
   143  		owner := metav1.GetControllerOf(object)
   144  		if owner == nil {
   145  			return false
   146  		}
   147  
   148  		ownerGV, err := schema.ParseGroupVersion(owner.APIVersion)
   149  		return err == nil &&
   150  			ownerGV.Group == gk.Group &&
   151  			owner.Kind == gk.Kind
   152  	}
   153  }
   154  
   155  // FilterController makes it simple to create FilterFunc's for use with
   156  // cache.FilteringResourceEventHandler that filter based on the
   157  // controlling resource.
   158  func FilterController(r kmeta.OwnerRefable) func(obj interface{}) bool {
   159  	return FilterControllerGK(r.GetGroupVersionKind().GroupKind())
   160  }
   161  
   162  // FilterWithName makes it simple to create FilterFunc's for use with
   163  // cache.FilteringResourceEventHandler that filter based on a name.
   164  func FilterWithName(name string) func(obj interface{}) bool {
   165  	return func(obj interface{}) bool {
   166  		if object, ok := obj.(metav1.Object); ok {
   167  			return name == object.GetName()
   168  		}
   169  		return false
   170  	}
   171  }
   172  
   173  // FilterWithNameAndNamespace makes it simple to create FilterFunc's for use with
   174  // cache.FilteringResourceEventHandler that filter based on a namespace and a name.
   175  func FilterWithNameAndNamespace(namespace, name string) func(obj interface{}) bool {
   176  	return func(obj interface{}) bool {
   177  		if object, ok := obj.(metav1.Object); ok {
   178  			return name == object.GetName() &&
   179  				namespace == object.GetNamespace()
   180  		}
   181  		return false
   182  	}
   183  }
   184  
   185  // Impl is our core controller implementation.  It handles queuing and feeding work
   186  // from the queue to an implementation of Reconciler.
   187  type Impl struct {
   188  	// Name is the unique name for this controller workqueue within this process.
   189  	// This is used for surfacing metrics, and per-controller leader election.
   190  	Name string
   191  
   192  	// Reconciler is the workhorse of this controller, it is fed the keys
   193  	// from the workqueue to process.  Public for testing.
   194  	Reconciler Reconciler
   195  
   196  	// workQueue is a rate-limited two-lane work queue.
   197  	// This is used to queue work to be processed instead of performing it as
   198  	// soon as a change happens. This means we can ensure we only process a
   199  	// fixed amount of resources at a time, and makes it easy to ensure we are
   200  	// never processing the same item simultaneously in two different workers.
   201  	// The slow queue is used for global resync and other background processes
   202  	// which are not required to complete at the highest priority.
   203  	workQueue *twoLaneRateLimitingQueue
   204  
   205  	// Concurrency - The number of workers to use when processing the controller's workqueue.
   206  	Concurrency int
   207  
   208  	// Sugared logger is easier to use but is not as performant as the
   209  	// raw logger. In performance critical paths, call logger.Desugar()
   210  	// and use the returned raw logger instead. In addition to the
   211  	// performance benefits, raw logger also preserves type-safety at
   212  	// the expense of slightly greater verbosity.
   213  	logger *zap.SugaredLogger
   214  
   215  	// Tracker allows reconcilers to associate a reference with particular key,
   216  	// such that when the reference changes the key is queued for reconciliation.
   217  	Tracker tracker.Interface
   218  }
   219  
   220  // ControllerOptions encapsulates options for creating a new controller,
   221  // including throttling and stats behavior.
   222  type ControllerOptions struct {
   223  	WorkQueueName string
   224  	Logger        *zap.SugaredLogger
   225  	RateLimiter   workqueue.TypedRateLimiter[any]
   226  	Concurrency   int
   227  }
   228  
   229  // NewContext instantiates an instance of our controller that will feed work to the
   230  // provided Reconciler as it is enqueued.
   231  func NewContext(ctx context.Context, r Reconciler, options ControllerOptions) *Impl {
   232  	if options.RateLimiter == nil {
   233  		options.RateLimiter = workqueue.DefaultTypedControllerRateLimiter[any]()
   234  	}
   235  	if options.Concurrency == 0 {
   236  		options.Concurrency = DefaultThreadsPerController
   237  	}
   238  	i := &Impl{
   239  		Name:        options.WorkQueueName,
   240  		Reconciler:  r,
   241  		workQueue:   newTwoLaneWorkQueue(options.WorkQueueName, options.RateLimiter),
   242  		logger:      options.Logger,
   243  		Concurrency: options.Concurrency,
   244  	}
   245  
   246  	if t := GetTracker(ctx); t != nil {
   247  		i.Tracker = t
   248  	} else {
   249  		i.Tracker = tracker.New(i.EnqueueKey, GetTrackerLease(ctx))
   250  	}
   251  
   252  	return i
   253  }
   254  
   255  // WorkQueue permits direct access to the work queue.
   256  func (c *Impl) WorkQueue() workqueue.TypedRateLimitingInterface[any] {
   257  	return c.workQueue
   258  }
   259  
   260  // EnqueueAfter takes a resource, converts it into a namespace/name string,
   261  // and passes it to EnqueueKey.
   262  func (c *Impl) EnqueueAfter(obj interface{}, after time.Duration) {
   263  	object, err := kmeta.DeletionHandlingAccessor(obj)
   264  	if err != nil {
   265  		c.logger.Errorw("EnqueueAfter", zap.Error(err))
   266  		return
   267  	}
   268  	c.EnqueueKeyAfter(types.NamespacedName{Namespace: object.GetNamespace(), Name: object.GetName()}, after)
   269  }
   270  
   271  // EnqueueSlowKey takes a resource, converts it into a namespace/name string,
   272  // and enqueues that key in the slow lane.
   273  func (c *Impl) EnqueueSlowKey(key types.NamespacedName) {
   274  	c.workQueue.AddSlow(key)
   275  
   276  	if logger := c.logger.Desugar(); logger.Core().Enabled(zapcore.DebugLevel) {
   277  		logger.Debug(fmt.Sprintf("Adding to the slow queue %s (depth(total/slow): %d/%d)",
   278  			safeKey(key), c.workQueue.Len(), c.workQueue.SlowLen()),
   279  			zap.String(logkey.Key, key.String()))
   280  	}
   281  }
   282  
   283  // EnqueueSlow extracts namespaced name from the object and enqueues it on the slow
   284  // work queue.
   285  func (c *Impl) EnqueueSlow(obj interface{}) {
   286  	object, err := kmeta.DeletionHandlingAccessor(obj)
   287  	if err != nil {
   288  		c.logger.Errorw("EnqueueSlow", zap.Error(err))
   289  		return
   290  	}
   291  	key := types.NamespacedName{Namespace: object.GetNamespace(), Name: object.GetName()}
   292  	c.EnqueueSlowKey(key)
   293  }
   294  
   295  // Enqueue takes a resource, converts it into a namespace/name string,
   296  // and passes it to EnqueueKey.
   297  func (c *Impl) Enqueue(obj interface{}) {
   298  	object, err := kmeta.DeletionHandlingAccessor(obj)
   299  	if err != nil {
   300  		c.logger.Errorw("Enqueue", zap.Error(err))
   301  		return
   302  	}
   303  	c.EnqueueKey(types.NamespacedName{Namespace: object.GetNamespace(), Name: object.GetName()})
   304  }
   305  
   306  // EnqueueSentinel returns a Enqueue method which will always enqueue a
   307  // predefined key instead of the object key.
   308  func (c *Impl) EnqueueSentinel(k types.NamespacedName) func(interface{}) {
   309  	return func(interface{}) {
   310  		c.EnqueueKey(k)
   311  	}
   312  }
   313  
   314  // EnqueueControllerOf takes a resource, identifies its controller resource,
   315  // converts it into a namespace/name string, and passes that to EnqueueKey.
   316  func (c *Impl) EnqueueControllerOf(obj interface{}) {
   317  	object, err := kmeta.DeletionHandlingAccessor(obj)
   318  	if err != nil {
   319  		c.logger.Error(err)
   320  		return
   321  	}
   322  
   323  	// If we can determine the controller ref of this object, then
   324  	// add that object to our workqueue.
   325  	if owner := metav1.GetControllerOf(object); owner != nil {
   326  		c.EnqueueKey(types.NamespacedName{Namespace: object.GetNamespace(), Name: owner.Name})
   327  	}
   328  }
   329  
   330  // EnqueueLabelOfNamespaceScopedResource returns with an Enqueue func that
   331  // takes a resource, identifies its controller resource through given namespace
   332  // and name labels, converts it into a namespace/name string, and passes that
   333  // to EnqueueKey. The controller resource must be of namespace-scoped.
   334  func (c *Impl) EnqueueLabelOfNamespaceScopedResource(namespaceLabel, nameLabel string) func(obj interface{}) {
   335  	return func(obj interface{}) {
   336  		object, err := kmeta.DeletionHandlingAccessor(obj)
   337  		if err != nil {
   338  			c.logger.Error(err)
   339  			return
   340  		}
   341  
   342  		labels := object.GetLabels()
   343  		controllerKey, ok := labels[nameLabel]
   344  		if !ok {
   345  			c.logger.Debugf("Object %s/%s does not have a referring name label %s",
   346  				object.GetNamespace(), object.GetName(), nameLabel)
   347  			return
   348  		}
   349  
   350  		if namespaceLabel != "" {
   351  			controllerNamespace, ok := labels[namespaceLabel]
   352  			if !ok {
   353  				c.logger.Debugf("Object %s/%s does not have a referring namespace label %s",
   354  					object.GetNamespace(), object.GetName(), namespaceLabel)
   355  				return
   356  			}
   357  
   358  			c.EnqueueKey(types.NamespacedName{Namespace: controllerNamespace, Name: controllerKey})
   359  			return
   360  		}
   361  
   362  		// Pass through namespace of the object itself if no namespace label specified.
   363  		// This is for the scenario that object and the parent resource are of same namespace,
   364  		// e.g. to enqueue the revision of an endpoint.
   365  		c.EnqueueKey(types.NamespacedName{Namespace: object.GetNamespace(), Name: controllerKey})
   366  	}
   367  }
   368  
   369  // EnqueueLabelOfClusterScopedResource returns with an Enqueue func
   370  // that takes a resource, identifies its controller resource through
   371  // given name label, and passes it to EnqueueKey.
   372  // The controller resource must be of cluster-scoped.
   373  func (c *Impl) EnqueueLabelOfClusterScopedResource(nameLabel string) func(obj interface{}) {
   374  	return func(obj interface{}) {
   375  		object, err := kmeta.DeletionHandlingAccessor(obj)
   376  		if err != nil {
   377  			c.logger.Error(err)
   378  			return
   379  		}
   380  
   381  		labels := object.GetLabels()
   382  		controllerKey, ok := labels[nameLabel]
   383  		if !ok {
   384  			c.logger.Debugf("Object %s/%s does not have a referring name label %s",
   385  				object.GetNamespace(), object.GetName(), nameLabel)
   386  			return
   387  		}
   388  
   389  		c.EnqueueKey(types.NamespacedName{Namespace: "", Name: controllerKey})
   390  	}
   391  }
   392  
   393  // EnqueueNamespaceOf takes a resource, and enqueues the Namespace to which it belongs.
   394  func (c *Impl) EnqueueNamespaceOf(obj interface{}) {
   395  	object, err := kmeta.DeletionHandlingAccessor(obj)
   396  	if err != nil {
   397  		c.logger.Errorw("EnqueueNamespaceOf", zap.Error(err))
   398  		return
   399  	}
   400  	c.EnqueueKey(types.NamespacedName{Name: object.GetNamespace()})
   401  }
   402  
   403  // EnqueueKey takes a namespace/name string and puts it onto the work queue.
   404  func (c *Impl) EnqueueKey(key types.NamespacedName) {
   405  	c.workQueue.Add(key)
   406  
   407  	if logger := c.logger.Desugar(); logger.Core().Enabled(zapcore.DebugLevel) {
   408  		logger.Debug(fmt.Sprintf("Adding to queue %s (depth: %d)", safeKey(key), c.workQueue.Len()),
   409  			zap.String(logkey.Key, key.String()))
   410  	}
   411  }
   412  
   413  // MaybeEnqueueBucketKey takes a Bucket and namespace/name string and puts it onto
   414  // the slow work queue.
   415  func (c *Impl) MaybeEnqueueBucketKey(bkt reconciler.Bucket, key types.NamespacedName) {
   416  	if bkt.Has(key) {
   417  		c.EnqueueSlowKey(key)
   418  	}
   419  }
   420  
   421  // EnqueueKeyAfter takes a namespace/name string and schedules its execution in
   422  // the work queue after given delay.
   423  func (c *Impl) EnqueueKeyAfter(key types.NamespacedName, delay time.Duration) {
   424  	c.workQueue.AddAfter(key, delay)
   425  
   426  	if logger := c.logger.Desugar(); logger.Core().Enabled(zapcore.DebugLevel) {
   427  		logger.Debug(fmt.Sprintf("Adding to queue %s (delay: %v, depth: %d)", safeKey(key), delay, c.workQueue.Len()),
   428  			zap.String(logkey.Key, key.String()))
   429  	}
   430  }
   431  
   432  // Run runs the controller with it's configured Concurrency
   433  func (c *Impl) Run(ctx context.Context) error {
   434  	return c.RunContext(ctx, c.Concurrency)
   435  }
   436  
   437  // RunContext starts the controller's worker threads, the number of which is threadiness.
   438  // If the context has been decorated for LeaderElection, then an elector is built and run.
   439  // It then blocks until the context is cancelled, at which point it shuts down its
   440  // internal work queue and waits for workers to finish processing their current
   441  // work items.
   442  func (c *Impl) RunContext(ctx context.Context, threadiness int) error {
   443  	sg := sync.WaitGroup{}
   444  	defer func() {
   445  		c.workQueue.ShutDown()
   446  		for c.workQueue.Len() > 0 {
   447  			time.Sleep(time.Millisecond * 100)
   448  		}
   449  		sg.Wait()
   450  		runtime.HandleCrash()
   451  	}()
   452  
   453  	if la, ok := c.Reconciler.(reconciler.LeaderAware); ok {
   454  		// Build and execute an elector.
   455  		le, err := kle.BuildElector(ctx, la, c.Name, c.MaybeEnqueueBucketKey)
   456  		if err != nil {
   457  			return err
   458  		}
   459  		if ib, ok := le.(kle.ElectorWithInitialBuckets); ok {
   460  			for _, b := range ib.InitialBuckets() {
   461  				// No need to provide an enq function since the controller
   462  				// is not processing items
   463  				la.Promote(b, nil)
   464  			}
   465  		}
   466  		sg.Add(1)
   467  		go func() {
   468  			defer sg.Done()
   469  			le.Run(ctx)
   470  		}()
   471  	}
   472  
   473  	// Launch workers to process resources that get enqueued to our workqueue.
   474  	c.logger.Infow("Starting controller and workers", zap.Int("threadiness", threadiness))
   475  	for range threadiness {
   476  		sg.Add(1)
   477  		go func() {
   478  			defer sg.Done()
   479  			for c.processNextWorkItem() {
   480  			}
   481  		}()
   482  	}
   483  
   484  	c.logger.Info("Started workers")
   485  	<-ctx.Done()
   486  	c.logger.Info("Shutting down workers")
   487  
   488  	return nil
   489  }
   490  
   491  // processNextWorkItem will read a single work item off the workqueue and
   492  // attempt to process it, by calling Reconcile on our Reconciler.
   493  func (c *Impl) processNextWorkItem() bool {
   494  	obj, shutdown := c.workQueue.Get()
   495  	if shutdown {
   496  		return false
   497  	}
   498  	key := obj.(types.NamespacedName)
   499  	keyStr := safeKey(key)
   500  
   501  	c.logger.Debugf("Processing from queue %s (depth: %d)", safeKey(key), c.workQueue.Len())
   502  
   503  	startTime := time.Now()
   504  
   505  	var err error
   506  	defer func() {
   507  		// We call Done here so the workqueue knows we have finished
   508  		// processing this item. We also must remember to call Forget if
   509  		// reconcile succeeds. If a transient error occurs, we do not call
   510  		// Forget and put the item back to the queue with an increased
   511  		// delay.
   512  		c.workQueue.Done(key)
   513  	}()
   514  
   515  	// Embed the key into the logger and attach that to the context we pass
   516  	// to the Reconciler.
   517  	logger := c.logger.With(zap.String(logkey.TraceID, uuid.NewString()), zap.String(logkey.Key, keyStr))
   518  	ctx := logging.WithLogger(context.Background(), logger)
   519  
   520  	// Run Reconcile, passing it the namespace/name string of the
   521  	// resource to be synced.
   522  	if err = c.Reconciler.Reconcile(ctx, keyStr); err != nil {
   523  		c.handleErr(logger, err, key, startTime)
   524  		return true
   525  	}
   526  
   527  	// Finally, if no error occurs we Forget this item so it does not
   528  	// have any delay when another change happens.
   529  	c.workQueue.Forget(key)
   530  	logger.Infow("Reconcile succeeded", zap.Duration("duration", time.Since(startTime)))
   531  
   532  	return true
   533  }
   534  
   535  func (c *Impl) handleErr(logger *zap.SugaredLogger, err error, key types.NamespacedName, startTime time.Time) {
   536  	// Check if we should skip this key or if the queue is shutting down.
   537  	// We check shutdown here since controller Run might have exited by now
   538  	// (since while this item was being processed, queue.Len==0).
   539  	if IsSkipKey(err) || c.workQueue.ShuttingDown() {
   540  		c.workQueue.Forget(key)
   541  		return
   542  	}
   543  
   544  	if ok, delay := IsRequeueKey(err); ok {
   545  		c.workQueue.AddAfter(key, delay)
   546  		logger.Debugf("Requeuing key %s (by request) after %v (depth: %d)", safeKey(key), delay, c.workQueue.Len())
   547  		return
   548  	}
   549  
   550  	// Conflict errors are expected, requeue to retry
   551  	if apierrors.IsConflict(err) {
   552  		logger.Debugw("Reconcile conflict", zap.Duration("duration", time.Since(startTime)))
   553  		c.workQueue.AddRateLimited(key)
   554  		return
   555  	}
   556  
   557  	logger.Errorw("Reconcile error", zap.Duration("duration", time.Since(startTime)), zap.Error(err))
   558  
   559  	// Re-queue the key if it's a transient error.
   560  	if !IsPermanentError(err) {
   561  		c.workQueue.AddRateLimited(key)
   562  		logger.Debugf("Requeuing key %s due to non-permanent error (depth: %d)", safeKey(key), c.workQueue.Len())
   563  		return
   564  	}
   565  
   566  	c.workQueue.Forget(key)
   567  }
   568  
   569  // GlobalResync enqueues into the slow lane all objects from the passed SharedInformer
   570  func (c *Impl) GlobalResync(si cache.SharedInformer) {
   571  	alwaysTrue := func(interface{}) bool { return true }
   572  	c.FilteredGlobalResync(alwaysTrue, si)
   573  }
   574  
   575  // FilteredGlobalResync enqueues all objects from the
   576  // SharedInformer that pass the filter function in to the slow queue.
   577  func (c *Impl) FilteredGlobalResync(f func(interface{}) bool, si cache.SharedInformer) {
   578  	if c.workQueue.ShuttingDown() {
   579  		return
   580  	}
   581  	list := si.GetStore().List()
   582  	for _, obj := range list {
   583  		if f(obj) {
   584  			c.EnqueueSlow(obj)
   585  		}
   586  	}
   587  }
   588  
   589  // NewSkipKey returns a new instance of skipKeyError.
   590  // Users can return this type of error to indicate that the key was skipped.
   591  func NewSkipKey(key string) error {
   592  	return skipKeyError{key: key}
   593  }
   594  
   595  // skipKeyError is an error that indicates a key was skipped.
   596  // We should not re-queue keys when it returns this error from Reconcile.
   597  type skipKeyError struct {
   598  	key string
   599  }
   600  
   601  var _ error = skipKeyError{}
   602  
   603  // Error implements the Error() interface of error.
   604  func (err skipKeyError) Error() string {
   605  	return fmt.Sprintf("skipped key: %q", err.key)
   606  }
   607  
   608  // IsSkipKey returns true if the given error is a skipKeyError.
   609  func IsSkipKey(err error) bool {
   610  	return errors.Is(err, skipKeyError{})
   611  }
   612  
   613  // Is implements the Is() interface of error. It returns whether the target
   614  // error can be treated as equivalent to a permanentError.
   615  func (skipKeyError) Is(target error) bool {
   616  	_, ok := target.(skipKeyError)
   617  	return ok
   618  }
   619  
   620  // NewPermanentError returns a new instance of permanentError.
   621  // Users can wrap an error as permanentError with this in reconcile
   622  // when they do not expect the key to get re-queued.
   623  func NewPermanentError(err error) error {
   624  	return permanentError{e: err}
   625  }
   626  
   627  // permanentError is an error that is considered not transient.
   628  // We should not re-queue keys when it returns with thus error in reconcile.
   629  type permanentError struct {
   630  	e error
   631  }
   632  
   633  // IsPermanentError returns true if the given error is a permanentError or
   634  // wraps a permanentError.
   635  func IsPermanentError(err error) bool {
   636  	return errors.Is(err, permanentError{})
   637  }
   638  
   639  // Is implements the Is() interface of error. It returns whether the target
   640  // error can be treated as equivalent to a permanentError.
   641  func (permanentError) Is(target error) bool {
   642  	_, ok := target.(permanentError)
   643  	return ok
   644  }
   645  
   646  var _ error = permanentError{}
   647  
   648  // Error implements the Error() interface of error.
   649  func (err permanentError) Error() string {
   650  	if err.e == nil {
   651  		return ""
   652  	}
   653  
   654  	return err.e.Error()
   655  }
   656  
   657  // Unwrap implements the Unwrap() interface of error. It returns the error
   658  // wrapped inside permanentError.
   659  func (err permanentError) Unwrap() error {
   660  	return err.e
   661  }
   662  
   663  // NewRequeueImmediately returns a new instance of requeueKeyError.
   664  // Users can return this type of error to immediately requeue a key.
   665  func NewRequeueImmediately() error {
   666  	return requeueKeyError{}
   667  }
   668  
   669  // NewRequeueAfter returns a new instance of requeueKeyError.
   670  // Users can return this type of error to requeue a key after a delay.
   671  func NewRequeueAfter(dur time.Duration) error {
   672  	return requeueKeyError{duration: dur}
   673  }
   674  
   675  // requeueKeyError is an error that indicates the reconciler wants to reprocess
   676  // the key after a particular duration (possibly zero).
   677  // We should re-queue keys with the desired duration when this is returned by Reconcile.
   678  type requeueKeyError struct {
   679  	duration time.Duration
   680  }
   681  
   682  var _ error = requeueKeyError{}
   683  
   684  // Error implements the Error() interface of error.
   685  func (err requeueKeyError) Error() string {
   686  	return fmt.Sprintf("requeue after: %s", err.duration)
   687  }
   688  
   689  // IsRequeueKey returns true if the given error is a requeueKeyError.
   690  func IsRequeueKey(err error) (bool, time.Duration) {
   691  	rqe := requeueKeyError{}
   692  	if errors.As(err, &rqe) {
   693  		return true, rqe.duration
   694  	}
   695  	return false, 0
   696  }
   697  
   698  // Is implements the Is() interface of error. It returns whether the target
   699  // error can be treated as equivalent to a requeueKeyError.
   700  func (requeueKeyError) Is(target error) bool {
   701  	_, ok := target.(requeueKeyError)
   702  	return ok
   703  }
   704  
   705  // Informer is the group of methods that a type must implement to be passed to
   706  // StartInformers.
   707  type Informer interface {
   708  	Run(<-chan struct{})
   709  	HasSynced() bool
   710  }
   711  
   712  // StartInformers kicks off all of the passed informers and then waits for all
   713  // of them to synchronize.
   714  func StartInformers(stopCh <-chan struct{}, informers ...Informer) error {
   715  	for _, informer := range informers {
   716  		go informer.Run(stopCh)
   717  	}
   718  
   719  	for i, informer := range informers {
   720  		if ok := cache.WaitForCacheSync(stopCh, informer.HasSynced); !ok {
   721  			return fmt.Errorf("failed to wait for cache at index %d to sync", i)
   722  		}
   723  	}
   724  	return nil
   725  }
   726  
   727  // RunInformers kicks off all of the passed informers and then waits for all of
   728  // them to synchronize. Returned function will wait for all informers to finish.
   729  func RunInformers(stopCh <-chan struct{}, informers ...Informer) (func(), error) {
   730  	var wg sync.WaitGroup
   731  	wg.Add(len(informers))
   732  	for _, informer := range informers {
   733  		go func() {
   734  			defer wg.Done()
   735  			informer.Run(stopCh)
   736  		}()
   737  	}
   738  
   739  	for i, informer := range informers {
   740  		if ok := WaitForCacheSyncQuick(stopCh, informer.HasSynced); !ok {
   741  			return wg.Wait, fmt.Errorf("failed to wait for cache at index %d to sync", i)
   742  		}
   743  	}
   744  	return wg.Wait, nil
   745  }
   746  
   747  // WaitForCacheSyncQuick is the same as cache.WaitForCacheSync but with a much reduced
   748  // check-rate for the sync period.
   749  func WaitForCacheSyncQuick(stopCh <-chan struct{}, cacheSyncs ...cache.InformerSynced) bool {
   750  	err := wait.PollUntilContextCancel(wait.ContextForChannel(stopCh), time.Millisecond, true,
   751  		func(context.Context) (bool, error) {
   752  			for _, syncFunc := range cacheSyncs {
   753  				if !syncFunc() {
   754  					return false, nil
   755  				}
   756  			}
   757  			return true, nil
   758  		},
   759  	)
   760  	return err == nil
   761  }
   762  
   763  // StartAll kicks off all of the passed controllers with DefaultThreadsPerController.
   764  func StartAll(ctx context.Context, controllers ...*Impl) error {
   765  	eg, egCtx := errgroup.WithContext(ctx)
   766  
   767  	// Start all of the controllers.
   768  	for _, controller := range controllers {
   769  		c := controller
   770  		eg.Go(func() error {
   771  			return c.Run(egCtx)
   772  		})
   773  	}
   774  	return eg.Wait()
   775  }
   776  
   777  // This is attached to contexts passed to controller constructors to associate
   778  // a resync period.
   779  type resyncPeriodKey struct{}
   780  
   781  // WithResyncPeriod associates the given resync period with the given context in
   782  // the context that is returned.
   783  func WithResyncPeriod(ctx context.Context, resync time.Duration) context.Context {
   784  	return context.WithValue(ctx, resyncPeriodKey{}, resync)
   785  }
   786  
   787  // GetResyncPeriod returns the resync period associated with the given context.
   788  // When none is specified a default resync period is used.
   789  func GetResyncPeriod(ctx context.Context) time.Duration {
   790  	rp := ctx.Value(resyncPeriodKey{})
   791  	if rp == nil {
   792  		return DefaultResyncPeriod
   793  	}
   794  	return rp.(time.Duration)
   795  }
   796  
   797  // GetTrackerLease fetches the tracker lease from the controller context.
   798  func GetTrackerLease(ctx context.Context) time.Duration {
   799  	return 3 * GetResyncPeriod(ctx)
   800  }
   801  
   802  // trackerKey is used to associate tracker.Interface with contexts.
   803  type trackerKey struct{}
   804  
   805  // WithTracker attaches the given tracker.Interface to the provided context
   806  // in the returned context.
   807  func WithTracker(ctx context.Context, t tracker.Interface) context.Context {
   808  	return context.WithValue(ctx, trackerKey{}, t)
   809  }
   810  
   811  // GetTracker attempts to look up the tracker.Interface on a given context.
   812  // It may return null if none is found.
   813  func GetTracker(ctx context.Context) tracker.Interface {
   814  	untyped := ctx.Value(trackerKey{})
   815  	if untyped == nil {
   816  		return nil
   817  	}
   818  	return untyped.(tracker.Interface)
   819  }
   820  
   821  // erKey is used to associate record.EventRecorders with contexts.
   822  type erKey struct{}
   823  
   824  // WithEventRecorder attaches the given record.EventRecorder to the provided context
   825  // in the returned context.
   826  func WithEventRecorder(ctx context.Context, er record.EventRecorder) context.Context {
   827  	return context.WithValue(ctx, erKey{}, er)
   828  }
   829  
   830  // GetEventRecorder attempts to look up the record.EventRecorder on a given context.
   831  // It may return null if none is found.
   832  func GetEventRecorder(ctx context.Context) record.EventRecorder {
   833  	untyped := ctx.Value(erKey{})
   834  	if untyped == nil {
   835  		return nil
   836  	}
   837  	return untyped.(record.EventRecorder)
   838  }
   839  
   840  func safeKey(key types.NamespacedName) string {
   841  	if key.Namespace == "" {
   842  		return key.Name
   843  	}
   844  	return key.String()
   845  }