k8s.io/client-go@v0.22.2/dynamic/dynamicinformer/informer.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package dynamicinformer
    18  
    19  import (
    20  	"context"
    21  	"sync"
    22  	"time"
    23  
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/runtime/schema"
    28  	"k8s.io/apimachinery/pkg/watch"
    29  	"k8s.io/client-go/dynamic"
    30  	"k8s.io/client-go/dynamic/dynamiclister"
    31  	"k8s.io/client-go/informers"
    32  	"k8s.io/client-go/tools/cache"
    33  )
    34  
    35  // NewDynamicSharedInformerFactory constructs a new instance of dynamicSharedInformerFactory for all namespaces.
    36  func NewDynamicSharedInformerFactory(client dynamic.Interface, defaultResync time.Duration) DynamicSharedInformerFactory {
    37  	return NewFilteredDynamicSharedInformerFactory(client, defaultResync, metav1.NamespaceAll, nil)
    38  }
    39  
    40  // NewFilteredDynamicSharedInformerFactory constructs a new instance of dynamicSharedInformerFactory.
    41  // Listers obtained via this factory will be subject to the same filters as specified here.
    42  func NewFilteredDynamicSharedInformerFactory(client dynamic.Interface, defaultResync time.Duration, namespace string, tweakListOptions TweakListOptionsFunc) DynamicSharedInformerFactory {
    43  	return &dynamicSharedInformerFactory{
    44  		client:           client,
    45  		defaultResync:    defaultResync,
    46  		namespace:        namespace,
    47  		informers:        map[schema.GroupVersionResource]informers.GenericInformer{},
    48  		startedInformers: make(map[schema.GroupVersionResource]bool),
    49  		tweakListOptions: tweakListOptions,
    50  	}
    51  }
    52  
    53  type dynamicSharedInformerFactory struct {
    54  	client        dynamic.Interface
    55  	defaultResync time.Duration
    56  	namespace     string
    57  
    58  	lock      sync.Mutex
    59  	informers map[schema.GroupVersionResource]informers.GenericInformer
    60  	// startedInformers is used for tracking which informers have been started.
    61  	// This allows Start() to be called multiple times safely.
    62  	startedInformers map[schema.GroupVersionResource]bool
    63  	tweakListOptions TweakListOptionsFunc
    64  }
    65  
    66  var _ DynamicSharedInformerFactory = &dynamicSharedInformerFactory{}
    67  
    68  func (f *dynamicSharedInformerFactory) ForResource(gvr schema.GroupVersionResource) informers.GenericInformer {
    69  	f.lock.Lock()
    70  	defer f.lock.Unlock()
    71  
    72  	key := gvr
    73  	informer, exists := f.informers[key]
    74  	if exists {
    75  		return informer
    76  	}
    77  
    78  	informer = NewFilteredDynamicInformer(f.client, gvr, f.namespace, f.defaultResync, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
    79  	f.informers[key] = informer
    80  
    81  	return informer
    82  }
    83  
    84  // Start initializes all requested informers.
    85  func (f *dynamicSharedInformerFactory) Start(stopCh <-chan struct{}) {
    86  	f.lock.Lock()
    87  	defer f.lock.Unlock()
    88  
    89  	for informerType, informer := range f.informers {
    90  		if !f.startedInformers[informerType] {
    91  			go informer.Informer().Run(stopCh)
    92  			f.startedInformers[informerType] = true
    93  		}
    94  	}
    95  }
    96  
    97  // WaitForCacheSync waits for all started informers' cache were synced.
    98  func (f *dynamicSharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[schema.GroupVersionResource]bool {
    99  	informers := func() map[schema.GroupVersionResource]cache.SharedIndexInformer {
   100  		f.lock.Lock()
   101  		defer f.lock.Unlock()
   102  
   103  		informers := map[schema.GroupVersionResource]cache.SharedIndexInformer{}
   104  		for informerType, informer := range f.informers {
   105  			if f.startedInformers[informerType] {
   106  				informers[informerType] = informer.Informer()
   107  			}
   108  		}
   109  		return informers
   110  	}()
   111  
   112  	res := map[schema.GroupVersionResource]bool{}
   113  	for informType, informer := range informers {
   114  		res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
   115  	}
   116  	return res
   117  }
   118  
   119  // NewFilteredDynamicInformer constructs a new informer for a dynamic type.
   120  func NewFilteredDynamicInformer(client dynamic.Interface, gvr schema.GroupVersionResource, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions TweakListOptionsFunc) informers.GenericInformer {
   121  	return &dynamicInformer{
   122  		gvr: gvr,
   123  		informer: cache.NewSharedIndexInformer(
   124  			&cache.ListWatch{
   125  				ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
   126  					if tweakListOptions != nil {
   127  						tweakListOptions(&options)
   128  					}
   129  					return client.Resource(gvr).Namespace(namespace).List(context.TODO(), options)
   130  				},
   131  				WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
   132  					if tweakListOptions != nil {
   133  						tweakListOptions(&options)
   134  					}
   135  					return client.Resource(gvr).Namespace(namespace).Watch(context.TODO(), options)
   136  				},
   137  			},
   138  			&unstructured.Unstructured{},
   139  			resyncPeriod,
   140  			indexers,
   141  		),
   142  	}
   143  }
   144  
   145  type dynamicInformer struct {
   146  	informer cache.SharedIndexInformer
   147  	gvr      schema.GroupVersionResource
   148  }
   149  
   150  var _ informers.GenericInformer = &dynamicInformer{}
   151  
   152  func (d *dynamicInformer) Informer() cache.SharedIndexInformer {
   153  	return d.informer
   154  }
   155  
   156  func (d *dynamicInformer) Lister() cache.GenericLister {
   157  	return dynamiclister.NewRuntimeObjectShim(dynamiclister.New(d.informer.GetIndexer(), d.gvr))
   158  }