github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/queueinformer/config.go (about)

     1  package queueinformer
     2  
     3  import (
     4  	"github.com/pkg/errors"
     5  	"github.com/sirupsen/logrus"
     6  	"k8s.io/client-go/discovery"
     7  	"k8s.io/client-go/tools/cache"
     8  	"k8s.io/client-go/util/workqueue"
     9  
    10  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubestate"
    11  	"github.com/operator-framework/operator-lifecycle-manager/pkg/metrics"
    12  )
    13  
    14  type queueInformerConfig struct {
    15  	provider metrics.MetricsProvider
    16  	logger   *logrus.Logger
    17  	queue    workqueue.RateLimitingInterface
    18  	informer cache.SharedIndexInformer
    19  	indexer  cache.Indexer
    20  	keyFunc  KeyFunc
    21  	syncer   kubestate.Syncer
    22  }
    23  
    24  // Option applies an option to the given queue informer config.
    25  type Option func(config *queueInformerConfig)
    26  
    27  // apply sequentially applies the given options to the config.
    28  func (c *queueInformerConfig) apply(options []Option) {
    29  	for _, option := range options {
    30  		option(c)
    31  	}
    32  }
    33  
    34  func newInvalidConfigError(msg string) error {
    35  	return errors.Errorf("invalid queue informer config: %s", msg)
    36  }
    37  
    38  func (c *queueInformerConfig) complete() {
    39  	if c.indexer == nil && c.informer != nil {
    40  		// Extract indexer from informer if
    41  		c.indexer = c.informer.GetIndexer()
    42  	}
    43  }
    44  
    45  // validate returns an error if the config isn't valid.
    46  func (c *queueInformerConfig) validateQueueInformer() (err error) {
    47  	switch config := c; {
    48  	case config.provider == nil:
    49  		err = newInvalidConfigError("nil metrics provider")
    50  	case config.logger == nil:
    51  		err = newInvalidConfigError("nil logger")
    52  	case config.queue == nil:
    53  		err = newInvalidConfigError("nil queue")
    54  	case config.indexer == nil && config.informer == nil:
    55  		err = newInvalidConfigError("nil indexer and informer")
    56  	case config.keyFunc == nil:
    57  		err = newInvalidConfigError("nil key function")
    58  	case config.syncer == nil:
    59  		err = newInvalidConfigError("nil syncer")
    60  	}
    61  
    62  	return
    63  }
    64  
    65  // difference from above is that this intentionally verifies without index/informer
    66  func (c *queueInformerConfig) validateQueue() (err error) {
    67  	switch config := c; {
    68  	case config.provider == nil:
    69  		err = newInvalidConfigError("nil metrics provider")
    70  	case config.logger == nil:
    71  		err = newInvalidConfigError("nil logger")
    72  	case config.queue == nil:
    73  		err = newInvalidConfigError("nil queue")
    74  	case config.keyFunc == nil:
    75  		err = newInvalidConfigError("nil key function")
    76  	case config.syncer == nil:
    77  		err = newInvalidConfigError("nil syncer")
    78  	}
    79  
    80  	return
    81  }
    82  
    83  func defaultKeyFunc(obj interface{}) (string, bool) {
    84  	// Get keys nested in resource events up to depth 2
    85  	keyable := false
    86  	for d := 0; d < 2 && !keyable; d++ {
    87  		switch v := obj.(type) {
    88  		case string:
    89  			return v, true
    90  		case kubestate.ResourceEvent:
    91  			obj = v.Resource()
    92  		default:
    93  			keyable = true
    94  		}
    95  	}
    96  
    97  	k, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
    98  	if err != nil {
    99  		return k, false
   100  	}
   101  
   102  	return k, true
   103  }
   104  
   105  func defaultConfig() *queueInformerConfig {
   106  	return &queueInformerConfig{
   107  		provider: metrics.NewMetricsNil(),
   108  		queue: workqueue.NewTypedRateLimitingQueueWithConfig[any](
   109  			workqueue.DefaultTypedControllerRateLimiter[any](),
   110  			workqueue.TypedRateLimitingQueueConfig[any]{
   111  				Name: "default",
   112  			}),
   113  		logger:  logrus.New(),
   114  		keyFunc: defaultKeyFunc,
   115  	}
   116  }
   117  
   118  // WithMetricsProvider configures the QueueInformer's MetricsProvider as provider.
   119  func WithMetricsProvider(provider metrics.MetricsProvider) Option {
   120  	return func(config *queueInformerConfig) {
   121  		config.provider = provider
   122  	}
   123  }
   124  
   125  // WithLogger configures logger as the QueueInformer's Logger.
   126  func WithLogger(logger *logrus.Logger) Option {
   127  	return func(config *queueInformerConfig) {
   128  		config.logger = logger
   129  	}
   130  }
   131  
   132  // WithQueue sets the queue used by a QueueInformer.
   133  func WithQueue(queue workqueue.RateLimitingInterface) Option {
   134  	return func(config *queueInformerConfig) {
   135  		config.queue = queue
   136  	}
   137  }
   138  
   139  // WithInformer sets the informer used by a QueueInformer.
   140  func WithInformer(informer cache.SharedIndexInformer) Option {
   141  	return func(config *queueInformerConfig) {
   142  		config.informer = informer
   143  	}
   144  }
   145  
   146  // WithIndexer sets the indexer used by a QueueInformer.
   147  func WithIndexer(indexer cache.Indexer) Option {
   148  	return func(config *queueInformerConfig) {
   149  		config.indexer = indexer
   150  	}
   151  }
   152  
   153  // WithKeyFunc sets the key func used by a QueueInformer.
   154  func WithKeyFunc(keyFunc KeyFunc) Option {
   155  	return func(config *queueInformerConfig) {
   156  		config.keyFunc = keyFunc
   157  	}
   158  }
   159  
   160  // WithSyncer sets the syncer invoked by a QueueInformer.
   161  func WithSyncer(syncer kubestate.Syncer) Option {
   162  	return func(config *queueInformerConfig) {
   163  		config.syncer = syncer
   164  	}
   165  }
   166  
   167  type operatorConfig struct {
   168  	serverVersion  discovery.ServerVersionInterface
   169  	queueInformers []*QueueInformer
   170  	informers      []cache.SharedIndexInformer
   171  	logger         *logrus.Logger
   172  	numWorkers     int
   173  }
   174  
   175  type OperatorOption func(*operatorConfig)
   176  
   177  // apply sequentially applies the given options to the config.
   178  func (c *operatorConfig) apply(options []OperatorOption) {
   179  	for _, option := range options {
   180  		option(c)
   181  	}
   182  }
   183  
   184  func newInvalidOperatorConfigError(msg string) error {
   185  	return errors.Errorf("invalid queue informer operator config: %s", msg)
   186  }
   187  
   188  // WithOperatorLogger sets the logger used by an Operator.
   189  func WithOperatorLogger(logger *logrus.Logger) OperatorOption {
   190  	return func(config *operatorConfig) {
   191  		config.logger = logger
   192  	}
   193  }
   194  
   195  // WithQueueInformers registers a set of initial QueueInformers with an Operator.
   196  // If the QueueInformer is configured with a SharedIndexInformer, that SharedIndexInformer
   197  // is registered with the Operator automatically.
   198  func WithQueueInformers(queueInformers ...*QueueInformer) OperatorOption {
   199  	return func(config *operatorConfig) {
   200  		config.queueInformers = queueInformers
   201  	}
   202  }
   203  
   204  // WithInformers registers a set of initial Informers with an Operator.
   205  func WithInformers(informers ...cache.SharedIndexInformer) OperatorOption {
   206  	return func(config *operatorConfig) {
   207  		config.informers = informers
   208  	}
   209  }
   210  
   211  // WithNumWorkers sets the number of workers an Operator uses to process each queue.
   212  // It translates directly to the number of queue items processed in parallel for a given queue.
   213  // Specifying zero or less workers is an invariant and will cause an error upon configuration.
   214  // Specifying one worker indicates that each queue will only have one item processed at a time.
   215  func WithNumWorkers(numWorkers int) OperatorOption {
   216  	return func(config *operatorConfig) {
   217  		config.numWorkers = numWorkers
   218  	}
   219  }
   220  
   221  // validate returns an error if the config isn't valid.
   222  func (c *operatorConfig) validate() (err error) {
   223  	switch config := c; {
   224  	case config.serverVersion == nil:
   225  		err = newInvalidOperatorConfigError("discovery client nil")
   226  	case config.numWorkers < 1:
   227  		err = newInvalidOperatorConfigError("must specify at least one worker per queue")
   228  	}
   229  
   230  	return
   231  }
   232  
   233  func defaultOperatorConfig() *operatorConfig {
   234  	return &operatorConfig{
   235  		logger:     logrus.New(),
   236  		numWorkers: 2,
   237  	}
   238  }