@TOC
metadata包
用于获取gvr对应的metadata(gvr的TypeMeta和ObjectMeta)的informer/lister/client
metadatalister包
- interface.go 定义了获取(从索引器(缓存)中get/list)obj的接口
- 接口
// Lister 获取资源和获取NamespaceLister。 type Lister interface { // List 列出索引器(缓存)中的所有资源的MetaData。 List(selector labels.Selector) (ret []*metav1.PartialObjectMetadata, err error) // Get 从索引器(缓存)中检索具有给定名称的资源的MetaData Get(name string) (*metav1.PartialObjectMetadata, error) // Namespace 返回一个对象,该对象可以列出和获取给定命名空间中的资源。 Namespace(namespace string) NamespaceLister } // NamespaceLister 获取命名空间下的资源。类似于controller-runtime分析client包的Reader接口 type NamespaceLister interface { // List 列出索引器(缓存)中给定命名空间的所有资源的Metadata。 List(selector labels.Selector) (ret []*metav1.PartialObjectMetadata, err error) // Get 从索引器(缓存)中检索给定命名空间和名称的资源的Metadata。 Get(name string) (*metav1.PartialObjectMetadata, error) }
- 接口
- lister.go
- 结构体
// metadataLister 实现了 Lister 接口。 type metadataLister struct { // 索引器(缓存) indexer cache.Indexer // 索引器对应的资源gvr,该索引器只存储该gvr对应的资源的Metadata gvr schema.GroupVersionResource } // List 列出索引器中的所有资源的Metadata。 func (l *metadataLister) List(selector labels.Selector) (ret []*metav1.PartialObjectMetadata, err error) { // 该方法到对应包在做具体分析,用来获取符合selector对应添加的item err = cache.ListAll(l.indexer, selector, func(m interface{}) { // 符合添加的item会追加到ret ret = append(ret, m.(*metav1.PartialObjectMetadata)) }) return ret, err } // Get 从索引器中检索具有给定名称的资源 func (l *dynamicLister) Get(name string) (*metav1.PartialObjectMetadata, error) { // 没有使用索引,这里为什么没有判断是否是l中对应的gvr? 因为在add到indexer时已经做了区分,不同的gvr在不同的indexer中 obj, exists, err := l.indexer.GetByKey(name) if err != nil { return nil, err } if !exists { return nil, errors.NewNotFound(l.gvr.GroupResource(), name) } return obj.(*metav1.PartialObjectMetadata), nil } // Namespace 返回一个对象,该对象可以从给定的命名空间中列出和获取资源Metadata. func (l *dynamicLister) Namespace(namespace string) NamespaceLister { return &metadataNamespaceLister{indexer: l.indexer, namespace: namespace, gvr: l.gvr} } // metadataNamespaceLister 实现了 NamespaceLister 接口。相比metadataLister多了namespace属性,用来限定namespace type metadataNamespaceLister struct { // 索引器(缓存) indexer cache.Indexer // 命名空间 namespace string // 索引器对应的资源gvr,该索引器只存储该gvr对应的资源的Metadata gvr schema.GroupVersionResource } // List 列出索引器中给定命名空间的所有资源Metadata。 func (l *dynamicNamespaceLister) List(selector labels.Selector) (ret []*metav1.PartialObjectMetadata, err error) { // 该方法到对应包在做具体分析,用来获取符合selector和namespace对应添加的item err = cache.ListAllByNamespace(l.indexer, l.namespace, selector, func(m interface{}) { ret = append(ret, m.(*metav1.PartialObjectMetadata)) }) return ret, err } // Get 从索引器中检索给定命名空间和名称的资源的Metadata。 func (l *dynamicNamespaceLister) Get(name string) (*metav1.PartialObjectMetadata, error) { // 注意: 这里可以看到indexer中items的存放,当namespace不为空时,key是${namespace}/${name} obj, exists, err := l.indexer.GetByKey(l.namespace + "/" + name) if err != nil { return nil, err } if !exists { return nil, errors.NewNotFound(l.gvr.GroupResource(), name) } return obj.(*metav1.PartialObjectMetadata), nil } - 函数
// New 返回一个新的 Lister. func New(indexer cache.Indexer, gvr schema.GroupVersionResource) Lister { return &metadataLister{indexer: indexer, gvr: gvr} }
- 结构体
- shim.go
- 结构体
// dynamicListerShim 实现了 cache.GenericLister(后面章节再详细介绍) 接口。 // 包装了Lister接口,其实没有多少差别,只是List把返回slice中PartialObjectMetadata对象变为object对象 type metadataListerShim struct { lister Lister } // List 将返回跨命名空间的所有对象(其实是Metadata对象) func (s *metadataListerShim) List(selector labels.Selector) (ret []runtime.Object, err error) { // 从索引器(缓存)中获取所有符合标签选择器的obj objs, err := s.lister.List(selector) if err != nil { return nil, err } // 返回slice中PartialObjectMetadata对象变为Object对象 ret = make([]runtime.Object, len(objs)) for index, obj := range objs { ret[index] = obj } return ret, err } func (s *metadataListerShim) Get(name string) (runtime.Object, error) { return s.lister.Get(name) } // 获取限定命名空间的Lister func (s *metadataListerShim) ByNamespace(namespace string) cache.GenericNamespaceLister { return &metadataNamespaceListerShim{ namespaceLister: s.lister.Namespace(namespace), } } // metadataNamespaceListerShim 实现了 NamespaceLister 接口。 // 它包装了 NamespaceLister 以便它实现 cache.GenericNamespaceLister 接口 // 其实没有多少差别,只是List把返回slice中PartialObjectMetadata对象变为object对象 type metadataNamespaceListerShim struct { namespaceLister NamespaceLister } // List 将返回此命名空间中的所有对象(其实是Metadata) func (ns *metadataNamespaceListerShim) List(selector labels.Selector) (ret []runtime.Object, err error) { objs, err := ns.namespaceLister.List(selector) if err != nil { return nil, err } // 返回slice中PartialObjectMetadata对象变为Object对象 ret = make([]runtime.Object, len(objs)) for index, obj := range objs { ret[index] = obj } return ret, err } // Get 将尝试按命名空间和名称检索 func (ns *metadataNamespaceListerShim) Get(name string) (runtime.Object, error) { return ns.namespaceLister.Get(name) }
- 结构体
metadatainformer包
- interface.go
- 接口 定义了获取Informer的方法,等待缓存同步的方法,启动所有informer的方法
// Dynamic SharedInformerFactory 为动态客户端提供对共享informer和lister的访问 type DynamicSharedInformerFactory interface { // 启动所有informer的方法 Start(stopCh <-chan struct{}) // 获取Informer的方法 ForResource(gvr schema.GroupVersionResource) informers.GenericInformer // 等待缓存同步的方法 WaitForCacheSync(stopCh <-chan struct{}) map[schema.GroupVersionResource]bool } // TweakListOptionsFunc 定义了一个辅助函数的签名,想要为 API 提供更多的列表选项 type TweakListOptionsFunc func(*metav1.ListOptions)
- 接口 定义了获取Informer的方法,等待缓存同步的方法,启动所有informer的方法
- informer.go
- 函数
// NewSharedInformerFactory 为所有命名空间构造一个 SharedInformerFactory 的新实例。 func NewSharedInformerFactory(client dynamic.Interface, defaultResync time.Duration) SharedInformerFactory { return NewFilteredSharedInformerFactory(client, defaultResync, metav1.NamespaceAll, nil) } // NewFilteredSharedInformerFactory 构造了一个 metadataSharedInformerFactory 的新实例。 // 通过此工厂获得的lister将受到此处指定的相同过滤器的约束。 func NewFilteredDynamicSharedInformerFactory(client dynamic.Interface, defaultResync time.Duration, namespace string, tweakListOptions TweakListOptionsFunc) DynamicSharedInformerFactory { return &metadataSharedInformerFactory{ client: client, defaultResync: defaultResync, namespace: namespace, informers: map[schema.GroupVersionResource]informers.GenericInformer{}, startedInformers: make(map[schema.GroupVersionResource]bool), tweakListOptions: tweakListOptions, } } // NewFilteredMetadataInformer 为动态类型构造一个新的 Informer。 func NewFilteredMetadataInformer(client dynamic.Interface, gvr schema.GroupVersionResource, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions TweakListOptionsFunc) informers.GenericInformer { return &dynamicInformer{ gvr: gvr, // 创建共享的SharedIndexInformer informer: cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.Resource(gvr).Namespace(namespace).List(context.TODO(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.Resource(gvr).Namespace(namespace).Watch(context.TODO(), options) }, }, &unstructured.Unstructured{}, resyncPeriod, indexers, ), } } - 结构体
type metadataSharedInformerFactory struct { // 构建ListWatch接口使用,为后来构建reflector,执行listWatch监控api resource提供client client metadata.Interface // 同步周期,informer同步deltaFIFO中数据到listener中的chan中 defaultResync time.Duration // 命名空间 namespace string lock sync.Mutex // 缓存informer到map中 informers map[schema.GroupVersionResource]informers.GenericInformer // startInformers 用于跟踪哪些 Informers 已启动。这允许安全地多次调用 Start()。 startedInformers map[schema.GroupVersionResource]bool tweakListOptions TweakListOptionsFunc } // 实现metadataSharedInformerFactory的ForResource方法 func (f *metadataSharedInformerFactory) ForResource(gvr schema.GroupVersionResource) informers.GenericInformer { f.lock.Lock() defer f.lock.Unlock() key := gvr // 获取缓存map中的informer informer, exists := f.informers[key] if exists { return informer } // 不存在就创建 informer = NewFilteredMetadataInformer(f.client, gvr, f.namespace, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) f.informers[key] = informer return informer } // 实现SharedInformerFactory的Start方法,启动所有未启动的informer。 func (f *metadataSharedInformerFactory) Start(stopCh <-chan struct{}) { f.lock.Lock() defer f.lock.Unlock() // 遍历所有informer for informerType, informer := range f.informers { // 判断该informer是否已经启动 if !f.startedInformers[informerType] { // 启动informer go informer.Informer().Run(stopCh) // 设置对应gvr的informer已经启动 f.startedInformers[informerType] = true } } } // 实现SharedInformerFactory的WaitForCacheSync方法,等待所有启动的informer的缓存同步。 func (f *metadataSharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[schema.GroupVersionResource]bool { informers := func() map[schema.GroupVersionResource]cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() // 定义map,用于接收所有已经启动的informer informers := map[schema.GroupVersionResource]cache.SharedIndexInformer{} for informerType, informer := range f.informers { if f.startedInformers[informerType] { informers[informerType] = informer.Informer() } } return informers }() // 定义map,用于接收所有同步完成的informer res := map[schema.GroupVersionResource]bool{} // 遍历已经启动的所有informer for informType, informer := range informers { // 执行同步方法 // (1) 如果informer中controller为空,返回false, // (2) 如果informer.controller的queue还没有调用过Add/Update/Delete/AddIfNotPresent或者queue的initialPopulationCount != 0 (队列中还有数据),返回false res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) } return res } // Metadata的Informer结构体,包装了SharedIndexInformer和gvr type metadataInformer struct { informer cache.SharedIndexInformer gvr schema.GroupVersionResource } // 实现GenericInformer的Informer方法 func (d *metadataInformer) Informer() cache.SharedIndexInformer { return d.informer } // 实现GenericInformer的Lister方法,使用metadataInformer的indexer和gvr构造以Lister func (d *metadataInformer) Lister() cache.GenericLister { return metadatalister.NewRuntimeObjectShim(dynamiclister.New(d.informer.GetIndexer(), d.gvr)) }
- 函数