1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat: add explicit key support to controller utils (#4628)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-09-19 13:25:03 +02:00 committed by GitHub
parent 71404df826
commit 6eea7c45f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 28 deletions

View file

@ -1,6 +1,8 @@
package controller package controller
import ( import (
"errors"
"github.com/go-logr/logr" "github.com/go-logr/logr"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
@ -11,6 +13,7 @@ type (
addFunc func(interface{}) addFunc func(interface{})
updateFunc func(interface{}, interface{}) updateFunc func(interface{}, interface{})
deleteFunc func(interface{}) deleteFunc func(interface{})
keyFunc func(interface{}) (interface{}, error)
) )
func AddEventHandlers(informer cache.SharedInformer, a addFunc, u updateFunc, d deleteFunc) { func AddEventHandlers(informer cache.SharedInformer, a addFunc, u updateFunc, d deleteFunc) {
@ -21,32 +24,57 @@ func AddEventHandlers(informer cache.SharedInformer, a addFunc, u updateFunc, d
}) })
} }
func AddDefaultEventHandlers(logger logr.Logger, informer cache.SharedInformer, queue workqueue.RateLimitingInterface) { func AddKeyedEventHandlers(logger logr.Logger, informer cache.SharedInformer, queue workqueue.RateLimitingInterface, parseKey keyFunc) {
AddEventHandlers(informer, AddFunc(logger, queue), UpdateFunc(logger, queue), DeleteFunc(logger, queue)) AddEventHandlers(informer, AddFunc(logger, queue, parseKey), UpdateFunc(logger, queue, parseKey), DeleteFunc(logger, queue, parseKey))
} }
func Enqueue(logger logr.Logger, queue workqueue.RateLimitingInterface, obj interface{}) { func AddDefaultEventHandlers(logger logr.Logger, informer cache.SharedInformer, queue workqueue.RateLimitingInterface) {
if key, err := cache.MetaNamespaceKeyFunc(obj); err != nil { AddKeyedEventHandlers(logger, informer, queue, MetaNamespaceKey)
logger.Error(err, "failed to compute key name") }
func AddExplicitEventHandlers[K any](logger logr.Logger, informer cache.SharedInformer, queue workqueue.RateLimitingInterface, parseKey func(K) cache.ExplicitKey) {
AddKeyedEventHandlers(logger, informer, queue, ExplicitKey(parseKey))
}
func Enqueue(logger logr.Logger, queue workqueue.RateLimitingInterface, obj interface{}, parseKey keyFunc) {
if key, err := parseKey(obj); err != nil {
logger.Error(err, "failed to compute key name", "obj", obj)
} else { } else {
queue.Add(key) queue.Add(key)
} }
} }
func AddFunc(logger logr.Logger, queue workqueue.RateLimitingInterface) addFunc { func MetaNamespaceKey(obj interface{}) (interface{}, error) {
return func(obj interface{}) { return cache.MetaNamespaceKeyFunc(obj)
Enqueue(logger, queue, obj) }
func ExplicitKey[K any](parseKey func(K) cache.ExplicitKey) keyFunc {
return func(obj interface{}) (interface{}, error) {
if obj == nil {
return nil, errors.New("obj is nil")
}
if key, ok := obj.(K); !ok {
return nil, errors.New("obj cannot be converted")
} else {
return parseKey(key), nil
}
} }
} }
func UpdateFunc(logger logr.Logger, queue workqueue.RateLimitingInterface) updateFunc { func AddFunc(logger logr.Logger, queue workqueue.RateLimitingInterface, parseKey keyFunc) addFunc {
return func(obj interface{}) {
Enqueue(logger, queue, obj, parseKey)
}
}
func UpdateFunc(logger logr.Logger, queue workqueue.RateLimitingInterface, parseKey keyFunc) updateFunc {
return func(_, obj interface{}) { return func(_, obj interface{}) {
Enqueue(logger, queue, obj) Enqueue(logger, queue, obj, parseKey)
} }
} }
func DeleteFunc(logger logr.Logger, queue workqueue.RateLimitingInterface) deleteFunc { func DeleteFunc(logger logr.Logger, queue workqueue.RateLimitingInterface, parseKey keyFunc) deleteFunc {
return func(obj interface{}) { return func(obj interface{}) {
Enqueue(logger, queue, kubeutils.GetObjectWithTombstone(obj)) Enqueue(logger, queue, kubeutils.GetObjectWithTombstone(obj), parseKey)
} }
} }

View file

@ -34,33 +34,40 @@ func worker(logger logr.Logger, queue workqueue.RateLimitingInterface, maxRetrie
} }
func processNextWorkItem(logger logr.Logger, queue workqueue.RateLimitingInterface, maxRetries int, r reconcileFunc) bool { func processNextWorkItem(logger logr.Logger, queue workqueue.RateLimitingInterface, maxRetries int, r reconcileFunc) bool {
if key, quit := queue.Get(); !quit { if obj, quit := queue.Get(); !quit {
defer queue.Done(key) defer queue.Done(obj)
handleErr(logger, queue, maxRetries, reconcile(key.(string), r), key) handleErr(logger, queue, maxRetries, reconcile(obj, r), obj)
return true return true
} }
return false return false
} }
func handleErr(logger logr.Logger, queue workqueue.RateLimitingInterface, maxRetries int, err error, key interface{}) { func handleErr(logger logr.Logger, queue workqueue.RateLimitingInterface, maxRetries int, err error, obj interface{}) {
if err == nil { if err == nil {
queue.Forget(key) queue.Forget(obj)
} else if errors.IsNotFound(err) { } else if errors.IsNotFound(err) {
logger.V(4).Info("Dropping request from the queue", "key", key, "error", err.Error()) logger.V(4).Info("Dropping request from the queue", "obj", obj, "error", err.Error())
queue.Forget(key) queue.Forget(obj)
} else if queue.NumRequeues(key) < maxRetries { } else if queue.NumRequeues(obj) < maxRetries {
logger.V(3).Info("Retrying request", "key", key, "error", err.Error()) logger.V(3).Info("Retrying request", "obj", obj, "error", err.Error())
queue.AddRateLimited(key) queue.AddRateLimited(obj)
} else { } else {
logger.Error(err, "Failed to process request", "key", key) logger.Error(err, "Failed to process request", "obj", obj)
queue.Forget(key) queue.Forget(obj)
} }
} }
func reconcile(key string, r reconcileFunc) error { func reconcile(obj interface{}, r reconcileFunc) error {
if namespace, name, err := cache.SplitMetaNamespaceKey(key); err != nil { var k, ns, n string
return err if key, ok := obj.(cache.ExplicitKey); ok {
k = string(key)
} else { } else {
return r(key, namespace, name) k = obj.(string)
if namespace, name, err := cache.SplitMetaNamespaceKey(k); err != nil {
return err
} else {
ns, n = namespace, name
}
} }
return r(k, ns, n)
} }