1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/gencontroller/controller.go
2019-07-23 03:07:11 -04:00

164 lines
4.6 KiB
Go

package gencontroller
import (
"fmt"
"time"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/annotations"
policyLister "github.com/nirmata/kyverno/pkg/client/listers/policy/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/event"
policySharedInformer "github.com/nirmata/kyverno/pkg/sharedinformer"
"github.com/nirmata/kyverno/pkg/violation"
"k8s.io/apimachinery/pkg/api/errors"
v1Informer "k8s.io/client-go/informers/core/v1"
v1CoreLister "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
//Controller watches the 'Namespace' resource creation/update and applied the generation rules on them
type Controller struct {
client *client.Client
namespaceLister v1CoreLister.NamespaceLister
namespaceSynced cache.InformerSynced
policyLister policyLister.PolicyLister
eventController event.Generator
violationBuilder violation.Generator
annotationsController annotations.Controller
workqueue workqueue.RateLimitingInterface
}
//NewGenController returns a new Controller to manage generation rules
func NewGenController(client *client.Client,
eventController event.Generator,
policyInformer policySharedInformer.PolicyInformer,
violationBuilder violation.Generator,
namespaceInformer v1Informer.NamespaceInformer,
annotationsController annotations.Controller) *Controller {
// create the controller
controller := &Controller{
client: client,
namespaceLister: namespaceInformer.Lister(),
namespaceSynced: namespaceInformer.Informer().HasSynced,
policyLister: policyInformer.GetLister(),
eventController: eventController,
violationBuilder: violationBuilder,
annotationsController: annotationsController,
workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), wqNamespace),
}
namespaceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: controller.createNamespaceHandler,
UpdateFunc: controller.updateNamespaceHandler,
})
return controller
}
func (c *Controller) createNamespaceHandler(resource interface{}) {
c.enqueueNamespace(resource)
}
func (c *Controller) updateNamespaceHandler(oldResoruce, newResource interface{}) {
// DO we need to anything if the namespace is modified ?
}
func (c *Controller) enqueueNamespace(obj interface{}) {
var key string
var err error
if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
glog.Error(err)
return
}
c.workqueue.Add(key)
}
//Run to run the controller
func (c *Controller) Run(stopCh <-chan struct{}) error {
if ok := cache.WaitForCacheSync(stopCh, c.namespaceSynced); !ok {
return fmt.Errorf("failed to wait for caches to sync")
}
for i := 0; i < workerCount; i++ {
go wait.Until(c.runWorker, time.Second, stopCh)
}
glog.Info("started namespace controller workers")
return nil
}
//Stop to stop the controller
func (c *Controller) Stop() {
defer c.workqueue.ShutDown()
glog.Info("shutting down namespace controller workers")
}
func (c *Controller) runWorker() {
for c.processNextWorkItem() {
}
}
func (c *Controller) processNextWorkItem() bool {
obj, shutdown := c.workqueue.Get()
if shutdown {
return false
}
err := func(obj interface{}) error {
defer c.workqueue.Done(obj)
err := c.syncHandler(obj)
c.handleErr(err, obj)
return nil
}(obj)
if err != nil {
glog.Error(err)
return true
}
return true
}
func (c *Controller) handleErr(err error, key interface{}) {
if err == nil {
c.workqueue.Forget(key)
return
}
if c.workqueue.NumRequeues(key) < wqRetryLimit {
glog.Warningf("Error syncing events %v: %v", key, err)
c.workqueue.AddRateLimited(key)
return
}
c.workqueue.Forget(key)
glog.Error(err)
glog.Warningf("Dropping the key %q out of the queue: %v", key, err)
}
func (c *Controller) syncHandler(obj interface{}) error {
var key string
var ok bool
if key, ok = obj.(string); !ok {
return fmt.Errorf("expected string in workqueue but got %v", obj)
}
// Namespace is cluster wide resource
_, name, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
glog.Errorf("invalid namespace key: %s", key)
return err
}
// Get Namespace
ns, err := c.namespaceLister.Get(name)
if err != nil {
if errors.IsNotFound(err) {
glog.Errorf("namespace '%s' in work queue no longer exists", key)
return nil
}
}
//TODO: need to find a way to store the policy such that we can directly queury the
// policies with generation policies
// PolicyListerExpansion
c.processNamespace(ns)
return nil
}