// NewTokensController returns a new *TokensController. func NewTokensController(cl clientset.Interface, options TokensControllerOptions) *TokensController { e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, } if cl != nil && cl.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().GetRESTClient().GetRateLimiter()) } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &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, framework.ResourceEventHandlerFuncs{ AddFunc: e.serviceAccountAdded, UpdateFunc: e.serviceAccountUpdated, DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) tokenSelector := fields.SelectorFromSet(map[string]string{api.SecretTypeField: string(api.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = framework.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, framework.ResourceEventHandlerFuncs{ AddFunc: e.secretAdded, UpdateFunc: e.secretUpdated, DeleteFunc: e.secretDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.serviceAccountsSynced = e.serviceAccountController.HasSynced e.secretsSynced = e.secretController.HasSynced return e }
// NewTokensController returns a new *TokensController. func NewTokensController(cl client.Interface, options TokensControllerOptions) *TokensController { e := &TokensController{ client: cl, token: options.TokenGenerator, rootCA: options.RootCA, } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options unversioned.ListOptions) (runtime.Object, error) { return e.client.ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { return e.client.ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.serviceAccountAdded, UpdateFunc: e.serviceAccountUpdated, DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) tokenSelector := fields.SelectorFromSet(map[string]string{client.SecretType: string(api.SecretTypeServiceAccountToken)}) e.secrets, e.secretController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options unversioned.ListOptions) (runtime.Object, error) { options.FieldSelector.Selector = tokenSelector return e.client.Secrets(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { options.FieldSelector.Selector = tokenSelector return e.client.Secrets(api.NamespaceAll).Watch(options) }, }, &api.Secret{}, options.SecretResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.secretAdded, UpdateFunc: e.secretUpdated, DeleteFunc: e.secretDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.serviceAccountsSynced = e.serviceAccountController.HasSynced e.secretsSynced = e.secretController.HasSynced return e }
// NewServiceAccountsController returns a new *ServiceAccountsController. func NewServiceAccountsController(cl clientset.Interface, options ServiceAccountsControllerOptions) *ServiceAccountsController { e := &ServiceAccountsController{ client: cl, serviceAccountsToEnsure: options.ServiceAccounts, } if cl != nil && cl.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("serviceaccount_controller", cl.Core().GetRESTClient().GetRateLimiter()) } accountSelector := fields.Everything() if len(options.ServiceAccounts) == 1 { // If we're maintaining a single account, we can scope the accounts we watch to just that name accountSelector = fields.SelectorFromSet(map[string]string{api.ObjectNameField: options.ServiceAccounts[0].Name}) } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = accountSelector return e.client.Core().ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = accountSelector return e.client.Core().ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.namespaces, e.namespaceController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return e.client.Core().Namespaces().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return e.client.Core().Namespaces().Watch(options) }, }, &api.Namespace{}, options.NamespaceResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.namespaceAdded, UpdateFunc: e.namespaceUpdated, }, cache.Indexers{"name": nameIndexFunc}, ) return e }
// NewServiceAccountsController returns a new *ServiceAccountsController. func NewServiceAccountsController(cl client.Interface, options ServiceAccountsControllerOptions) *ServiceAccountsController { e := &ServiceAccountsController{ client: cl, serviceAccountsToEnsure: options.ServiceAccounts, } accountSelector := fields.Everything() if len(options.ServiceAccounts) == 1 { // If we're maintaining a single account, we can scope the accounts we watch to just that name accountSelector = fields.SelectorFromSet(map[string]string{client.ObjectNameField: options.ServiceAccounts[0].Name}) } e.serviceAccounts, e.serviceAccountController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{accountSelector}} return e.client.ServiceAccounts(api.NamespaceAll).List(options) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { options.FieldSelector.Selector = accountSelector return e.client.ServiceAccounts(api.NamespaceAll).Watch(options) }, }, &api.ServiceAccount{}, options.ServiceAccountResync, framework.ResourceEventHandlerFuncs{ DeleteFunc: e.serviceAccountDeleted, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) e.namespaces, e.namespaceController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func() (runtime.Object, error) { return e.client.Namespaces().List(unversioned.ListOptions{}) }, WatchFunc: func(options unversioned.ListOptions) (watch.Interface, error) { return e.client.Namespaces().Watch(options) }, }, &api.Namespace{}, options.NamespaceResync, framework.ResourceEventHandlerFuncs{ AddFunc: e.namespaceAdded, UpdateFunc: e.namespaceUpdated, }, cache.Indexers{"name": nameIndexFunc}, ) return e }
func New(kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, threshold int) *GCController { if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("gc_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } gcc := &GCController{ kubeClient: kubeClient, threshold: threshold, deletePod: func(namespace, name string) error { return kubeClient.Core().Pods(namespace).Delete(name, api.NewDeleteOptions(0)) }, } terminatedSelector := fields.ParseSelectorOrDie("status.phase!=" + string(api.PodPending) + ",status.phase!=" + string(api.PodRunning) + ",status.phase!=" + string(api.PodUnknown)) gcc.podStore.Indexer, gcc.podStoreSyncer = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { options.FieldSelector = terminatedSelector return gcc.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { options.FieldSelector = terminatedSelector return gcc.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{}, // We don't need to build a index for podStore here actually, but build one for consistency. // It will ensure that if people start making use of the podStore in more specific ways, // they'll get the benefits they expect. It will also reserve the name for future refactorings. cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return gcc }
// 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.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), syncSecretQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), maxRetries: maxRetries, } e.serviceAccounts, e.serviceAccountController = framework.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, framework.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 = framework.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, framework.ResourceEventHandlerFuncs{ AddFunc: e.queueSecretSync, UpdateFunc: e.queueSecretUpdateSync, DeleteFunc: e.queueSecretSync, }, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}, ) return e }
// newReplicationManager configures a replication manager with the specified event recorder func newReplicationManager(eventRecorder record.EventRecorder, podInformer framework.SharedIndexInformer, kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, burstReplicas int, lookupCacheSize int, garbageCollectorEnabled bool) *ReplicationManager { if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("replication_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } rm := &ReplicationManager{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventRecorder, }, burstReplicas: burstReplicas, expectations: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()), queue: workqueue.New(), garbageCollectorEnabled: garbageCollectorEnabled, } rm.rcStore.Indexer, rm.rcController = framework.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, framework.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(framework.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 }
// Initializes the factory. func NewConfigFactory(client *client.Client, schedulerName string, hardPodAffinitySymmetricWeight int, failureDomains string) *ConfigFactory { stopEverything := make(chan struct{}) schedulerCache := schedulercache.New(30*time.Second, stopEverything) c := &ConfigFactory{ Client: client, PodQueue: cache.NewFIFO(cache.MetaNamespaceKeyFunc), ScheduledPodLister: &cache.StoreToPodLister{}, // Only nodes in the "Ready" condition with status == "True" are schedulable NodeLister: &cache.StoreToNodeLister{}, PVLister: &cache.StoreToPVFetcher{Store: cache.NewStore(cache.MetaNamespaceKeyFunc)}, PVCLister: &cache.StoreToPVCFetcher{Store: cache.NewStore(cache.MetaNamespaceKeyFunc)}, ServiceLister: &cache.StoreToServiceLister{Store: cache.NewStore(cache.MetaNamespaceKeyFunc)}, ControllerLister: &cache.StoreToReplicationControllerLister{Indexer: cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})}, ReplicaSetLister: &cache.StoreToReplicaSetLister{Store: cache.NewStore(cache.MetaNamespaceKeyFunc)}, schedulerCache: schedulerCache, StopEverything: stopEverything, SchedulerName: schedulerName, HardPodAffinitySymmetricWeight: hardPodAffinitySymmetricWeight, FailureDomains: failureDomains, } c.PodLister = schedulerCache // On add/delete to the scheduled pods, remove from the assumed pods. // We construct this here instead of in CreateFromKeys because // ScheduledPodLister is something we provide to plug in functions that // they may need to call. c.ScheduledPodLister.Indexer, c.scheduledPodPopulator = framework.NewIndexerInformer( c.createAssignedNonTerminatedPodLW(), &api.Pod{}, 0, framework.ResourceEventHandlerFuncs{ AddFunc: c.addPodToCache, UpdateFunc: c.updatePodInCache, DeleteFunc: c.deletePodFromCache, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) c.NodeLister.Store, c.nodePopulator = framework.NewInformer( c.createNodeLW(), &api.Node{}, 0, framework.ResourceEventHandlerFuncs{ AddFunc: c.addNodeToCache, UpdateFunc: c.updateNodeInCache, DeleteFunc: c.deleteNodeFromCache, }, ) return c }
//NewPodWatcher creates a new BuildPodWatcher useful to list the pods using a cache which gets updated based on the watch func. func NewPodWatcher(c *client.Client, ns string) *PodWatcher { pw := &PodWatcher{} pw.Store.Store, pw.Controller = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: podListFunc(c, ns), WatchFunc: podWatchFunc(c, ns), }, &api.Pod{}, resyncPeriod, framework.ResourceEventHandlerFuncs{}, cache.Indexers{}, ) return pw }
// NewEndpointController returns a new *EndpointController. func NewEndpointController(client *clientset.Clientset) *endpointController { e := &endpointController{ client: client, queue: workqueue.New(), } e.serviceStore.Store, e.serviceController = framework.NewInformer( &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, framework.ResourceEventHandlerFuncs{ AddFunc: e.enqueueService, UpdateFunc: func(old, cur interface{}) { e.enqueueService(cur) }, DeleteFunc: e.enqueueService, }, ) e.podStore.Indexer, e.podController = framework.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, framework.ResourceEventHandlerFuncs{ AddFunc: e.addPod, UpdateFunc: e.updatePod, DeleteFunc: e.deletePod, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) return e }
// NewPersistentVolumeController creates a new PersistentVolumeController func NewPersistentVolumeController( kubeClient clientset.Interface, syncPeriod time.Duration, provisioner vol.ProvisionableVolumePlugin, recyclers []vol.VolumePlugin, cloud cloudprovider.Interface, clusterName string, volumeSource, claimSource cache.ListerWatcher, eventRecorder record.EventRecorder, enableDynamicProvisioning bool, ) *PersistentVolumeController { if eventRecorder == nil { broadcaster := record.NewBroadcaster() broadcaster.StartRecordingToSink(&unversioned_core.EventSinkImpl{Interface: kubeClient.Core().Events("")}) eventRecorder = broadcaster.NewRecorder(api.EventSource{Component: "persistentvolume-controller"}) } controller := &PersistentVolumeController{ volumes: newPersistentVolumeOrderedIndex(), claims: cache.NewStore(framework.DeletionHandlingMetaNamespaceKeyFunc), kubeClient: kubeClient, eventRecorder: eventRecorder, runningOperations: goroutinemap.NewGoRoutineMap(false /* exponentialBackOffOnError */), cloud: cloud, provisioner: provisioner, enableDynamicProvisioning: enableDynamicProvisioning, clusterName: clusterName, createProvisionedPVRetryCount: createProvisionedPVRetryCount, createProvisionedPVInterval: createProvisionedPVInterval, } controller.recyclePluginMgr.InitPlugins(recyclers, controller) if controller.provisioner != nil { if err := controller.provisioner.Init(controller); err != nil { glog.Errorf("PersistentVolumeController: error initializing provisioner plugin: %v", err) } } if volumeSource == nil { volumeSource = &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return kubeClient.Core().PersistentVolumes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return kubeClient.Core().PersistentVolumes().Watch(options) }, } } controller.volumeSource = volumeSource if claimSource == nil { claimSource = &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return kubeClient.Core().PersistentVolumeClaims(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return kubeClient.Core().PersistentVolumeClaims(api.NamespaceAll).Watch(options) }, } } controller.claimSource = claimSource _, controller.volumeController = framework.NewIndexerInformer( volumeSource, &api.PersistentVolume{}, syncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: controller.addVolume, UpdateFunc: controller.updateVolume, DeleteFunc: controller.deleteVolume, }, cache.Indexers{"accessmodes": accessModesIndexFunc}, ) _, controller.claimController = framework.NewInformer( claimSource, &api.PersistentVolumeClaim{}, syncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: controller.addClaim, UpdateFunc: controller.updateClaim, DeleteFunc: controller.deleteClaim, }, ) return controller }
func NewResourceQuotaController(options *ResourceQuotaControllerOptions) *ResourceQuotaController { // build the resource quota controller rq := &ResourceQuotaController{ kubeClient: options.KubeClient, queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), resyncPeriod: options.ResyncPeriod, registry: options.Registry, replenishmentControllers: []framework.ControllerInterface{}, } if options.KubeClient != nil && options.KubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("resource_quota_controller", options.KubeClient.Core().GetRESTClient().GetRateLimiter()) } // set the synchronization handler rq.syncHandler = rq.syncResourceQuotaFromKey // build the controller that observes quota rq.rqIndexer, rq.rqController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return rq.kubeClient.Core().ResourceQuotas(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return rq.kubeClient.Core().ResourceQuotas(api.NamespaceAll).Watch(options) }, }, &api.ResourceQuota{}, rq.resyncPeriod(), framework.ResourceEventHandlerFuncs{ AddFunc: rq.enqueueResourceQuota, 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.(*api.ResourceQuota) curResourceQuota := cur.(*api.ResourceQuota) if quota.Equals(curResourceQuota.Spec.Hard, oldResourceQuota.Spec.Hard) { return } rq.enqueueResourceQuota(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 }
// NewResourceQuotaController creates a new ResourceQuotaController func NewResourceQuotaController(kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc) *ResourceQuotaController { rq := &ResourceQuotaController{ kubeClient: kubeClient, queue: workqueue.New(), resyncPeriod: resyncPeriod, } rq.rqIndexer, rq.rqController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return rq.kubeClient.Core().ResourceQuotas(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return rq.kubeClient.Core().ResourceQuotas(api.NamespaceAll).Watch(options) }, }, &api.ResourceQuota{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{ AddFunc: rq.enqueueResourceQuota, 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.(*api.ResourceQuota) curResourceQuota := cur.(*api.ResourceQuota) if api.Semantic.DeepEqual(oldResourceQuota.Spec.Hard, curResourceQuota.Status.Hard) { return } glog.V(4).Infof("Observed updated quota spec for %v/%v", curResourceQuota.Namespace, curResourceQuota.Name) rq.enqueueResourceQuota(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}, ) // We use this pod controller to rapidly observe when a pod deletion occurs in order to // release compute resources from any associated quota. rq.podStore.Store, rq.podController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return rq.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return rq.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{ DeleteFunc: rq.deletePod, }, ) // set the synchronization handler rq.syncHandler = rq.syncResourceQuotaFromKey return rq }
// NewReplicaSetController creates a new ReplicaSetController. func NewReplicaSetController(kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, burstReplicas int, lookupCacheSize int) *ReplicaSetController { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: kubeClient.Core().Events("")}) if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("replicaset_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } rsc := &ReplicaSetController{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "replicaset-controller"}), }, burstReplicas: burstReplicas, expectations: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()), queue: workqueue.New(), } rsc.rsStore.Store, rsc.rsController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return rsc.kubeClient.Extensions().ReplicaSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return rsc.kubeClient.Extensions().ReplicaSets(api.NamespaceAll).Watch(options) }, }, &extensions.ReplicaSet{}, // TODO: Can we have much longer period here? FullControllerResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: rsc.enqueueReplicaSet, UpdateFunc: func(old, cur interface{}) { oldRS := old.(*extensions.ReplicaSet) curRS := cur.(*extensions.ReplicaSet) // We should invalidate the whole lookup cache if a RS's selector has been updated. // // Imagine that you have two RSs: // * old RS1 // * new RS2 // You also have a pod that is attached to RS2 (because it doesn't match RS1 selector). // Now imagine that you are changing RS1 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 RS1 // // This makes the lookup cache less helpful, but selector update does not happen often, // so it's not a big problem if !reflect.DeepEqual(oldRS.Spec.Selector, curRS.Spec.Selector) { rsc.lookupCache.InvalidateAll() } // You might imagine that we only really need to enqueue the // replica set when Spec changes, but it is safer to sync any // time this function is triggered. That way a full informer // resync can requeue any replica set that don't yet have pods // but whose last attempts at creating a pod have failed (since // we don't block on creation of pods) instead of those // replica sets stalling indefinitely. Enqueueing every time // does result in some spurious syncs (like when Status.Replica // is updated and the watch notification from it retriggers // this function), but in general extra resyncs shouldn't be // that bad as ReplicaSets that haven't met expectations yet won't // sync, and all the listing is done using local stores. if oldRS.Status.Replicas != curRS.Status.Replicas { glog.V(4).Infof("Observed updated replica count for ReplicaSet: %v, %d->%d", curRS.Name, oldRS.Status.Replicas, curRS.Status.Replicas) } rsc.enqueueReplicaSet(cur) }, // This will enter the sync loop and no-op, because the replica set has been deleted from the store. // Note that deleting a replica set immediately after scaling it to 0 will not work. The recommended // way of achieving this is by performing a `stop` operation on the replica set. DeleteFunc: rsc.enqueueReplicaSet, }, ) rsc.podStore.Indexer, rsc.podController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return rsc.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return rsc.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, resyncPeriod(), framework.ResourceEventHandlerFuncs{ AddFunc: rsc.addPod, // This invokes the ReplicaSet for every pod change, eg: host assignment. Though this might seem like // overkill the most frequent pod update is status, and the associated ReplicaSet will only list from // local storage, so it should be ok. UpdateFunc: rsc.updatePod, DeleteFunc: rsc.deletePod, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) rsc.syncHandler = rsc.syncReplicaSet rsc.podStoreSynced = rsc.podController.HasSynced rsc.lookupCache = controller.NewMatchingCache(lookupCacheSize) return rsc }
// NewNodeController returns a new node controller to sync instances from cloudprovider. func NewNodeController( cloud cloudprovider.Interface, kubeClient clientset.Interface, podEvictionTimeout time.Duration, deletionEvictionLimiter flowcontrol.RateLimiter, terminationEvictionLimiter flowcontrol.RateLimiter, nodeMonitorGracePeriod time.Duration, nodeStartupGracePeriod time.Duration, nodeMonitorPeriod time.Duration, clusterCIDR *net.IPNet, serviceCIDR *net.IPNet, nodeCIDRMaskSize int, allocateNodeCIDRs bool) *NodeController { eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "controllermanager"}) eventBroadcaster.StartLogging(glog.Infof) if kubeClient != nil { glog.V(0).Infof("Sending events to api server.") eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: kubeClient.Core().Events("")}) } else { glog.V(0).Infof("No api server defined - no events will be sent to API server.") } if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("node_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } if allocateNodeCIDRs { if clusterCIDR == nil { glog.Fatal("NodeController: Must specify clusterCIDR if allocateNodeCIDRs == true.") } mask := clusterCIDR.Mask if maskSize, _ := mask.Size(); maskSize > nodeCIDRMaskSize { glog.Fatal("NodeController: Invalid clusterCIDR, mask size of clusterCIDR must be less than nodeCIDRMaskSize.") } } evictorLock := sync.Mutex{} nc := &NodeController{ cloud: cloud, knownNodeSet: make(sets.String), kubeClient: kubeClient, recorder: recorder, podEvictionTimeout: podEvictionTimeout, maximumGracePeriod: 5 * time.Minute, evictorLock: &evictorLock, podEvictor: NewRateLimitedTimedQueue(deletionEvictionLimiter), terminationEvictor: NewRateLimitedTimedQueue(terminationEvictionLimiter), nodeStatusMap: make(map[string]nodeStatusData), nodeMonitorGracePeriod: nodeMonitorGracePeriod, nodeMonitorPeriod: nodeMonitorPeriod, nodeStartupGracePeriod: nodeStartupGracePeriod, lookupIP: net.LookupIP, now: unversioned.Now, clusterCIDR: clusterCIDR, serviceCIDR: serviceCIDR, allocateNodeCIDRs: allocateNodeCIDRs, forcefullyDeletePod: func(p *api.Pod) error { return forcefullyDeletePod(kubeClient, p) }, nodeExistsInCloudProvider: func(nodeName string) (bool, error) { return nodeExistsInCloudProvider(cloud, nodeName) }, nodeCIDRUpdateChannel: make(chan nodeAndCIDR, cidrUpdateQueueSize), } nc.podStore.Indexer, nc.podController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, controller.NoResyncPeriodFunc(), framework.ResourceEventHandlerFuncs{ AddFunc: nc.maybeDeleteTerminatingPod, UpdateFunc: func(_, obj interface{}) { nc.maybeDeleteTerminatingPod(obj) }, }, // We don't need to build a index for podStore here actually, but build one for consistency. // It will ensure that if people start making use of the podStore in more specific ways, // they'll get the benefits they expect. It will also reserve the name for future refactorings. cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) nodeEventHandlerFuncs := framework.ResourceEventHandlerFuncs{} if nc.allocateNodeCIDRs { nodeEventHandlerFuncs = framework.ResourceEventHandlerFuncs{ AddFunc: nc.allocateOrOccupyCIDR, DeleteFunc: nc.recycleCIDR, } } nc.nodeStore.Store, nc.nodeController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Core().Nodes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Core().Nodes().Watch(options) }, }, &api.Node{}, controller.NoResyncPeriodFunc(), nodeEventHandlerFuncs, ) nc.daemonSetStore.Store, nc.daemonSetController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).Watch(options) }, }, &extensions.DaemonSet{}, controller.NoResyncPeriodFunc(), framework.ResourceEventHandlerFuncs{}, ) if allocateNodeCIDRs { nc.cidrAllocator = NewCIDRRangeAllocator(clusterCIDR, nodeCIDRMaskSize) } return nc }
// NewLoadBalancerController creates a controller for gce loadbalancers. // - kubeClient: A kubernetes REST client. // - clusterManager: A ClusterManager capable of creating all cloud resources // required for L7 loadbalancing. // - resyncPeriod: Watchers relist from the Kubernetes API server this often. func NewLoadBalancerController(kubeClient *client.Client, clusterManager *ClusterManager, resyncPeriod time.Duration, namespace string) (*LoadBalancerController, error) { eventBroadcaster := record.NewBroadcaster() eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(kubeClient.Events("")) lbc := LoadBalancerController{ client: kubeClient, CloudClusterManager: clusterManager, stopCh: make(chan struct{}), recorder: eventBroadcaster.NewRecorder( api.EventSource{Component: "loadbalancer-controller"}), } lbc.nodeQueue = NewTaskQueue(lbc.syncNodes) lbc.ingQueue = NewTaskQueue(lbc.sync) lbc.hasSynced = lbc.storesSynced // Ingress watch handlers pathHandlers := framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { addIng := obj.(*extensions.Ingress) if !isGCEIngress(addIng) { glog.Infof("Ignoring add for ingress %v based on annotation %v", addIng.Name, ingressClassKey) return } lbc.recorder.Eventf(addIng, api.EventTypeNormal, "ADD", fmt.Sprintf("%s/%s", addIng.Namespace, addIng.Name)) lbc.ingQueue.enqueue(obj) }, DeleteFunc: func(obj interface{}) { delIng := obj.(*extensions.Ingress) if !isGCEIngress(delIng) { glog.Infof("Ignoring delete for ingress %v based on annotation %v", delIng.Name, ingressClassKey) return } glog.Infof("Delete notification received for Ingress %v/%v", delIng.Namespace, delIng.Name) lbc.ingQueue.enqueue(obj) }, UpdateFunc: func(old, cur interface{}) { curIng := cur.(*extensions.Ingress) if !isGCEIngress(curIng) { return } if !reflect.DeepEqual(old, cur) { glog.V(3).Infof("Ingress %v changed, syncing", curIng.Name) } lbc.ingQueue.enqueue(cur) }, } lbc.ingLister.Store, lbc.ingController = framework.NewInformer( &cache.ListWatch{ ListFunc: ingressListFunc(lbc.client, namespace), WatchFunc: ingressWatchFunc(lbc.client, namespace), }, &extensions.Ingress{}, resyncPeriod, pathHandlers) // Service watch handlers svcHandlers := framework.ResourceEventHandlerFuncs{ AddFunc: lbc.enqueueIngressForService, UpdateFunc: func(old, cur interface{}) { if !reflect.DeepEqual(old, cur) { lbc.enqueueIngressForService(cur) } }, // Ingress deletes matter, service deletes don't. } lbc.svcLister.Store, lbc.svcController = framework.NewInformer( cache.NewListWatchFromClient( lbc.client, "services", namespace, fields.Everything()), &api.Service{}, resyncPeriod, svcHandlers) lbc.podLister.Indexer, lbc.podController = framework.NewIndexerInformer( cache.NewListWatchFromClient(lbc.client, "pods", namespace, fields.Everything()), &api.Pod{}, resyncPeriod, framework.ResourceEventHandlerFuncs{}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) nodeHandlers := framework.ResourceEventHandlerFuncs{ AddFunc: lbc.nodeQueue.enqueue, DeleteFunc: lbc.nodeQueue.enqueue, // Nodes are updated every 10s and we don't care, so no update handler. } // Node watch handlers lbc.nodeLister.Store, lbc.nodeController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(opts api.ListOptions) (runtime.Object, error) { return lbc.client.Get(). Resource("nodes"). FieldsSelectorParam(fields.Everything()). Do(). Get() }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return lbc.client.Get(). Prefix("watch"). Resource("nodes"). FieldsSelectorParam(fields.Everything()). Param("resourceVersion", options.ResourceVersion).Watch() }, }, &api.Node{}, 0, nodeHandlers) lbc.tr = &GCETranslator{&lbc} lbc.tlsLoader = &apiServerTLSLoader{client: lbc.client} glog.V(3).Infof("Created new loadbalancer controller") return &lbc, nil }
// newReplicationManagerInternal configures a replication manager with the specified event recorder func newReplicationManagerInternal(eventRecorder record.EventRecorder, podInformer framework.SharedIndexInformer, kubeClient clientset.Interface, resyncPeriod controller.ResyncPeriodFunc, burstReplicas int, lookupCacheSize int) *ReplicationManager { if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("replication_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } rm := &ReplicationManager{ kubeClient: kubeClient, podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventRecorder, }, burstReplicas: burstReplicas, expectations: controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()), queue: workqueue.New(), } rm.rcStore.Indexer, rm.rcController = framework.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, framework.ResourceEventHandlerFuncs{ AddFunc: rm.enqueueController, UpdateFunc: func(old, cur interface{}) { oldRC := old.(*api.ReplicationController) curRC := cur.(*api.ReplicationController) // We should invalidate the whole lookup cache if a RC's selector has been updated. // // Imagine that you have two RCs: // * old RC1 // * new RC2 // You also have a pod that is attached to RC2 (because it doesn't match RC1 selector). // Now imagine that you are changing RC1 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 RC1 // // This makes the lookup cache less helpful, but selector update does not happen often, // so it's not a big problem if !reflect.DeepEqual(oldRC.Spec.Selector, curRC.Spec.Selector) { rm.lookupCache.InvalidateAll() } // You might imagine that we only really need to enqueue the // controller when Spec changes, but it is safer to sync any // time this function is triggered. That way a full informer // resync can requeue any controllers that don't yet have pods // but whose last attempts at creating a pod have failed (since // we don't block on creation of pods) instead of those // controllers stalling indefinitely. Enqueueing every time // does result in some spurious syncs (like when Status.Replica // is updated and the watch notification from it retriggers // this function), but in general extra resyncs shouldn't be // that bad as rcs that haven't met expectations yet won't // sync, and all the listing is done using local stores. if oldRC.Status.Replicas != curRC.Status.Replicas { glog.V(4).Infof("Observed updated replica count for rc: %v, %d->%d", curRC.Name, oldRC.Status.Replicas, curRC.Status.Replicas) } rm.enqueueController(cur) }, // 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(framework.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 }
func NewDisruptionController(podInformer framework.SharedIndexInformer, kubeClient *client.Client) *DisruptionController { dc := &DisruptionController{ kubeClient: kubeClient, podController: podInformer.GetController(), queue: workqueue.New(), 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(framework.ResourceEventHandlerFuncs{ AddFunc: dc.addPod, UpdateFunc: dc.updatePod, DeleteFunc: dc.deletePod, }) dc.pdbStore, dc.pdbController = framework.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, framework.ResourceEventHandlerFuncs{ AddFunc: dc.addDb, UpdateFunc: dc.updateDb, DeleteFunc: dc.removeDb, }, ) dc.pdbLister.Store = dc.pdbStore dc.rcIndexer, dc.rcController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return dc.kubeClient.ReplicationControllers(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return dc.kubeClient.ReplicationControllers(api.NamespaceAll).Watch(options) }, }, &api.ReplicationController{}, 30*time.Second, framework.ResourceEventHandlerFuncs{}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.rcLister.Indexer = dc.rcIndexer dc.rsStore, dc.rsController = framework.NewInformer( &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, framework.ResourceEventHandlerFuncs{}, ) dc.rsLister.Store = dc.rsStore dc.dIndexer, dc.dController = framework.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, framework.ResourceEventHandlerFuncs{}, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) dc.dLister.Indexer = dc.dIndexer return dc }
// NewNodeController returns a new node controller to sync instances from cloudprovider. // This method returns an error if it is unable to initialize the CIDR bitmap with // podCIDRs it has already allocated to nodes. Since we don't allow podCIDR changes // currently, this should be handled as a fatal error. func NewNodeController( cloud cloudprovider.Interface, kubeClient clientset.Interface, podEvictionTimeout time.Duration, deletionEvictionLimiter flowcontrol.RateLimiter, terminationEvictionLimiter flowcontrol.RateLimiter, nodeMonitorGracePeriod time.Duration, nodeStartupGracePeriod time.Duration, nodeMonitorPeriod time.Duration, clusterCIDR *net.IPNet, serviceCIDR *net.IPNet, nodeCIDRMaskSize int, allocateNodeCIDRs bool) (*NodeController, error) { eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "controllermanager"}) eventBroadcaster.StartLogging(glog.Infof) if kubeClient != nil { glog.V(0).Infof("Sending events to api server.") eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: kubeClient.Core().Events("")}) } else { glog.V(0).Infof("No api server defined - no events will be sent to API server.") } if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("node_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } if allocateNodeCIDRs { if clusterCIDR == nil { glog.Fatal("NodeController: Must specify clusterCIDR if allocateNodeCIDRs == true.") } mask := clusterCIDR.Mask if maskSize, _ := mask.Size(); maskSize > nodeCIDRMaskSize { glog.Fatal("NodeController: Invalid clusterCIDR, mask size of clusterCIDR must be less than nodeCIDRMaskSize.") } } evictorLock := sync.Mutex{} nc := &NodeController{ cloud: cloud, knownNodeSet: make(sets.String), kubeClient: kubeClient, recorder: recorder, podEvictionTimeout: podEvictionTimeout, maximumGracePeriod: 5 * time.Minute, evictorLock: &evictorLock, podEvictor: NewRateLimitedTimedQueue(deletionEvictionLimiter), terminationEvictor: NewRateLimitedTimedQueue(terminationEvictionLimiter), nodeStatusMap: make(map[string]nodeStatusData), nodeMonitorGracePeriod: nodeMonitorGracePeriod, nodeMonitorPeriod: nodeMonitorPeriod, nodeStartupGracePeriod: nodeStartupGracePeriod, lookupIP: net.LookupIP, now: unversioned.Now, clusterCIDR: clusterCIDR, serviceCIDR: serviceCIDR, allocateNodeCIDRs: allocateNodeCIDRs, forcefullyDeletePod: func(p *api.Pod) error { return forcefullyDeletePod(kubeClient, p) }, nodeExistsInCloudProvider: func(nodeName string) (bool, error) { return nodeExistsInCloudProvider(cloud, nodeName) }, } nc.podStore.Indexer, nc.podController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, controller.NoResyncPeriodFunc(), framework.ResourceEventHandlerFuncs{ AddFunc: nc.maybeDeleteTerminatingPod, UpdateFunc: func(_, obj interface{}) { nc.maybeDeleteTerminatingPod(obj) }, }, // We don't need to build a index for podStore here actually, but build one for consistency. // It will ensure that if people start making use of the podStore in more specific ways, // they'll get the benefits they expect. It will also reserve the name for future refactorings. cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) nodeEventHandlerFuncs := framework.ResourceEventHandlerFuncs{} if nc.allocateNodeCIDRs { nodeEventHandlerFuncs = framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { node := obj.(*api.Node) err := nc.cidrAllocator.AllocateOrOccupyCIDR(node) if err != nil { glog.Errorf("Error allocating CIDR: %v", err) } }, UpdateFunc: func(_, obj interface{}) { node := obj.(*api.Node) // If the PodCIDR is not empty we either: // - already processed a Node that already had a CIDR after NC restarted // (cidr is marked as used), // - already processed a Node successfully and allocated a CIDR for it // (cidr is marked as used), // - already processed a Node but we did saw a "timeout" response and // request eventually got through in this case we haven't released // the allocated CIDR (cidr is still marked as used). // There's a possible error here: // - NC sees a new Node and assigns a CIDR X to it, // - Update Node call fails with a timeout, // - Node is updated by some other component, NC sees an update and // assigns CIDR Y to the Node, // - Both CIDR X and CIDR Y are marked as used in the local cache, // even though Node sees only CIDR Y // The problem here is that in in-memory cache we see CIDR X as marked, // which prevents it from being assigned to any new node. The cluster // state is correct. // Restart of NC fixes the issue. if node.Spec.PodCIDR == "" { err := nc.cidrAllocator.AllocateOrOccupyCIDR(node) if err != nil { glog.Errorf("Error allocating CIDR: %v", err) } } }, DeleteFunc: func(obj interface{}) { node := obj.(*api.Node) err := nc.cidrAllocator.ReleaseCIDR(node) if err != nil { glog.Errorf("Error releasing CIDR: %v", err) } }, } } nc.nodeStore.Store, nc.nodeController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Core().Nodes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Core().Nodes().Watch(options) }, }, &api.Node{}, controller.NoResyncPeriodFunc(), nodeEventHandlerFuncs, ) nc.daemonSetStore.Store, nc.daemonSetController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).Watch(options) }, }, &extensions.DaemonSet{}, controller.NoResyncPeriodFunc(), framework.ResourceEventHandlerFuncs{}, ) if allocateNodeCIDRs { var nodeList *api.NodeList var err error // We must poll because apiserver might not be up. This error causes // controller manager to restart. if pollErr := wait.Poll(10*time.Second, apiserverStartupGracePeriod, func() (bool, error) { nodeList, err = kubeClient.Core().Nodes().List(api.ListOptions{ FieldSelector: fields.Everything(), LabelSelector: labels.Everything(), }) if err != nil { glog.Errorf("Failed to list all nodes: %v", err) return false, nil } return true, nil }); pollErr != nil { return nil, fmt.Errorf("Failed to list all nodes in %v, cannot proceed without updating CIDR map", apiserverStartupGracePeriod) } nc.cidrAllocator, err = NewCIDRRangeAllocator(kubeClient, clusterCIDR, serviceCIDR, nodeCIDRMaskSize, nodeList) if err != nil { return nil, err } } return nc, nil }
func (m *NetworkManager) start(args []string) { m.init(args) m.PodStore, m.PodInformer = framework.NewIndexerInformer( cache.NewListWatchFromClient( m.Client, string(api.ResourcePods), api.NamespaceAll, fields.Everything(), ), &api.Pod{}, m.config.ResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { m.Controller.AddPod(obj.(*api.Pod)) }, UpdateFunc: func(oldObj, newObj interface{}) { m.Controller.UpdatePod( oldObj.(*api.Pod), newObj.(*api.Pod)) }, DeleteFunc: func(obj interface{}) { if pod, ok := obj.(*api.Pod); ok { m.Controller.DeletePod(pod) } }, }, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) m.NamespaceStore, m.NamespaceInformer = framework.NewInformer( cache.NewListWatchFromClient( m.Client, "namespaces", api.NamespaceAll, fields.Everything(), ), &api.Namespace{}, m.config.ResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { m.Controller.AddNamespace( obj.(*api.Namespace)) }, UpdateFunc: func(oldObj, newObj interface{}) { m.Controller.UpdateNamespace( oldObj.(*api.Namespace), newObj.(*api.Namespace)) }, DeleteFunc: func(obj interface{}) { if namespace, ok := obj.(*api.Namespace); ok { m.Controller.DeleteNamespace(namespace) } }, }, ) m.RCStore, m.RCInformer = framework.NewInformer( cache.NewListWatchFromClient( m.Client, string(api.ResourceReplicationControllers), api.NamespaceAll, fields.Everything(), ), &api.ReplicationController{}, m.config.ResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { m.Controller.AddReplicationController( obj.(*api.ReplicationController)) }, UpdateFunc: func(oldObj, newObj interface{}) { m.Controller.UpdateReplicationController( oldObj.(*api.ReplicationController), newObj.(*api.ReplicationController)) }, DeleteFunc: func(obj interface{}) { if rc, ok := obj.(*api.ReplicationController); ok { m.Controller.DeleteReplicationController(rc) } }, }, ) m.ServiceStore, m.ServiceInformer = framework.NewInformer( cache.NewListWatchFromClient( m.Client, string(api.ResourceServices), api.NamespaceAll, fields.Everything(), ), &api.Service{}, m.config.ResyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { m.Controller.AddService( obj.(*api.Service)) }, UpdateFunc: func(oldObj, newObj interface{}) { m.Controller.UpdateService( oldObj.(*api.Service), newObj.(*api.Service)) }, DeleteFunc: func(obj interface{}) { if service, ok := obj.(*api.Service); ok { m.Controller.DeleteService(service) } }, }, ) m.Controller.SetPodStore(m.PodStore) m.Controller.SetNamespaceStore(m.NamespaceStore) m.Controller.SetReplicationControllerStore(m.RCStore) m.Controller.SetServiceStore(m.ServiceStore) }
// 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 }
// NewNodeController returns a new node controller to sync instances from cloudprovider. // This method returns an error if it is unable to initialize the CIDR bitmap with // podCIDRs it has already allocated to nodes. Since we don't allow podCIDR changes // currently, this should be handled as a fatal error. func NewNodeController( cloud cloudprovider.Interface, kubeClient clientset.Interface, podEvictionTimeout time.Duration, evictionLimiterQPS float32, nodeMonitorGracePeriod time.Duration, nodeStartupGracePeriod time.Duration, nodeMonitorPeriod time.Duration, clusterCIDR *net.IPNet, serviceCIDR *net.IPNet, nodeCIDRMaskSize int, allocateNodeCIDRs bool) (*NodeController, error) { eventBroadcaster := record.NewBroadcaster() recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "controllermanager"}) eventBroadcaster.StartLogging(glog.Infof) if kubeClient != nil { glog.V(0).Infof("Sending events to api server.") eventBroadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: kubeClient.Core().Events("")}) } else { glog.V(0).Infof("No api server defined - no events will be sent to API server.") } if kubeClient != nil && kubeClient.Core().GetRESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("node_controller", kubeClient.Core().GetRESTClient().GetRateLimiter()) } if allocateNodeCIDRs { if clusterCIDR == nil { glog.Fatal("NodeController: Must specify clusterCIDR if allocateNodeCIDRs == true.") } mask := clusterCIDR.Mask if maskSize, _ := mask.Size(); maskSize > nodeCIDRMaskSize { glog.Fatal("NodeController: Invalid clusterCIDR, mask size of clusterCIDR must be less than nodeCIDRMaskSize.") } } evictorLock := sync.Mutex{} nc := &NodeController{ cloud: cloud, knownNodeSet: make(map[string]*api.Node), kubeClient: kubeClient, recorder: recorder, podEvictionTimeout: podEvictionTimeout, maximumGracePeriod: 5 * time.Minute, evictorLock: &evictorLock, zonePodEvictor: make(map[string]*RateLimitedTimedQueue), zoneTerminationEvictor: make(map[string]*RateLimitedTimedQueue), nodeStatusMap: make(map[string]nodeStatusData), nodeMonitorGracePeriod: nodeMonitorGracePeriod, nodeMonitorPeriod: nodeMonitorPeriod, nodeStartupGracePeriod: nodeStartupGracePeriod, lookupIP: net.LookupIP, now: unversioned.Now, clusterCIDR: clusterCIDR, serviceCIDR: serviceCIDR, allocateNodeCIDRs: allocateNodeCIDRs, forcefullyDeletePod: func(p *api.Pod) error { return forcefullyDeletePod(kubeClient, p) }, nodeExistsInCloudProvider: func(nodeName string) (bool, error) { return nodeExistsInCloudProvider(cloud, nodeName) }, computeZoneStateFunc: ComputeZoneState, evictionLimiterQPS: evictionLimiterQPS, zoneStates: make(map[string]zoneState), } nc.podStore.Indexer, nc.podController = framework.NewIndexerInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Core().Pods(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Core().Pods(api.NamespaceAll).Watch(options) }, }, &api.Pod{}, controller.NoResyncPeriodFunc(), framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { nc.maybeDeleteTerminatingPod(obj, nc.nodeStore.Store, nc.forcefullyDeletePod) }, UpdateFunc: func(_, obj interface{}) { nc.maybeDeleteTerminatingPod(obj, nc.nodeStore.Store, nc.forcefullyDeletePod) }, }, // We don't need to build a index for podStore here actually, but build one for consistency. // It will ensure that if people start making use of the podStore in more specific ways, // they'll get the benefits they expect. It will also reserve the name for future refactorings. cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, ) nodeEventHandlerFuncs := framework.ResourceEventHandlerFuncs{} if nc.allocateNodeCIDRs { nodeEventHandlerFuncs = framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { node := obj.(*api.Node) err := nc.cidrAllocator.AllocateOrOccupyCIDR(node) if err != nil { glog.Errorf("Error allocating CIDR: %v", err) } }, DeleteFunc: func(obj interface{}) { node := obj.(*api.Node) err := nc.cidrAllocator.ReleaseCIDR(node) if err != nil { glog.Errorf("Error releasing CIDR: %v", err) } }, } } nc.nodeStore.Store, nc.nodeController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Core().Nodes().List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Core().Nodes().Watch(options) }, }, &api.Node{}, controller.NoResyncPeriodFunc(), nodeEventHandlerFuncs, ) nc.daemonSetStore.Store, nc.daemonSetController = framework.NewInformer( &cache.ListWatch{ ListFunc: func(options api.ListOptions) (runtime.Object, error) { return nc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).List(options) }, WatchFunc: func(options api.ListOptions) (watch.Interface, error) { return nc.kubeClient.Extensions().DaemonSets(api.NamespaceAll).Watch(options) }, }, &extensions.DaemonSet{}, controller.NoResyncPeriodFunc(), framework.ResourceEventHandlerFuncs{}, ) if allocateNodeCIDRs { var nodeList *api.NodeList var err error // We must poll because apiserver might not be up. This error causes // controller manager to restart. if pollErr := wait.Poll(10*time.Second, apiserverStartupGracePeriod, func() (bool, error) { nodeList, err = kubeClient.Core().Nodes().List(api.ListOptions{ FieldSelector: fields.Everything(), LabelSelector: labels.Everything(), }) if err != nil { glog.Errorf("Failed to list all nodes: %v", err) return false, nil } return true, nil }); pollErr != nil { return nil, fmt.Errorf("Failed to list all nodes in %v, cannot proceed without updating CIDR map", apiserverStartupGracePeriod) } nc.cidrAllocator, err = NewCIDRRangeAllocator(kubeClient, clusterCIDR, serviceCIDR, nodeCIDRMaskSize, nodeList) if err != nil { return nil, err } } return nc, nil }