package policycache import ( "reflect" "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1" "k8s.io/client-go/tools/cache" ) // Controller is responsible for synchronizing Policy Cache, // it embeds a policy informer to handle policy events. // The cache is synced when a policy is add/update/delete. // This cache is only used in the admission webhook to fast retrieve // policies based on types (Mutate/ValidateEnforce/Generate). type Controller struct { pSynched cache.InformerSynced nspSynched cache.InformerSynced Cache Interface log logr.Logger } // NewPolicyCacheController create a new PolicyController func NewPolicyCacheController( pInformer kyvernoinformer.ClusterPolicyInformer, nspInformer kyvernoinformer.PolicyInformer, log logr.Logger) *Controller { pc := Controller{ Cache: newPolicyCache(log, pInformer.Lister(), nspInformer.Lister()), log: log, } // ClusterPolicy Informer pInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: pc.addPolicy, UpdateFunc: pc.updatePolicy, DeleteFunc: pc.deletePolicy, }) // Policy Informer nspInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: pc.addNsPolicy, UpdateFunc: pc.updateNsPolicy, DeleteFunc: pc.deleteNsPolicy, }) pc.pSynched = pInformer.Informer().HasSynced pc.nspSynched = nspInformer.Informer().HasSynced return &pc } // convertPolicyToClusterPolicy - convert Policy to ClusterPolicy // This will retain the kind of Policy and convert type to ClusterPolicy func convertPolicyToClusterPolicy(nsPolicies *kyverno.Policy) *kyverno.ClusterPolicy { cpol := kyverno.ClusterPolicy(*nsPolicies) return &cpol } func (c *Controller) addPolicy(obj interface{}) { p := obj.(*kyverno.ClusterPolicy) c.Cache.Add(p) } func (c *Controller) updatePolicy(old, cur interface{}) { pOld := old.(*kyverno.ClusterPolicy) pNew := cur.(*kyverno.ClusterPolicy) if reflect.DeepEqual(pOld.Spec, pNew.Spec) { return } c.Cache.Remove(pOld) c.Cache.Add(pNew) } func (c *Controller) deletePolicy(obj interface{}) { p := obj.(*kyverno.ClusterPolicy) c.Cache.Remove(p) } // addNsPolicy - Add Policy to cache func (c *Controller) addNsPolicy(obj interface{}) { p := obj.(*kyverno.Policy) c.Cache.Add(convertPolicyToClusterPolicy(p)) } // updateNsPolicy - Update Policy of cache func (c *Controller) updateNsPolicy(old, cur interface{}) { npOld := old.(*kyverno.Policy) npNew := cur.(*kyverno.Policy) if reflect.DeepEqual(npOld.Spec, npNew.Spec) { return } c.Cache.Remove(convertPolicyToClusterPolicy(npOld)) c.Cache.Add(convertPolicyToClusterPolicy(npNew)) } // deleteNsPolicy - Delete Policy from cache func (c *Controller) deleteNsPolicy(obj interface{}) { p := obj.(*kyverno.Policy) c.Cache.Remove(convertPolicyToClusterPolicy(p)) } // Run waits until policy informer to be synced func (c *Controller) Run(workers int, stopCh <-chan struct{}) { logger := c.log logger.Info("starting") defer logger.Info("shutting down") if !cache.WaitForCacheSync(stopCh, c.pSynched) { logger.Info("failed to sync informer cache") return } <-stopCh }