简介
之前介绍过sigs.k8s.io controller-runtime系列之九 config分析sigs.k8s.io controller-runtime-config 。
本文主要介绍pkg/source和pkg/event和pkg/handler的源码分析。主要为controllerManager中的属性提供默认配置
目录结构
- 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...) }
- 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) }
- 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 }
- 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) } }
- EventHandler结构体 EventHandler可以调和响应事件的reconcile.Requests(如Pod Create)。
- 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(), }}) }
- 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 }
- 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) }