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 }