mirror of https://github.com/k3s-io/k3s
126 lines
3.0 KiB
Go
126 lines
3.0 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/rancher/lasso/pkg/client"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/watch"
|
|
"k8s.io/client-go/tools/cache"
|
|
)
|
|
|
|
type Options struct {
|
|
Namespace string
|
|
Resync time.Duration
|
|
TweakList TweakListOptionsFunc
|
|
WaitHealthy func(ctx context.Context)
|
|
}
|
|
|
|
func NewCache(obj, listObj runtime.Object, client *client.Client, opts *Options) cache.SharedIndexInformer {
|
|
indexers := cache.Indexers{}
|
|
|
|
if client.Namespaced {
|
|
indexers[cache.NamespaceIndex] = cache.MetaNamespaceIndexFunc
|
|
}
|
|
|
|
opts = applyDefaultCacheOptions(opts)
|
|
|
|
lw := &deferredListWatcher{
|
|
client: client,
|
|
tweakList: opts.TweakList,
|
|
namespace: opts.Namespace,
|
|
listObj: listObj,
|
|
waitHealthy: opts.WaitHealthy,
|
|
}
|
|
|
|
return &deferredCache{
|
|
SharedIndexInformer: cache.NewSharedIndexInformer(
|
|
lw,
|
|
obj,
|
|
opts.Resync,
|
|
indexers,
|
|
),
|
|
deferredListWatcher: lw,
|
|
}
|
|
}
|
|
|
|
func applyDefaultCacheOptions(opts *Options) *Options {
|
|
var newOpts Options
|
|
if opts != nil {
|
|
newOpts = *opts
|
|
}
|
|
if newOpts.Resync == 0 {
|
|
newOpts.Resync = 10 * time.Hour
|
|
}
|
|
if newOpts.TweakList == nil {
|
|
newOpts.TweakList = func(*metav1.ListOptions) {}
|
|
}
|
|
return &newOpts
|
|
}
|
|
|
|
type deferredCache struct {
|
|
cache.SharedIndexInformer
|
|
deferredListWatcher *deferredListWatcher
|
|
}
|
|
|
|
type deferredListWatcher struct {
|
|
lw cache.ListerWatcher
|
|
client *client.Client
|
|
tweakList TweakListOptionsFunc
|
|
namespace string
|
|
listObj runtime.Object
|
|
waitHealthy func(ctx context.Context)
|
|
}
|
|
|
|
func (d *deferredListWatcher) List(options metav1.ListOptions) (runtime.Object, error) {
|
|
if d.lw == nil {
|
|
return nil, fmt.Errorf("cache not started")
|
|
}
|
|
return d.lw.List(options)
|
|
}
|
|
|
|
func (d *deferredListWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
|
|
if d.lw == nil {
|
|
return nil, fmt.Errorf("cache not started")
|
|
}
|
|
return d.lw.Watch(options)
|
|
}
|
|
|
|
func (d *deferredListWatcher) run(stopCh <-chan struct{}) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
go func() {
|
|
<-stopCh
|
|
cancel()
|
|
}()
|
|
|
|
d.lw = &cache.ListWatch{
|
|
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
|
d.tweakList(&options)
|
|
// If ResourceVersion is set to 0 then the Limit is ignored on the API side. Usually
|
|
// that's not a problem, but with very large counts of a single object type the client will
|
|
// hit it's connection timeout
|
|
if options.ResourceVersion == "0" {
|
|
options.ResourceVersion = ""
|
|
}
|
|
listObj := d.listObj.DeepCopyObject()
|
|
err := d.client.List(ctx, d.namespace, listObj, options)
|
|
if err != nil && d.waitHealthy != nil {
|
|
d.waitHealthy(ctx)
|
|
}
|
|
return listObj, err
|
|
},
|
|
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
|
d.tweakList(&options)
|
|
return d.client.Watch(ctx, d.namespace, options)
|
|
},
|
|
}
|
|
}
|
|
|
|
func (d *deferredCache) Run(stopCh <-chan struct{}) {
|
|
d.deferredListWatcher.run(stopCh)
|
|
d.SharedIndexInformer.Run(stopCh)
|
|
}
|