sigs.k8s.io controller-runtime系列之十 sourceeventhandler分析

简介

之前介绍过sigs.k8s.io controller-runtime系列之九 config分析sigs.k8s.io controller-runtime-config
本文主要介绍pkg/source和pkg/event和pkg/handler的源码分析。主要为controllerManager中的属性提供默认配置

目录结构

  1. source/source.go
    • Source结构体
    // 源是事件的源(eh.g。对Kubernetes对象、Webhook回调等创建、更新、删除操作)
    // 它应该由event.EventHandlers处理,以便将reconcile.Requests排队。
    //
    // 用户可以构建自己的源代码实现。如果他们的实现inject接口,当调用Watch时,控制器将注入依赖项。
    type Source interface {
    	// Start是内部的,应该仅由控制器调用,以便向informer注册EventHandler以将reconcile.Requests排队。 
    	Start(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
    }
    
    • SyncingSource方法
    // SyncingSource是在使用之前需要同步源。在启动worker之前,控制器将调用其WaitForSync。 
    type SyncingSource interface {
    	Source
    	WaitForSync(ctx context.Context) error
    }
    
    • NewKindWithCache方法
    // 创建一个不带InjectCache的源,这样就可以确保给定的缓存被使用而不被覆盖。它可以通过传递另一个集群的缓存来监视另一个集群中的对象
    func NewKindWithCache(object client.Object, cache cache.Cache) SyncingSource {
    	return &kindWithCache{kind: Kind{Type: object, cache: cache}}
    }
    
    // 用于提供一个集群内watch的事件源
    type Kind struct {
    	// 被监视对象的type
    	Type client.Object
    
    	// 用来监视api
    	cache cache.Cache
    
    	// 如果在启动过程中遇到错误,started可能包含错误。如果它关闭并且没有包含错误,启动和同步完成。 
    	started     chan error
    	startCancel func()
    }
    
    type kindWithCache struct {
    	kind Kind
    }
    
    // 实现Source接口
    func (ks *kindWithCache) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
    	prct ...predicate.Predicate) error {
    	return ks.kind.Start(ctx, handler, queue, prct...)
    }
    // 实现SyncingSource接口
    func (ks *kindWithCache) WaitForSync(ctx context.Context) error {
    	return ks.kind.WaitForSync(ctx)
    }
    
    // Start是内部的,应该只由控制器调用,以便向Informer注册EventHandler,将协调Requests排队。 
    func (ks *Kind) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
    	prct ...predicate.Predicate) error {
    
    	// Type 必须由用户指定
    	if ks.Type == nil {
    		return fmt.Errorf("must specify Kind.Type")
    	}
    
    	// cache在kind start前,必须被指定
    	if ks.cache == nil {
    		return fmt.Errorf("must call CacheInto on Kind before calling Start")
    	}
    
    	// cache.GetInformer 将阻塞,直到context取消 (cache已经开启并且cache不能同步对应的informer(最常见的原因是RBAC问题))
    	ctx, ks.startCancel = context.WithCancel(ctx)
    	ks.started = make(chan error)
    	go func() {
    		// 从cache中得到informer并且为该imformer添加一个填充event队列的EventHandler
    		i, err := ks.cache.GetInformer(ctx, ks.Type)
    		if err != nil {
    			kindMatchErr := &meta.NoKindMatchError{}
    			if errors.As(err, &kindMatchErr) {
    				log.Error(err, "if kind is a CRD, it should be installed before calling Start",
    					"kind", kindMatchErr.GroupKind)
    			}
    			ks.started <- err
    			return
    		}
    		i.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
            // 等待cache同步完成
    		if !ks.cache.WaitForCacheSync(ctx) {
    			// Would be great to return something more informative here
    			ks.started <- errors.New("cache did not sync")
    		}
    		close(ks.started)
    	}()
    
    	return nil
    }
    
    // 允许controllers开始工作(reconcile)直到cache同步完成
    func (ks *Kind) WaitForSync(ctx context.Context) error {
    	select {
    	case err := <-ks.started:
    		return err
    	case <-ctx.Done():
    		ks.startCancel()
    		return errors.New("timed out waiting for cache to be synced")
    	}
    }
    
    • Channel结构体 为cluster外部提供events source(例如;GitHub Webhook callback),
      通道要求用户连接外部源(http处理程序)将GenericeEvents写入基础通道。
    type Channel struct {
    	// once确保事件分发goroutine只执行一次 
    	once sync.Once
    
    	// Source是获取GenericEvents的源通道 
    	Source <-chan event.GenericEvent
    
    	// 结束正在进行的goroutine,并关闭channel
    	stop <-chan struct{}
    
    	// 添加的事件处理程序的目标通道
    	dest []chan event.GenericEvent
    
    	// 指定目标通道的缓存大小,默认是 1024.
    	DestBufferSize int
    
    	// 在added/removed操作中确保dest是安全的
    	destLock sync.Mutex
    }
    
    // 仅仅由controller调用,并且实现了Source接口
    func (cs *Channel) Start(
    	ctx context.Context,
    	handler handler.EventHandler,
    	queue workqueue.RateLimitingInterface,
    	prct ...predicate.Predicate) error {
    	// 验证cs中的Source是否为空,应该由用户指定
    	if cs.Source == nil {
    		return fmt.Errorf("must specify Channel.Source")
    	}
    
    	// 验证cs中stop是否为空
    	if cs.stop == nil {
    		return fmt.Errorf("must call InjectStop on Channel before calling Start")
    	}
    
    	// 如果cs中DestBufferSize没有设置,则设置默认
    	if cs.DestBufferSize == 0 {
    		cs.DestBufferSize = defaultBufferSize
    	}
    
        // 构造目标源chan
    	dst := make(chan event.GenericEvent, cs.DestBufferSize)
    
    	cs.destLock.Lock()
    	cs.dest = append(cs.dest, dst)
    	cs.destLock.Unlock()
    
    	cs.once.Do(func() {
            // 循环同步
    		go cs.syncLoop(ctx)
    	})
    
    	go func() {
    		for evt := range dst {
    			shouldHandle := true
                // 使用prct中的predicate过滤是否是eventHanler处理的event
    			for _, p := range prct {
    				if !p.Generic(evt) {
    					shouldHandle = false
    					break
    				}
    			}
                // 如果是,则添加到handler中(其实是添加到queue中)
    			if shouldHandle {
    				handler.Generic(evt, queue)
    			}
    		}
    	}()
    
    	return nil
    }
    
    // 循环同步
    func (cs *Channel) syncLoop(ctx context.Context) {
    	for {
    		select {
    		case <-ctx.Done():
    			// 关闭cs的dest
    			cs.doStop()
    			return
    		case evt, stillOpen := <-cs.Source:
    			if !stillOpen {
    				// cs中source关闭,不需要做任何操作,关闭dest
    				cs.doStop()
    				return
    			}
                // 为cs中dest的每一个chan加入evt
    			cs.distribute(evt)
    		}
    	}
    }
    
    // 关闭cs中的dest
    func (cs *Channel) doStop() {
    	cs.destLock.Lock()
    	defer cs.destLock.Unlock()
    
    	for _, dst := range cs.dest {
    		close(dst)
    	}
    }
    
    // 为cs中dest的每一个chan加入evt 
    func (cs *Channel) distribute(evt event.GenericEvent) {
    	cs.destLock.Lock()
    	defer cs.destLock.Unlock()
    
    	for _, dst := range cs.dest {
    		// 我们不能再开启goroutine执行,否则我们会遇到将event写入已经关闭通道的竞争条件。
            // 为了避免阻塞,dest通道应该设置合适的缓冲区大小。如果我们仍然看到它被lock,那么
            // 控制器被认为处于异常状态。 
    		dst <- evt
    	}
    }
    
    • Informer结构体
    // Informer用于提供监视(例如Pod Create)在集群内部发起的事件源,区别于Kind结构体,是否需要自己获取informer
    type Informer struct {
    	// controller-runtime Informer(cache包中参考cache分析)
    	Informer cache.Informer
    }
    
    // Start是内部的,应该只由控制器调用,以便向Informer注册EventHandler,使reconcile.Requests排队。 
    func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
    	prct ...predicate.Predicate) error {
    
    	// 必须由用户指定
    	if is.Informer == nil {
    		return fmt.Errorf("must specify Informer.Informer")
    	}
        // 添加EventHandler到informer
    	is.Informer.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
    	return nil
    }
    
    // Func 是Informer的函数类型,和Informer类似
    type Func func(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
    
    // 实现Source接口
    func (f Func) Start(ctx context.Context, evt handler.EventHandler, queue workqueue.RateLimitingInterface,
    	pr ...predicate.Predicate) error {
    	return f(ctx, evt, queue, pr...)
    }
    
  2. source/internal/eventsource.go
    • EventHandler结构体 适配handler.EventHandler接口到k8s的client-go的cache.ResourceEventHandler接口
    type EventHandler struct {
        // handler.EventHandler接口类型的结构体
    	EventHandler handler.EventHandler
        // 存放需要该handler处理的reconcile request
    	Queue        workqueue.RateLimitingInterface
        // 过滤resource是否保存到queue
    	Predicates   []predicate.Predicate
    }
    
    // 创建 CreateEvent 对象并且执行EventHandler的Create方法
    func (e EventHandler) OnAdd(obj interface{}) {
    	c := event.CreateEvent{}
    
    	// 判断obj是否是client.Object
    	if o, ok := obj.(client.Object); ok {
    		c.Object = o
    	} else {
    		log.Error(nil, "OnAdd missing Object",
    			"object", obj, "type", fmt.Sprintf("%T", obj))
    		return
    	}
    
        // 循环e.Predicates来过滤是否可以创建Event
    	for _, p := range e.Predicates {
    		if !p.Create(c) {
    			return
    		}
    	}
    
    	// 执行EventHandler的Create方法
    	e.EventHandler.Create(c, e.Queue)
    }
    
    // 创建 更新UdateEvent 对象并且执行EventHandler的Update方法
    func (e EventHandler) OnUpdate(oldObj, newObj interface{}) {
    	u := event.UpdateEvent{}
    
        // 判断oldObj是否是client.Object
    	if o, ok := oldObj.(client.Object); ok {
    		u.ObjectOld = o
    	} else {
    		log.Error(nil, "OnUpdate missing ObjectOld",
    			"object", oldObj, "type", fmt.Sprintf("%T", oldObj))
    		return
    	}
    
    	// 判断newObj是否是client.Object
    	if o, ok := newObj.(client.Object); ok {
    		u.ObjectNew = o
    	} else {
    		log.Error(nil, "OnUpdate missing ObjectNew",
    			"object", newObj, "type", fmt.Sprintf("%T", newObj))
    		return
    	}
    
        // 循环e.Predicates来过滤是否可以创建Event
    	for _, p := range e.Predicates {
    		if !p.Update(u) {
    			return
    		}
    	}
    
    	// 执行EventHandler的Update方法
    	e.EventHandler.Update(u, e.Queue)
    }
    
    // 创建 删除DeleteEvent 对象并且执行EventHandler的Delete方法
    func (e EventHandler) OnDelete(obj interface{}) {
    	d := event.DeleteEvent{}
    
    	// 通过取出obj对象来处理tombstone事件(这是一个特别的事件,DeletedFinalStateUnknown被放置在DeltaFIFO中,当对象已删除,但断开连接时错过了监视删除事件
        // apiserver。在这种情况下,我们不知道对象的最终“resting”状态,所以有可能包含的“Obj”是旧的。)。
        // 删除事件将对象包装在DeleteFinalStateUnknown结构体,因此需要取出该对象。
       
        // 如果我们没有错过一些事情(监视删除事件apiserver断开),这就不应该发生,而我们已经得出结论,我们没有错过(监视删除事件apiserver断开)
        // 并根据这种观点做出决定。
    	var ok bool
    	if _, ok = obj.(client.Object); !ok {
    		// If the object doesn't have Metadata, assume it is a tombstone object of type DeletedFinalStateUnknown
    		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
    		if !ok {
    			log.Error(nil, "Error decoding objects.  Expected cache.DeletedFinalStateUnknown",
    				"type", fmt.Sprintf("%T", obj),
    				"object", obj)
    			return
    		}
    
    		obj = tombstone.Obj
    	}
    
    	if o, ok := obj.(client.Object); ok {
    		d.Object = o
    	} else {
    		log.Error(nil, "OnDelete missing Object",
    			"object", obj, "type", fmt.Sprintf("%T", obj))
    		return
    	}
    
        // 循环e.Predicates来过滤是否可以创建Event
    	for _, p := range e.Predicates {
    		if !p.Delete(d) {
    			return
    		}
    	}
    
    	// 执行EventHanler的Delete方法
    	e.EventHandler.Delete(d, e.Queue)
    }
    
  3. event/event.go
    • 各种类型Event结构体
    // Kubernetes object被创建产生的event。由source.Source生成并由handler.EventHandler转化为reconcile.Request
    type CreateEvent struct {
    	// 产生event的obj
    	Object client.Object
    }
    
    // Kubernetes object被更新产生的event.  由source.Source生成并由handler.EventHandler转化为reconcile.Request
    type UpdateEvent struct {
    	// 事件关联之前的obj
    	ObjectOld client.Object
    
    	// 事件关联之后的obj
    	ObjectNew client.Object
    }
    
    // Kubernetes object被删除产生的event.  由source.Source生成并由handler.EventHandler转化为reconcile.Request
    type DeleteEvent struct {
    	// 删除的obj
    	Object client.Object
    
    	// 如果删除事件丢失,但我们将对象标识为已删除,则该值为true
    	DeleteStateUnknown bool
    }
    
    // 操作类型未知的事件(例如,轮询或源自集群外部的事件).
    // GenericeEvent应由source.source生成,并由handler.EventHandler转换为reconcile.Request。 
    type GenericEvent struct {
    	// 事件关联的obj
    	Object client.Object
    }
    
  4. handler/eventhandler.go
    • EventHandler结构体 EventHandler可以调和响应事件的reconcile.Requests(如Pod Create)。
      eventandlers为一个对象映射一个事件来触发相同对象或不同对象的Reconciles -例如,如果有一个Foo类型的对象的事件(使用source.KindSource),然后调和一个或多个对象类型的Bar。
    type EventHandler interface {
    	// 响应create event. 例如 Pod Creation.
    	Create(event.CreateEvent, workqueue.RateLimitingInterface)
    
    	// 响应update event. 例如 Pod Updated.
    	Update(event.UpdateEvent, workqueue.RateLimitingInterface)
    
    	// 响应delete event. 例如 Pod Deleted.
    	Delete(event.DeleteEvent, workqueue.RateLimitingInterface)
    
    	// 响应未知类型的事件或合成事件时调用的,这些事件被触发为cron或外部触发请求,例如:reconcile Autoscaling,或Webhook。
    	Generic(event.GenericEvent, workqueue.RateLimitingInterface)
    }
    
    • Funcs结构体
    // 实现了 EventHandler接口的结构体.
    type Funcs struct {
    	// 在响应add事件时调用。默认为空操作。RateLimitingInterface用于将协调请求排队。
    	CreateFunc func(event.CreateEvent, workqueue.RateLimitingInterface)
    
    	// 在响应update事件时调用。默认为空操作。RateLimitingInterface用于将协调请求排队。
    	UpdateFunc func(event.UpdateEvent, workqueue.RateLimitingInterface)
    
    	// 在响应delete事件时调用。默认为空操作。RateLimitingInterface用于将协调请求排队。
    	DeleteFunc func(event.DeleteEvent, workqueue.RateLimitingInterface)
    
    	// 在响应generic事件时调用。默认为空操作。RateLimitingInterface用于将协调请求排队。
    	GenericFunc func(event.GenericEvent, workqueue.RateLimitingInterface)
    }
    // 实现了 EventHandler接口的Create方法
    func (h Funcs) Create(e event.CreateEvent, q workqueue.RateLimitingInterface) {
    	if h.CreateFunc != nil {
    		h.CreateFunc(e, q)
    	}
    }
    
    // 实现了 EventHandler接口的Delete方法
    func (h Funcs) Delete(e event.DeleteEvent, q workqueue.RateLimitingInterface) {
    	if h.DeleteFunc != nil {
    		h.DeleteFunc(e, q)
    	}
    }
    
    // 实现了 EventHandler接口的Update方法
    func (h Funcs) Update(e event.UpdateEvent, q workqueue.RateLimitingInterface) {
    	if h.UpdateFunc != nil {
    		h.UpdateFunc(e, q)
    	}
    }
    
    // 实现了 EventHandler接口的Generic方法
    func (h Funcs) Generic(e event.GenericEvent, q workqueue.RateLimitingInterface) {
    	if h.GenericFunc != nil {
    		h.GenericFunc(e, q)
    	}
    }
    
  5. handler/enqueue.go
    • EnqueueRequestForObject结构体及其方法
    // 入队source的event,该source包含了name和namespace的object
    // 几乎被所有具有关联资源(例如CRDs)的控制器使用,以协调关联资源。
    type EnqueueRequestForObject struct{}
    
    // 实现EventHandler接口的Create方法
    func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
    	if evt.Object == nil {
    		enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
    		return
    	}
    	q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
    		Name:      evt.Object.GetName(),
    		Namespace: evt.Object.GetNamespace(),
    	}})
    }
    
    // 实现EventHandler接口的Update方法
    func (e *EnqueueRequestForObject) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
    	switch {
    	case evt.ObjectNew != nil:
    		q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
    			Name:      evt.ObjectNew.GetName(),
    			Namespace: evt.ObjectNew.GetNamespace(),
    		}})
    	case evt.ObjectOld != nil:
    		q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
    			Name:      evt.ObjectOld.GetName(),
    			Namespace: evt.ObjectOld.GetNamespace(),
    		}})
    	default:
    		enqueueLog.Error(nil, "UpdateEvent received with no metadata", "event", evt)
    	}
    }
    
    // 实现EventHandler接口的Delete方法
    func (e *EnqueueRequestForObject) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
    	if evt.Object == nil {
    		enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt)
    		return
    	}
    	q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
    		Name:      evt.Object.GetName(),
    		Namespace: evt.Object.GetNamespace(),
    	}})
    }
    
    // 实现EventHandler接口的Generic方法
    func (e *EnqueueRequestForObject) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
    	if evt.Object == nil {
    		enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt)
    		return
    	}
    	q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
    		Name:      evt.Object.GetName(),
    		Namespace: evt.Object.GetNamespace(),
    	}})
    }  
    
  6. handler/enqueue_owner.go
    • EnqueueRequestForOwner结构体及其方法
    // EnqueueRequestForOwner将对象所有者的请求排队。例如,创建的对象的对象是事件的来源。
    // 如果一个replicasset创建了Pods,用户可以使用以下方法协调replicasset来响应Pod Events:
    // 1. 使用source.Kind 的Type属性为Pod
    // 2. 使用handler.EnqueueRequestForOwner EventHandler,其 OwnerType 为 ReplicaSet,IsController 设置为 true。
    type EnqueueRequestForOwner struct {
    	// OwnerType 是要在 OwnerReferences 中查找的 Owner 对象的类型。仅比较 Group 和 Kind
    	OwnerType runtime.Object
    
    	// 如果IsController: true,只会查看OwnerReferences中第一个 OwnerReference.Controller为true的OwnerReference。
        // 我理解的IsController是要找出OwnerType的OwnerReferences中,第一个Controller为true(即是由OwnerType直接关联的,
        // 比如ReplicaSet直接创建的Pod)
    	IsController bool
    
    	// groupKind 是来自 OwnerType 的缓存 group和kind
    	groupKind schema.GroupKind
    
    	// 映射GroupVersionKinds 到 Resources
    	mapper meta.RESTMapper
    }
    
    // 实现EventHandler接口的Create方法.
    func (e *EnqueueRequestForOwner) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
        // 获取CreateEvent的Object包含的OwnersReferences并且其中OwnersReference的Group和Kind和e中的OwnerType相同,然后形成ReconcileRequest返回
    	e.getOwnerReconcileRequest(evt.Object, reqs)
        // 遍历ReconcileRequest数组,添加到队列(每一个controller会有一个全局的队列,存放reconcile request)中
    	for req := range reqs {
    		q.Add(req)
    	}
    }
    
    // 实现EventHandler接口的Update方法.
    func (e *EnqueueRequestForOwner) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
        // 获取UpdateEvent的ObjectOld包含的OwnersReferences并且其中OwnersReference的Group和Kind和e中的OwnerType相同,然后形成ReconcileRequest返回
    	e.getOwnerReconcileRequest(evt.ObjectOld, reqs)
        // 获取UpdateEvent的ObjectNew包含的OwnersReferences并且其中OwnersReference的Group和Kind和e中的OwnerType相同,然后形成ReconcileRequest返回
    	e.getOwnerReconcileRequest(evt.ObjectNew, reqs)
        // 遍历ReconcileRequest数组,添加到队列(每一个controller会有一个全局的队列,存放reconcile request)中
    	for req := range reqs {
    		q.Add(req)
    	}
    }
    
    // 实现EventHandler接口的Delete方法.
    func (e *EnqueueRequestForOwner) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
        // 获取DeleteEvent的Object包含的OwnersReferences并且其中OwnersReference的Group和Kind和e中的OwnerType相同,然后形成ReconcileRequest返回
    	e.getOwnerReconcileRequest(evt.Object, reqs)
        // 遍历ReconcileRequest数组,添加到队列(每一个controller会有一个全局的队列,存放reconcile request)中
    	for req := range reqs {
    		q.Add(req)
    	}
    }
    
    // 实现EventHandler接口的Generic方法.
    func (e *EnqueueRequestForOwner) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
        // 获取GenericEvent的Object包含的OwnersReferences并且其中OwnersReference的Group和Kind和e中的OwnerType相同,然后形成ReconcileRequest返回
    	e.getOwnerReconcileRequest(evt.Object, reqs)
        // 遍历ReconcileRequest数组,添加到队列(每一个controller会有一个全局的队列,存放reconcile request)中
    	for req := range reqs {
    		q.Add(req)
    	}
    }
    
    // parseOwnerTypeGroupKind 将 OwnerType 解析为 Group 和 Kind 并缓存结果。如果无法使用参数scheme解析 OwnerType,则返回 false。
    func (e *EnqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
    	// 获取OwnerType的所有GVK
    	kinds, _, err := scheme.ObjectKinds(e.OwnerType)
    	if err != nil {
    		log.Error(err, "Could not get ObjectKinds for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType))
    		return err
    	}
    	// 预计只有 1 种。如果有不止一种,这可能是一个边缘情况,例如 ListOptions。
    	if len(kinds) != 1 {
    		err := fmt.Errorf("expected exactly 1 kind for OwnerType %T, but found %s kinds", e.OwnerType, kinds)
    		log.Error(nil, "expected exactly 1 kind for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType), "kinds", kinds)
    		return err
    	}
    	// 缓存 OwnerType 的group和kind
    	e.groupKind = schema.GroupKind{Group: kinds[0].Group, Kind: kinds[0].Kind}
    	return nil
    }
    
    // getOwnerReconcileRequest 查看object的所有OwnerReference并构建 reconcile.Request 的map以协调匹配 e.OwnerType 的对象的OwnerReference。
    func (e *EnqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) {
    	// getOwnersReferences 返回 EnqueueRequestForOwner 指定的对象的 OwnerReferences
        // - 如果 IsController 为 true:仅获取 object.OwnerReference中Controller为true的(如果找到)
        // - 如果 IsController 为 false:获取所有 object.OwnerReferences.
    	for _, ref := range e.getOwnersReferences(object) {
    		// 从 OwnerReference 中解析出 Group 以将其与从请求的 OwnerType 中解析出的内容进行比较
            // 获取OwnersReference的GK
    		refGV, err := schema.ParseGroupVersion(ref.APIVersion)
    		if err != nil {
    			log.Error(err, "Could not parse OwnerReference APIVersion",
    				"api version", ref.APIVersion)
    			return
    		}
    
    		// 将 OwnerReference Group 和 Kind 与用户指定的 OwnerType Group 和 Kind 进行比较。
    		// 如果两者匹配,则为OwnerReference 引用的对象创建一个请求。在事件中使用 OwnerReference 中的 Name 和 对象中的 Namespace。
    		if ref.Kind == e.groupKind.Kind && refGV.Group == e.groupKind.Group {
    			// 为OwnerReference 引用的对象创建一个请求,其中NamespacedName的Name为OwnersReference的Name
    			request := reconcile.Request{NamespacedName: types.NamespacedName{
    				Name: ref.Name,
    			}}
    
    			// 如果所有者没有命名空间,那么我们应该将命名空间设置为空
    			mapping, err := e.mapper.RESTMapping(e.groupKind, refGV.Version)
    			if err != nil {
    				log.Error(err, "Could not retrieve rest mapping", "kind", e.groupKind)
    				return
    			}
    			if mapping.Scope.Name() != meta.RESTScopeNameRoot {
    				request.Namespace = object.GetNamespace()
    			}
    
    			result[request] = empty{}
    		}
    	}
    }
    
    // getOwnersReferences 返回 EnqueueRequestForOwner 指定的对象的 OwnerReferences
    // - 如果 IsController 为 true:仅获取 object.OwnerReference中Controller为true的(如果找到)
    // - 如果 IsController 为 false:获取所有 object.OwnerReferences.
    func (e *EnqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference {
    	if object == nil {
    		return nil
    	}
    
    	// 如果IsController为false,则返回全部OwnerReferences
    	if !e.IsController {
    		return object.GetOwnerReferences()
    	}
    	// 过滤找到OwnerReferences中第一个Controller为true的
    	if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
    		return []metav1.OwnerReference{*ownerRef}
    	}
    	// 如果没找到  返回nil
    	return nil
    }
    
  7. handler/enqueue_mapped.go
    • EnqueueRequestsFromMapFunc函数及enqueueRequestsFromMapFunc结构体和方法
    // MapFunc 是通用函数来生成reconcile.Request。
    type MapFunc func(client.Object) []reconcile.Request
    
    // EnqueueRequestsFromMapFunc 通过运行一个转换函数来生成reconcile.Request数组,该函数在每个事件上输出一个reconcile.Request 集合。 
    // reconcile.Request集合可以用于任意一组由某些用户指定的源事件转换定义的对象。 (例如,为一组对象触发 Reconciler以响应由添加或删除节点引起的集群大小调整事件)
    //
    // EnqueueRequestsFromMapFunc 经常用于从一个对象关联到一个或多个其他不同类型的对象。
    func EnqueueRequestsFromMapFunc(fn MapFunc) EventHandler {
    	return &enqueueRequestsFromMapFunc{
    		toRequests: fn,
    	}
    }
    // enqueueRequestsFromMapFunc结构体 
    type enqueueRequestsFromMapFunc struct {
    	// 将参数转换为reconcile request切片
    	toRequests MapFunc
    }    
    
    // 调用e.toRequests获取对象object的reconcile.Request数组,遍历数组入队q,并追加到reqs
    func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) {
    	for _, req := range e.toRequests(object) {
    		_, ok := reqs[req]
    		if !ok {
    			q.Add(req)
    			reqs[req] = empty{}
    		}
    	}
    }
    
    // 实现EventHandler的Create方法.
    func (e *enqueueRequestsFromMapFunc) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
    	e.mapAndEnqueue(q, evt.Object, reqs)
    }
    
    // 实现EventHandler的Update方法.
    func (e *enqueueRequestsFromMapFunc) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
    	e.mapAndEnqueue(q, evt.ObjectOld, reqs)
    	e.mapAndEnqueue(q, evt.ObjectNew, reqs)
    }
    
    // 实现EventHandler的Delete方法.
    func (e *enqueueRequestsFromMapFunc) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
    	e.mapAndEnqueue(q, evt.Object, reqs)
    }
    
    // 实现EventHandler的Generic方法.
    func (e *enqueueRequestsFromMapFunc) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
    	reqs := map[reconcile.Request]empty{}
    	e.mapAndEnqueue(q, evt.Object, reqs)
    } 
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值