package policycache import ( "context" "github.com/go-logr/logr" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" kyvernov1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1" kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" pcache "github.com/kyverno/kyverno/pkg/policycache" controllerutils "github.com/kyverno/kyverno/pkg/utils/controller" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" ) const ( maxRetries = 10 workers = 3 ) type controller struct { cache pcache.Cache // listers cpolLister kyvernov1listers.ClusterPolicyLister polLister kyvernov1listers.PolicyLister // cpolSynced returns true if the cluster policy shared informer has synced at least once cpolSynced cache.InformerSynced // polSynced returns true if the policy shared informer has synced at least once polSynced cache.InformerSynced // queue queue workqueue.RateLimitingInterface } func NewController(pcache pcache.Cache, cpolInformer kyvernov1informers.ClusterPolicyInformer, polInformer kyvernov1informers.PolicyInformer) *controller { c := controller{ cache: pcache, cpolLister: cpolInformer.Lister(), polLister: polInformer.Lister(), cpolSynced: cpolInformer.Informer().HasSynced, polSynced: polInformer.Informer().HasSynced, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), controllerName), } controllerutils.AddDefaultEventHandlers(logger.V(3), cpolInformer.Informer(), c.queue) controllerutils.AddDefaultEventHandlers(logger.V(3), polInformer.Informer(), c.queue) return &c } func (c *controller) WarmUp() error { logger.Info("warming up ...") defer logger.Info("warm up done") pols, err := c.polLister.Policies(metav1.NamespaceAll).List(labels.Everything()) if err != nil { return err } for _, policy := range pols { if key, err := cache.MetaNamespaceKeyFunc(policy); err != nil { return err } else { c.cache.Set(key, policy) } } cpols, err := c.cpolLister.List(labels.Everything()) if err != nil { return err } for _, policy := range cpols { if key, err := cache.MetaNamespaceKeyFunc(policy); err != nil { return err } else { c.cache.Set(key, policy) } } return nil } func (c *controller) Run(ctx context.Context) { controllerutils.Run(ctx, controllerName, logger.V(3), c.queue, workers, maxRetries, c.reconcile, c.cpolSynced, c.polSynced) } func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, namespace, name string) error { policy, err := c.loadPolicy(namespace, name) if err != nil { if errors.IsNotFound(err) { c.cache.Unset(key) } return err } // TODO: check resource version ? c.cache.Set(key, policy) return nil } func (c *controller) loadPolicy(namespace, name string) (kyvernov1.PolicyInterface, error) { if namespace == "" { return c.cpolLister.Get(name) } else { return c.polLister.Policies(namespace).Get(name) } }