...

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

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

     1  /*
     2  Copyright 2018 The Kubernetes 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      http://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  	"fmt"
    22  	"time"
    23  
    24  	"github.com/go-logr/logr"
    25  	"k8s.io/client-go/util/workqueue"
    26  	"k8s.io/klog/v2"
    27  
    28  	"sigs.k8s.io/controller-runtime/pkg/internal/controller"
    29  	"sigs.k8s.io/controller-runtime/pkg/manager"
    30  	"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
    31  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    32  	"sigs.k8s.io/controller-runtime/pkg/source"
    33  )
    34  
    35  // Options are the arguments for creating a new Controller.
    36  type Options struct {
    37  	// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
    38  	MaxConcurrentReconciles int
    39  
    40  	// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
    41  	// Defaults to 2 minutes if not set.
    42  	CacheSyncTimeout time.Duration
    43  
    44  	// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
    45  	// Defaults to the Controller.RecoverPanic setting from the Manager if unset.
    46  	RecoverPanic *bool
    47  
    48  	// NeedLeaderElection indicates whether the controller needs to use leader election.
    49  	// Defaults to true, which means the controller will use leader election.
    50  	NeedLeaderElection *bool
    51  
    52  	// Reconciler reconciles an object
    53  	Reconciler reconcile.Reconciler
    54  
    55  	// RateLimiter is used to limit how frequently requests may be queued.
    56  	// Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting.
    57  	// The overall is a token bucket and the per-item is exponential.
    58  	RateLimiter ratelimiter.RateLimiter
    59  
    60  	// NewQueue constructs the queue for this controller once the controller is ready to start.
    61  	// With NewQueue a custom queue implementation can be used, e.g. a priority queue to prioritize with which
    62  	// priority/order objects are reconciled (e.g. to reconcile objects with changes first).
    63  	// This is a func because the standard Kubernetes work queues start themselves immediately, which
    64  	// leads to goroutine leaks if something calls controller.New repeatedly.
    65  	// The NewQueue func gets the controller name and the RateLimiter option (defaulted if necessary) passed in.
    66  	// NewQueue defaults to NewRateLimitingQueueWithConfig.
    67  	//
    68  	// NOTE: LOW LEVEL PRIMITIVE!
    69  	// Only use a custom NewQueue if you know what you are doing.
    70  	NewQueue func(controllerName string, rateLimiter ratelimiter.RateLimiter) workqueue.RateLimitingInterface
    71  
    72  	// LogConstructor is used to construct a logger used for this controller and passed
    73  	// to each reconciliation via the context field.
    74  	LogConstructor func(request *reconcile.Request) logr.Logger
    75  }
    76  
    77  // Controller implements a Kubernetes API.  A Controller manages a work queue fed reconcile.Requests
    78  // from source.Sources.  Work is performed through the reconcile.Reconciler for each enqueued item.
    79  // Work typically is reads and writes Kubernetes objects to make the system state match the state specified
    80  // in the object Spec.
    81  type Controller interface {
    82  	// Reconciler is called to reconcile an object by Namespace/Name
    83  	reconcile.Reconciler
    84  
    85  	// Watch watches the provided Source.
    86  	Watch(src source.Source) error
    87  
    88  	// Start starts the controller.  Start blocks until the context is closed or a
    89  	// controller has an error starting.
    90  	Start(ctx context.Context) error
    91  
    92  	// GetLogger returns this controller logger prefilled with basic information.
    93  	GetLogger() logr.Logger
    94  }
    95  
    96  // New returns a new Controller registered with the Manager.  The Manager will ensure that shared Caches have
    97  // been synced before the Controller is Started.
    98  func New(name string, mgr manager.Manager, options Options) (Controller, error) {
    99  	c, err := NewUnmanaged(name, mgr, options)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	// Add the controller as a Manager components
   105  	return c, mgr.Add(c)
   106  }
   107  
   108  // NewUnmanaged returns a new controller without adding it to the manager. The
   109  // caller is responsible for starting the returned controller.
   110  func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error) {
   111  	if options.Reconciler == nil {
   112  		return nil, fmt.Errorf("must specify Reconciler")
   113  	}
   114  
   115  	if len(name) == 0 {
   116  		return nil, fmt.Errorf("must specify Name for Controller")
   117  	}
   118  
   119  	if options.LogConstructor == nil {
   120  		log := mgr.GetLogger().WithValues(
   121  			"controller", name,
   122  		)
   123  		options.LogConstructor = func(req *reconcile.Request) logr.Logger {
   124  			log := log
   125  			if req != nil {
   126  				log = log.WithValues(
   127  					"object", klog.KRef(req.Namespace, req.Name),
   128  					"namespace", req.Namespace, "name", req.Name,
   129  				)
   130  			}
   131  			return log
   132  		}
   133  	}
   134  
   135  	if options.MaxConcurrentReconciles <= 0 {
   136  		if mgr.GetControllerOptions().MaxConcurrentReconciles > 0 {
   137  			options.MaxConcurrentReconciles = mgr.GetControllerOptions().MaxConcurrentReconciles
   138  		} else {
   139  			options.MaxConcurrentReconciles = 1
   140  		}
   141  	}
   142  
   143  	if options.CacheSyncTimeout == 0 {
   144  		if mgr.GetControllerOptions().CacheSyncTimeout != 0 {
   145  			options.CacheSyncTimeout = mgr.GetControllerOptions().CacheSyncTimeout
   146  		} else {
   147  			options.CacheSyncTimeout = 2 * time.Minute
   148  		}
   149  	}
   150  
   151  	if options.RateLimiter == nil {
   152  		options.RateLimiter = workqueue.DefaultControllerRateLimiter()
   153  	}
   154  
   155  	if options.NewQueue == nil {
   156  		options.NewQueue = func(controllerName string, rateLimiter ratelimiter.RateLimiter) workqueue.RateLimitingInterface {
   157  			return workqueue.NewRateLimitingQueueWithConfig(rateLimiter, workqueue.RateLimitingQueueConfig{
   158  				Name: controllerName,
   159  			})
   160  		}
   161  	}
   162  
   163  	if options.RecoverPanic == nil {
   164  		options.RecoverPanic = mgr.GetControllerOptions().RecoverPanic
   165  	}
   166  
   167  	if options.NeedLeaderElection == nil {
   168  		options.NeedLeaderElection = mgr.GetControllerOptions().NeedLeaderElection
   169  	}
   170  
   171  	// Create controller with dependencies set
   172  	return &controller.Controller{
   173  		Do:                      options.Reconciler,
   174  		RateLimiter:             options.RateLimiter,
   175  		NewQueue:                options.NewQueue,
   176  		MaxConcurrentReconciles: options.MaxConcurrentReconciles,
   177  		CacheSyncTimeout:        options.CacheSyncTimeout,
   178  		Name:                    name,
   179  		LogConstructor:          options.LogConstructor,
   180  		RecoverPanic:            options.RecoverPanic,
   181  		LeaderElected:           options.NeedLeaderElection,
   182  	}, nil
   183  }
   184  
   185  // ReconcileIDFromContext gets the reconcileID from the current context.
   186  var ReconcileIDFromContext = controller.ReconcileIDFromContext
   187  

View as plain text