// NewClusterQuotaMappingController builds a mapping between namespaces and clusterresourcequotas func NewClusterQuotaMappingController(namespaceInformer shared.NamespaceInformer, quotaInformer shared.ClusterResourceQuotaInformer) *ClusterQuotaMappingController { c := &ClusterQuotaMappingController{ namespaceQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "controller_clusterquotamappingcontroller_namespaces"), quotaQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "controller_clusterquotamappingcontroller_clusterquotas"), clusterQuotaMapper: NewClusterQuotaMapper(), } namespaceInformer.Informer().AddEventHandler(framework.ResourceEventHandlerFuncs{ AddFunc: c.addNamespace, UpdateFunc: c.updateNamespace, DeleteFunc: c.deleteNamespace, }) c.namespaceLister = namespaceInformer.Lister() c.namespacesSynced = namespaceInformer.Informer().HasSynced quotaInformer.Informer().AddEventHandler(framework.ResourceEventHandlerFuncs{ AddFunc: c.addQuota, UpdateFunc: c.updateQuota, DeleteFunc: c.deleteQuota, }) c.quotaLister = quotaInformer.Lister() c.quotasSynced = quotaInformer.Informer().HasSynced return c }
// NewServiceAccountsController returns a new *ServiceAccountsController. func NewServiceAccountsController(saInformer informers.ServiceAccountInformer, nsInformer informers.NamespaceInformer, cl clientset.Interface, options ServiceAccountsControllerOptions) *ServiceAccountsController { e := &ServiceAccountsController{ client: cl, serviceAccountsToEnsure: options.ServiceAccounts, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount"), } if cl != nil && cl.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().RESTClient().GetRateLimiter()) } saInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ DeleteFunc: e.serviceAccountDeleted, }) nsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: e.namespaceAdded, UpdateFunc: e.namespaceUpdated, }) e.saSynced = saInformer.Informer().HasSynced e.saLister = saInformer.Lister() e.nsSynced = nsInformer.Informer().HasSynced e.nsLister = nsInformer.Lister() e.syncHandler = e.syncNamespace return e }
func NewBucketingWorkQueue(name string) BucketingWorkQueue { return &workQueueBucket{ queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), name), work: map[interface{}][]interface{}{}, dirtyWork: map[interface{}][]interface{}{}, inProgress: map[interface{}]bool{}, } }
// NewDeploymentController creates a new DeploymentController. func NewDeploymentController(dInformer informers.DeploymentInformer, rsInformer informers.ReplicaSetInformer, podInformer informers.PodInformer, client clientset.Interface) *DeploymentController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) // TODO: remove the wrapper when every clients have moved to use the clientset. eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.Core().Events("")}) if client != nil && client.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("deployment_controller", client.Core().RESTClient().GetRateLimiter()) } dc := &DeploymentController{ client: client, eventRecorder: eventBroadcaster.NewRecorder(v1.EventSource{Component: "deployment-controller"}), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "deployment"), progressQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "progress-check"), } dc.rsControl = controller.RealRSControl{ KubeClient: client, Recorder: dc.eventRecorder, } dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dc.addDeployment, UpdateFunc: dc.updateDeployment, // This will enter the sync loop and no-op, because the deployment has been deleted from the store. DeleteFunc: dc.deleteDeployment, }) rsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dc.addReplicaSet, UpdateFunc: dc.updateReplicaSet, DeleteFunc: dc.deleteReplicaSet, }) podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ DeleteFunc: dc.deletePod, }) dc.syncHandler = dc.syncDeployment dc.enqueueDeployment = dc.enqueue dc.dLister = dInformer.Lister() dc.rsLister = rsInformer.Lister() dc.podLister = podInformer.Lister() dc.dListerSynced = dInformer.Informer().HasSynced dc.rsListerSynced = dInformer.Informer().HasSynced dc.podListerSynced = dInformer.Informer().HasSynced return dc }
func NewJobController(podInformer cache.SharedIndexInformer, kubeClient clientset.Interface) *JobController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) // TODO: remove the wrapper when every clients have moved to use the clientset. eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: kubeClient.Core().Events("")}) if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("job_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } jm := &JobController{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "job-controller"}), }, expectations: controller.NewControllerExpectations(), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "job"), recorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "job-controller"}), } jm.jobStore.Store, jm.jobController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return jm.kubeClient.Batch().Jobs(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return jm.kubeClient.Batch().Jobs(api.NamespaceAll).Watch(options) }, }, &batch.Job{}, // TODO: Can we have much longer period here? replicationcontroller.FullControllerResyncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: jm.enqueueController, UpdateFunc: func(old, cur interface{}) { if job := cur.(*batch.Job); !IsJobFinished(job) { jm.enqueueController(job) } }, DeleteFunc: jm.enqueueController, }, ) podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: jm.addPod, UpdateFunc: jm.updatePod, DeleteFunc: jm.deletePod, }) jm.podStore.Indexer = podInformer.GetIndexer() jm.podStoreSynced = podInformer.HasSynced jm.updateHandler = jm.updateJobStatus jm.syncHandler = jm.syncJob return jm }
// NewPetSetController creates a new petset controller. func NewPetSetController(podInformer framework.SharedIndexInformer, kubeClient *client.Client, resyncPeriod time.Duration) *PetSetController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(kubeClient.Events("")) recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "petset"}) pc := &apiServerPetClient{kubeClient, recorder, &defaultPetHealthChecker{}} psc := &PetSetController{ kubeClient: kubeClient, blockingPetStore: newUnHealthyPetTracker(pc), newSyncer: func(blockingPet *pcb) *petSyncer { return &petSyncer{pc, blockingPet} }, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "petset"), } podInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{ // lookup the petset and enqueue AddFunc: psc.addPod, // lookup current and old petset if labels changed UpdateFunc: psc.updatePod, // lookup petset accounting for deletion tombstones DeleteFunc: psc.deletePod, }) psc.podStore.Indexer = podInformer.GetIndexer() psc.podController = podInformer.GetController() psc.psStore.Store, psc.psController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return psc.kubeClient.Apps().PetSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return psc.kubeClient.Apps().PetSets(api.NamespaceAll).Watch(options) }, }, &apps.PetSet{}, petSetResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: psc.enqueuePetSet, UpdateFunc: func(old, cur interface{}) { oldPS := old.(*apps.PetSet) curPS := cur.(*apps.PetSet) if oldPS.Status.Replicas != curPS.Status.Replicas { glog.V(4).Infof("Observed updated replica count for PetSet: %v, %d->%d", curPS.Name, oldPS.Status.Replicas, curPS.Status.Replicas) } psc.enqueuePetSet(cur) }, DeleteFunc: psc.enqueuePetSet, }, ) // TODO: Watch volumes psc.podStoreSynced = psc.podController.HasSynced psc.syncHandler = psc.Sync return psc }
// newReplicationManager configures a replication manager with the specified event recorder func newReplicationManager(eventRecorder record.EventRecorder, podInformer cache.SharedIndexInformer, kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, burstReplicas int, lookupCacheSize int, garbageCollectorEnabled bool) *ReplicationManager { if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("replication_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } rm := &ReplicationManager{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventRecorder, }, burstReplicas: burstReplicas, expectations: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "replicationmanager"), garbageCollectorEnabled: garbageCollectorEnabled, } rm.rcStore.Indexer, rm.rcController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return rm.kubeClient.Core().ReplicationControllers(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return rm.kubeClient.Core().ReplicationControllers(api.NamespaceAll).Watch(options) }, }, &api.ReplicationController{}, // TODO: Can we have much longer period here? FullControllerResyncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: rm.enqueueController, UpdateFunc: rm.updateRC, // This will enter the sync loop and no-op, because the controller has been deleted from the store. // Note that deleting a controller immediately after scaling it to 0 will not work. The recommended // way of achieving this is by performing a `stop` operation on the controller. DeleteFunc: rm.enqueueController, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: rm.addPod, // This invokes the rc for every pod change, eg: host assignment. Though this might seem like overkill // the most frequent pod update is status, and the associated rc will only list from local storage, so // it should be ok. UpdateFunc: rm.updatePod, DeleteFunc: rm.deletePod, }) rm.podStore.Indexer = podInformer.GetIndexer() rm.podController = podInformer.GetController() rm.syncHandler = rm.syncReplicationController rm.podStoreSynced = rm.podController.HasSynced rm.lookupCache = controller.NewMatchingCache(lookupCacheSize) return rm }
// NewNamespaceController creates a new NamespaceController func NewNamespaceController( kubeClient clientset.Interface, clientPool dynamic.ClientPool, groupVersionResources []unversioned.GroupVersionResource, resyncPeriod time.Duration, finalizerToken api.FinalizerName) *NamespaceController { // create the controller so we can inject the enqueue function namespaceController := &NamespaceController{ kubeClient: kubeClient, clientPool: clientPool, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"), groupVersionResources: groupVersionResources, opCache: operationNotSupportedCache{}, finalizerToken: finalizerToken, } if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("namespace_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } // configure the backing store/controller store, controller := framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return kubeClient.Core().Namespaces().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return kubeClient.Core().Namespaces().Watch(options) }, }, &api.Namespace{}, resyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { namespace := obj.(*api.Namespace) namespaceController.enqueueNamespace(namespace) }, UpdateFunc: func(oldObj, newObj interface{}) { namespace := newObj.(*api.Namespace) namespaceController.enqueueNamespace(namespace) }, }, ) namespaceController.store = store namespaceController.controller = controller return namespaceController }
func NewAPIServiceRegistrationController(apiServerInformer informers.APIServiceInformer, apiHandlerManager APIHandlerManager) *APIServiceRegistrationController { c := &APIServiceRegistrationController{ apiHandlerManager: apiHandlerManager, apiServerLister: apiServerInformer.Lister(), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "APIServiceRegistrationController"), } apiServerInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: c.addAPIService, UpdateFunc: c.updateAPIService, DeleteFunc: c.deleteAPIService, }) c.syncFn = c.sync return c }
// NewEndpointController returns a new *EndpointController. func NewEndpointController(client *clientset.Clientset) *endpointController { e := &endpointController{ client: client, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "endpoint"), } e.serviceStore.Indexer, e.serviceController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().Services(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().Services(api.NamespaceAll).Watch(options) }, }, &api.Service{}, kservice.FullServiceResyncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: e.enqueueService, UpdateFunc: func(old, cur interface{}) { e.enqueueService(cur) }, DeleteFunc: e.enqueueService, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) e.podStore.Indexer, e.podController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, 5*time.Minute, cache.ResourceEventHandlerFuncs{ AddFunc: e.addPod, UpdateFunc: e.updatePod, DeleteFunc: e.deletePod, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return e }
// NewReplicationManager configures a replication manager with the specified event recorder func NewReplicationManager(podInformer, rcInformer cache.SharedIndexInformer, kubeClient clientset.Interface, burstReplicas int, lookupCacheSize int, garbageCollectorEnabled bool) *ReplicationManager { if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("replication_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.Core().Events("")}) rm := &ReplicationManager{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(v1.EventSource{Component: "replication-controller"}), }, burstReplicas: burstReplicas, expectations: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "replicationmanager"), garbageCollectorEnabled: garbageCollectorEnabled, } rcInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: rm.enqueueController, UpdateFunc: rm.updateRC, // This will enter the sync loop and no-op, because the controller has been deleted from the store. // Note that deleting a controller immediately after scaling it to 0 will not work. The recommended // way of achieving this is by performing a `stop` operation on the controller. DeleteFunc: rm.enqueueController, }) podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: rm.addPod, // This invokes the rc for every pod change, eg: host assignment. Though this might seem like overkill // the most frequent pod update is status, and the associated rc will only list from local storage, so // it should be ok. UpdateFunc: rm.updatePod, DeleteFunc: rm.deletePod, }) rm.syncHandler = rm.syncReplicationController rm.rcLister.Indexer = rcInformer.GetIndexer() rm.podLister.Indexer = podInformer.GetIndexer() rm.podListerSynced = podInformer.HasSynced rm.lookupCache = controller.NewMatchingCache(lookupCacheSize) return rm }
func NewJobController(podInformer cache.SharedIndexInformer, jobInformer informers.JobInformer, kubeClient clientset.Interface) *JobController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) // TODO: remove the wrapper when every clients have moved to use the clientset. eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.Core().Events("")}) if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("job_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } jm := &JobController{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(v1.EventSource{Component: "job-controller"}), }, expectations: controller.NewControllerExpectations(), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "job"), recorder: eventBroadcaster.NewRecorder(v1.EventSource{Component: "job-controller"}), } jobInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: jm.enqueueController, UpdateFunc: func(old, cur interface{}) { if job := cur.(*batch.Job); !IsJobFinished(job) { jm.enqueueController(job) } }, DeleteFunc: jm.enqueueController, }) jm.jobLister = jobInformer.Lister() jm.jobStoreSynced = jobInformer.Informer().HasSynced podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: jm.addPod, UpdateFunc: jm.updatePod, DeleteFunc: jm.deletePod, }) jm.podStore.Indexer = podInformer.GetIndexer() jm.podStoreSynced = podInformer.HasSynced jm.updateHandler = jm.updateJobStatus jm.syncHandler = jm.syncJob return jm }
// NewEndpointController returns a new *EndpointController. func NewEndpointController(podInformer cache.SharedIndexInformer, client clientset.Interface) *EndpointController { if client != nil && client.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("endpoint_controller", client.Core().GetRESTClient().GetRateLimiter()) } e := &EndpointController{ client: client, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "endpoint"), } e.serviceStore.Indexer, e.serviceController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().Services(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().Services(api.NamespaceAll).Watch(options) }, }, &api.Service{}, // TODO: Can we have much longer period here? FullServiceResyncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: e.enqueueService, UpdateFunc: func(old, cur interface{}) { e.enqueueService(cur) }, DeleteFunc: e.enqueueService, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: e.addPod, UpdateFunc: e.updatePod, DeleteFunc: e.deletePod, }) e.podStore.Indexer = podInformer.GetIndexer() e.podController = podInformer.GetController() e.podStoreSynced = podInformer.HasSynced return e }
func NewDisruptionController(podInformer cache.SharedIndexInformer, kubeClient internalclientset.Interface) *DisruptionController { dc := &DisruptionController{ kubeClient: kubeClient, podController: podInformer.GetController(), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "disruption"), recheckQueue: workqueue.NewNamedDelayingQueue("disruption-recheck"), broadcaster: record.NewBroadcaster(), } dc.recorder = dc.broadcaster.NewRecorder(api.EventSource{Component: "controllermanager"}) dc.getUpdater = func() updater { return dc.writePdbStatus } dc.podLister.Indexer = podInformer.GetIndexer() podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dc.addPod, UpdateFunc: dc.updatePod, DeleteFunc: dc.deletePod, }) dc.pdbStore, dc.pdbController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.kubeClient.Policy().PodDisruptionBudgets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.kubeClient.Policy().PodDisruptionBudgets(api.NamespaceAll).Watch(options) }, }, &policy.PodDisruptionBudget{}, 30*time.Second, cache.ResourceEventHandlerFuncs{ AddFunc: dc.addDb, UpdateFunc: dc.updateDb, DeleteFunc: dc.removeDb, }, ) dc.pdbLister.Store = dc.pdbStore dc.rcIndexer, dc.rcController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.kubeClient.Core().ReplicationControllers(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.kubeClient.Core().ReplicationControllers(api.NamespaceAll).Watch(options) }, }, &api.ReplicationController{}, 30*time.Second, cache.ResourceEventHandlerFuncs{}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.rcLister.Indexer = dc.rcIndexer dc.rsLister.Indexer, dc.rsController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.kubeClient.Extensions().ReplicaSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.kubeClient.Extensions().ReplicaSets(api.NamespaceAll).Watch(options) }, }, &extensions.ReplicaSet{}, 30*time.Second, cache.ResourceEventHandlerFuncs{}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.rsStore = dc.rsLister.Indexer dc.dIndexer, dc.dController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.kubeClient.Extensions().Deployments(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.kubeClient.Extensions().Deployments(api.NamespaceAll).Watch(options) }, }, &extensions.Deployment{}, 30*time.Second, cache.ResourceEventHandlerFuncs{}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.dLister.Indexer = dc.dIndexer return dc }
func NewDaemonSetsController(podInformer framework.SharedIndexInformer, kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, lookupCacheSize int) *DaemonSetsController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) // TODO: remove the wrapper when every clients have moved to use the clientset. eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: kubeClient.Core().Events("")}) if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("daemon_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } dsc := &DaemonSetsController{ kubeClient: kubeClient, eventRecorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "daemonset-controller"}), podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "daemon-set"}), }, burstReplicas: BurstReplicas, expectations: controller.NewControllerExpectations(), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "daemonset"), } // Manage addition/update of daemon sets. dsc.dsStore.Store, dsc.dsController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dsc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dsc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).Watch(options) }, }, &extensions.DaemonSet{}, // TODO: Can we have much longer period here? FullDaemonSetResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { ds := obj.(*extensions.DaemonSet) glog.V(4).Infof("Adding daemon set %s", ds.Name) dsc.enqueueDaemonSet(ds) }, UpdateFunc: func(old, cur interface{}) { oldDS := old.(*extensions.DaemonSet) curDS := cur.(*extensions.DaemonSet) // We should invalidate the whole lookup cache if a DS's selector has been updated. // // Imagine that you have two RSs: // * old DS1 // * new DS2 // You also have a pod that is attached to DS2 (because it doesn't match DS1 selector). // Now imagine that you are changing DS1 selector so that it is now matching that pod, // in such case we must invalidate the whole cache so that pod could be adopted by DS1 // // This makes the lookup cache less helpful, but selector update does not happen often, // so it's not a big problem if !reflect.DeepEqual(oldDS.Spec.Selector, curDS.Spec.Selector) { dsc.lookupCache.InvalidateAll() } glog.V(4).Infof("Updating daemon set %s", oldDS.Name) dsc.enqueueDaemonSet(curDS) }, DeleteFunc: dsc.deleteDaemonset, }, ) // Watch for creation/deletion of pods. The reason we watch is that we don't want a daemon set to create/delete // more pods until all the effects (expectations) of a daemon set's create/delete have been observed. podInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{ AddFunc: dsc.addPod, UpdateFunc: dsc.updatePod, DeleteFunc: dsc.deletePod, }) dsc.podStore.Indexer = podInformer.GetIndexer() dsc.podController = podInformer.GetController() dsc.podStoreSynced = podInformer.HasSynced // Watch for new nodes or updates to nodes - daemon pods are launched on new nodes, and possibly when labels on nodes change, dsc.nodeStore.Store, dsc.nodeController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dsc.kubeClient.Core().Nodes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dsc.kubeClient.Core().Nodes().Watch(options) }, }, &api.Node{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{ AddFunc: dsc.addNode, UpdateFunc: dsc.updateNode, }, ) dsc.nodeStoreSynced = dsc.nodeController.HasSynced dsc.syncHandler = dsc.syncDaemonSet dsc.lookupCache = controller.NewMatchingCache(lookupCacheSize) return dsc }
// NewTokensController returns a new *TokensController. func NewTokensController(cl clientset.Interface, options TokensControllerOptions) *TokensController { maxRetries := options.MaxRetries if maxRetries == 0 { maxRetries = 10 } e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, syncServiceAccountQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount_tokens_service"), syncSecretQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "serviceaccount_tokens_secret"), maxRetries: maxRetries, } if cl != nil && cl.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().GetRESTClient().GetRateLimiter()) } e.serviceAccounts, e.serviceAccountController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, cache.ResourceEventHandlerFuncs{ AddFunc: e.queueServiceAccountSync, UpdateFunc: e.queueServiceAccountUpdateSync, DeleteFunc: e.queueServiceAccountSync, }, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = tokenSelector return e.client.Core().Secrets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = tokenSelector return e.client.Core().Secrets(api.NamespaceAll).Watch(options) }, }, &api.Secret{}, options.SecretResync, cache.ResourceEventHandlerFuncs{ AddFunc: e.queueSecretSync, UpdateFunc: e.queueSecretUpdateSync, DeleteFunc: e.queueSecretSync, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) return e }
func NewDaemonSetsController(daemonSetInformer informers.DaemonSetInformer, podInformer informers.PodInformer, nodeInformer informers.NodeInformer, kubeClient clientset.Interface, lookupCacheSize int) *DaemonSetsController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) // TODO: remove the wrapper when every clients have moved to use the clientset. eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.Core().Events("")}) if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("daemon_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } dsc := &DaemonSetsController{ kubeClient: kubeClient, eventRecorder: eventBroadcaster.NewRecorder(v1.EventSource{Component: "daemonset-controller"}), podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(v1.EventSource{Component: "daemon-set"}), }, burstReplicas: BurstReplicas, expectations: controller.NewControllerExpectations(), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "daemonset"), } daemonSetInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { ds := obj.(*extensions.DaemonSet) glog.V(4).Infof("Adding daemon set %s", ds.Name) dsc.enqueueDaemonSet(ds) }, UpdateFunc: func(old, cur interface{}) { oldDS := old.(*extensions.DaemonSet) curDS := cur.(*extensions.DaemonSet) // We should invalidate the whole lookup cache if a DS's selector has been updated. // // Imagine that you have two RSs: // * old DS1 // * new DS2 // You also have a pod that is attached to DS2 (because it doesn't match DS1 selector). // Now imagine that you are changing DS1 selector so that it is now matching that pod, // in such case we must invalidate the whole cache so that pod could be adopted by DS1 // // This makes the lookup cache less helpful, but selector update does not happen often, // so it's not a big problem if !reflect.DeepEqual(oldDS.Spec.Selector, curDS.Spec.Selector) { dsc.lookupCache.InvalidateAll() } glog.V(4).Infof("Updating daemon set %s", oldDS.Name) dsc.enqueueDaemonSet(curDS) }, DeleteFunc: dsc.deleteDaemonset, }) dsc.dsStore = daemonSetInformer.Lister() dsc.dsStoreSynced = daemonSetInformer.Informer().HasSynced // Watch for creation/deletion of pods. The reason we watch is that we don't want a daemon set to create/delete // more pods until all the effects (expectations) of a daemon set's create/delete have been observed. podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dsc.addPod, UpdateFunc: dsc.updatePod, DeleteFunc: dsc.deletePod, }) dsc.podStore = podInformer.Lister() dsc.podStoreSynced = podInformer.Informer().HasSynced nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: dsc.addNode, UpdateFunc: dsc.updateNode, }, ) dsc.nodeStoreSynced = nodeInformer.Informer().HasSynced dsc.nodeStore = nodeInformer.Lister() dsc.syncHandler = dsc.syncDaemonSet dsc.lookupCache = controller.NewMatchingCache(lookupCacheSize) return dsc }
// NewNamespaceController creates a new NamespaceController func NewNamespaceController( kubeClient clientset.Interface, clientPool dynamic.ClientPool, groupVersionResourcesFn func() ([]schema.GroupVersionResource, error), resyncPeriod time.Duration, finalizerToken v1.FinalizerName) *NamespaceController { // the namespace deletion code looks at the discovery document to enumerate the set of resources on the server. // it then finds all namespaced resources, and in response to namespace deletion, will call delete on all of them. // unfortunately, the discovery information does not include the list of supported verbs/methods. if the namespace // controller calls LIST/DELETECOLLECTION for a resource, it will get a 405 error from the server and cache that that was the case. // we found in practice though that some auth engines when encountering paths they don't know about may return a 50x. // until we have verbs, we pre-populate resources that do not support list or delete for well-known apis rather than // probing the server once in order to be told no. opCache := &operationNotSupportedCache{ m: make(map[operationKey]bool), } ignoredGroupVersionResources := []schema.GroupVersionResource{ {Group: "", Version: "v1", Resource: "bindings"}, } for _, ignoredGroupVersionResource := range ignoredGroupVersionResources { opCache.setNotSupported(operationKey{op: operationDeleteCollection, gvr: ignoredGroupVersionResource}) opCache.setNotSupported(operationKey{op: operationList, gvr: ignoredGroupVersionResource}) } // create the controller so we can inject the enqueue function namespaceController := &NamespaceController{ kubeClient: kubeClient, clientPool: clientPool, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"), groupVersionResourcesFn: groupVersionResourcesFn, opCache: opCache, finalizerToken: finalizerToken, } if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("namespace_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } // configure the backing store/controller store, controller := cache.NewInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return kubeClient.Core().Namespaces().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return kubeClient.Core().Namespaces().Watch(options) }, }, &v1.Namespace{}, resyncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { namespace := obj.(*v1.Namespace) namespaceController.enqueueNamespace(namespace) }, UpdateFunc: func(oldObj, newObj interface{}) { namespace := newObj.(*v1.Namespace) namespaceController.enqueueNamespace(namespace) }, }, ) namespaceController.store = store namespaceController.controller = controller return namespaceController }
func NewResourceQuotaController(options *ResourceQuotaControllerOptions) *ResourceQuotaController { // build the resource quota controller rq := &ResourceQuotaController{ kubeClient: options.KubeClient, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resourcequota_primary"), missingUsageQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resourcequota_priority"), resyncPeriod: options.ResyncPeriod, registry: options.Registry, replenishmentControllers: []cache.Controller{}, } if options.KubeClient != nil && options.KubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("resource_quota_controller", options.KubeClient.Core().RESTClient().GetRateLimiter()) } // set the synchronization handler rq.syncHandler = rq.syncResourceQuotaFromKey // build the controller that observes quota rq.rqIndexer, rq.rqController = cache.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return rq.kubeClient.Core().ResourceQuotas(v1.NamespaceAll).List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return rq.kubeClient.Core().ResourceQuotas(v1.NamespaceAll).Watch(options) }, }, &v1.ResourceQuota{}, rq.resyncPeriod(), cache.ResourceEventHandlerFuncs{ AddFunc: rq.addQuota, UpdateFunc: func(old, cur interface{}) { // We are only interested in observing updates to quota.spec to drive updates to quota.status. // We ignore all updates to quota.Status because they are all driven by this controller. // IMPORTANT: // We do not use this function to queue up a full quota recalculation. To do so, would require // us to enqueue all quota.Status updates, and since quota.Status updates involve additional queries // that cannot be backed by a cache and result in a full query of a namespace's content, we do not // want to pay the price on spurious status updates. As a result, we have a separate routine that is // responsible for enqueue of all resource quotas when doing a full resync (enqueueAll) oldResourceQuota := old.(*v1.ResourceQuota) curResourceQuota := cur.(*v1.ResourceQuota) if quota.V1Equals(oldResourceQuota.Spec.Hard, curResourceQuota.Spec.Hard) { return } rq.addQuota(curResourceQuota) }, // This will enter the sync loop and no-op, because the controller has been deleted from the store. // Note that deleting a controller immediately after scaling it to 0 will not work. The recommended // way of achieving this is by performing a `stop` operation on the controller. DeleteFunc: rq.enqueueResourceQuota, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) for _, groupKindToReplenish := range options.GroupKindsToReplenish { controllerOptions := &ReplenishmentControllerOptions{ GroupKind: groupKindToReplenish, ResyncPeriod: options.ReplenishmentResyncPeriod, ReplenishmentFunc: rq.replenishQuota, } replenishmentController, err := options.ControllerFactory.NewController(controllerOptions) if err != nil { glog.Warningf("quota controller unable to replenish %s due to %v, changes only accounted during full resync", groupKindToReplenish, err) } else { rq.replenishmentControllers = append(rq.replenishmentControllers, replenishmentController) } } return rq }
// NewDeploymentController creates a new DeploymentController. func NewDeploymentController(client clientset.Interface, resyncPeriod controller.ResyncPeriodFunc) *DeploymentController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) // TODO: remove the wrapper when every clients have moved to use the clientset. eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: client.Core().Events("")}) if client != nil && client.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("deployment_controller", client.Core().GetRESTClient().GetRateLimiter()) } dc := &DeploymentController{ client: client, eventRecorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "deployment-controller"}), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "deployment"), } dc.dStore.Indexer, dc.dController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.client.Extensions().Deployments(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.client.Extensions().Deployments(api.NamespaceAll).Watch(options) }, }, &extensions.Deployment{}, FullDeploymentResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: dc.addDeploymentNotification, UpdateFunc: dc.updateDeploymentNotification, // This will enter the sync loop and no-op, because the deployment has been deleted from the store. DeleteFunc: dc.deleteDeploymentNotification, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.rsStore.Store, dc.rsController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.client.Extensions().ReplicaSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.client.Extensions().ReplicaSets(api.NamespaceAll).Watch(options) }, }, &extensions.ReplicaSet{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{ AddFunc: dc.addReplicaSet, UpdateFunc: dc.updateReplicaSet, DeleteFunc: dc.deleteReplicaSet, }, ) dc.podStore.Indexer, dc.podController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.client.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.client.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{ AddFunc: dc.addPod, UpdateFunc: dc.updatePod, DeleteFunc: dc.deletePod, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.syncHandler = dc.syncDeployment dc.dStoreSynced = dc.dController.HasSynced dc.rsStoreSynced = dc.rsController.HasSynced dc.podStoreSynced = dc.podController.HasSynced return dc }
func NewCertificateController(kubeClient clientset.Interface, syncPeriod time.Duration, caCertFile, caKeyFile string, approveAllKubeletCSRsForGroup string) (*CertificateController, error) { // Send events to the apiserver eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.Core().Events("")}) // Configure cfssl signer // TODO: support non-default policy and remote/pkcs11 signing policy := &config.Signing{ Default: config.DefaultConfig(), } ca, err := local.NewSignerFromFile(caCertFile, caKeyFile, policy) if err != nil { return nil, err } cc := &CertificateController{ kubeClient: kubeClient, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificate"), signer: ca, approveAllKubeletCSRsForGroup: approveAllKubeletCSRsForGroup, } // Manage the addition/update of certificate requests cc.csrStore.Store, cc.csrController = cache.NewInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return cc.kubeClient.Certificates().CertificateSigningRequests().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return cc.kubeClient.Certificates().CertificateSigningRequests().Watch(options) }, }, &certificates.CertificateSigningRequest{}, syncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { csr := obj.(*certificates.CertificateSigningRequest) glog.V(4).Infof("Adding certificate request %s", csr.Name) cc.enqueueCertificateRequest(obj) }, UpdateFunc: func(old, new interface{}) { oldCSR := old.(*certificates.CertificateSigningRequest) glog.V(4).Infof("Updating certificate request %s", oldCSR.Name) cc.enqueueCertificateRequest(new) }, DeleteFunc: func(obj interface{}) { csr, ok := obj.(*certificates.CertificateSigningRequest) if !ok { tombstone, ok := obj.(cache.DeletedFinalStateUnknown) if !ok { glog.V(2).Infof("Couldn't get object from tombstone %#v", obj) return } csr, ok = tombstone.Obj.(*certificates.CertificateSigningRequest) if !ok { glog.V(2).Infof("Tombstone contained object that is not a CSR: %#v", obj) return } } glog.V(4).Infof("Deleting certificate request %s", csr.Name) cc.enqueueCertificateRequest(obj) }, }, ) cc.syncHandler = cc.maybeSignCertificate return cc, nil }
// NewNamespaceController creates a new NamespaceController func NewNamespaceController( kubeClient clientset.Interface, clientPool dynamic.ClientPool, discoverResourcesFn func() ([]*metav1.APIResourceList, error), resyncPeriod time.Duration, finalizerToken v1.FinalizerName) *NamespaceController { opCache := &operationNotSupportedCache{ m: make(map[operationKey]bool), } // pre-fill opCache with the discovery info // // TODO(sttts): get rid of opCache and http 405 logic around it and trust discovery info resources, err := discoverResourcesFn() if err != nil { glog.Fatalf("Failed to get supported resources: %v", err) } deletableGroupVersionResources := []schema.GroupVersionResource{} for _, rl := range resources { gv, err := schema.ParseGroupVersion(rl.GroupVersion) if err != nil { glog.Errorf("Failed to parse GroupVersion %q, skipping: %v", rl.GroupVersion, err) continue } for _, r := range rl.APIResources { gvr := schema.GroupVersionResource{Group: gv.Group, Version: gv.Version, Resource: r.Name} verbs := sets.NewString([]string(r.Verbs)...) if !verbs.Has("delete") { glog.V(6).Infof("Skipping resource %v because it cannot be deleted.", gvr) } for _, op := range []operation{operationList, operationDeleteCollection} { if !verbs.Has(string(op)) { opCache.setNotSupported(operationKey{op: op, gvr: gvr}) } } deletableGroupVersionResources = append(deletableGroupVersionResources, gvr) } } // create the controller so we can inject the enqueue function namespaceController := &NamespaceController{ kubeClient: kubeClient, clientPool: clientPool, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespace"), discoverResourcesFn: discoverResourcesFn, opCache: opCache, finalizerToken: finalizerToken, } if kubeClient != nil && kubeClient.Core().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("namespace_controller", kubeClient.Core().RESTClient().GetRateLimiter()) } // configure the backing store/controller store, controller := cache.NewInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { return kubeClient.Core().Namespaces().List(options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { return kubeClient.Core().Namespaces().Watch(options) }, }, &v1.Namespace{}, resyncPeriod, cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { namespace := obj.(*v1.Namespace) namespaceController.enqueueNamespace(namespace) }, UpdateFunc: func(oldObj, newObj interface{}) { namespace := newObj.(*v1.Namespace) namespaceController.enqueueNamespace(namespace) }, }, ) namespaceController.store = store namespaceController.controller = controller return namespaceController }