func NewResourceQuotaController(options *ResourceQuotaControllerOptions) (*ResourceQuotaController, error) { // build the resource quota controller rq := &ResourceQuotaController{ // 用于和api-server交互 rqClient: options.QuotaClient, rqLister: options.ResourceQuotaInformer.Lister(), // sharedIndexInformer informerSyncedFuncs: []cache.InformerSynced{options.ResourceQuotaInformer.Informer().HasSynced}, // 将从apiserver那边同步过来的数据放入此队列中,进行异步处理 queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resourcequota_primary”), // 同样的事一个队列,也会处理此处的队列。 missingUsageQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resourcequota_priority" ), resyncPeriod: options.ResyncPeriod, registry: options.Registry, // 7个evalutor } // set the synchronization handler rq.syncHandler = rq.syncResourceQuotaFromKey // 为resourcequota增加事件的回调函数。当watch到apiserver中resource change的时候会触发这里设置的回调函数。 // 该方法同样比较核心,和Inform框架结合,进一步封装事件回调函数为processorlistner,并最终叫sharedprocessor进行统一管理。 // 此处不一一展开。感兴趣的话可参考shraed_informer.go options.ResourceQuotaInformer.Informer().AddEventHandlerWithResyncPeriod( 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, }, rq.resyncPeriod(), ) if options.DiscoveryFunc != nil { // 1. qm主要用于监听其他资源的变化情况,然后回调相应的函数。这里的回调函数是资源配额rq.replenishQuota。 // 2. 这里主要监听pod和service的资源变化,进行资源重计算。 qm := &QuotaMonitor{ informersStarted: options.InformersStarted, // chan 类型 informerFactory: options.InformerFactory, // sharedInformerFactory ignoredResources: options.IgnoredResourcesFunc(), // 忽略一些不需要monitor的对象。 resourceChanges: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "resource_quota_controller_resource_changes" ), resyncPeriod: options.ReplenishmentResyncPeriod, replenishmentFunc: rq.replenishQuota, registry: rq.registry, } rq.quotaMonitor = qm // do initial quota monitor setup // GetQuotableResources: 向APi server 同步获取可以计算配额的资源对象,判断的标准是支持verbs类别为:"create", "list", "watch", "delete" resources, err := GetQuotableResources(options.DiscoveryFunc) if err != nil { return nil, err } // 1. 为每个resource 分配一个添加监听事件的回调函数 // 2. 只会监听pod 和service的upate事件 // 3. 监听所有资源的delete事件。 if err = qm.SyncMonitors(resources); err != nil { utilruntime.HandleError(fmt.Errorf( "initial monitor sync has error: %v" , err)) } // only start quota once all informers synced rq.informerSyncedFuncs = append(rq.informerSyncedFuncs, qm.IsSynced) } return rq, nil } |