blob: 8ec1f2131eb28007023499aa5ad9dd77460ae7b6 [file] [log] [blame]
Jan Schära48bd3c2024-07-29 17:22:18 +02001package object
2
3// Taken and modified from the Kubernetes plugin of CoreDNS, under Apache 2.0.
4
5import (
6 "fmt"
7
8 "k8s.io/apimachinery/pkg/api/meta"
9 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 "k8s.io/apimachinery/pkg/runtime"
11 "k8s.io/client-go/tools/cache"
12)
13
14// KeyFunc works like cache.DeletionHandlingMetaNamespaceKeyFunc
15// but uses format "<name>.<namespace>" instead of "<namespace>/<name>".
16// This makes lookup for a service slightly more efficient, because we can
17// just use a slice of the query name instead of constructing a new string.
18func KeyFunc(obj interface{}) (string, error) {
19 if d, ok := obj.(cache.DeletedFinalStateUnknown); ok {
20 return d.Key, nil
21 }
22 objMeta, err := meta.Accessor(obj)
23 if err != nil {
24 return "", fmt.Errorf("object has no meta: %v", err)
25 }
26 if len(objMeta.GetNamespace()) == 0 {
27 return objMeta.GetName(), nil
28 }
29 return objMeta.GetName() + "." + objMeta.GetNamespace(), nil
30}
31
32// NewIndexerInformer is a copy of the cache.NewIndexerInformer function,
33// but allows custom process function.
34func NewIndexerInformer(lw cache.ListerWatcher, objType runtime.Object, h cache.ResourceEventHandler, indexers cache.Indexers, builder ProcessorBuilder) (cache.Indexer, cache.Controller) {
35 clientState := cache.NewIndexer(KeyFunc, indexers)
36
37 cfg := &cache.Config{
38 Queue: cache.NewDeltaFIFOWithOptions(cache.DeltaFIFOOptions{KeyFunction: KeyFunc, KnownObjects: clientState}),
39 ListerWatcher: lw,
40 ObjectType: objType,
41 FullResyncPeriod: 0,
42 RetryOnError: false,
43 Process: builder(clientState, h),
44 }
45 return clientState, cache.New(cfg)
46}
47
48// DefaultProcessor is based on the Process function from
49// cache.NewIndexerInformer except it does a conversion.
50func DefaultProcessor(convert ToFunc) ProcessorBuilder {
51 return func(clientState cache.Indexer, h cache.ResourceEventHandler) cache.ProcessFunc {
52 return func(obj interface{}, isInitialList bool) error {
53 for _, d := range obj.(cache.Deltas) {
54 switch d.Type {
55 case cache.Sync, cache.Added, cache.Updated:
56 metaObj := d.Object.(metav1.Object)
57 obj, err := convert(metaObj)
58 if err != nil {
59 return err
60 }
61 if old, exists, err := clientState.Get(obj); err == nil && exists {
62 if err := clientState.Update(obj); err != nil {
63 return err
64 }
65 h.OnUpdate(old, obj)
66 } else {
67 if err := clientState.Add(obj); err != nil {
68 return err
69 }
70 h.OnAdd(obj, isInitialList)
71 }
72 case cache.Deleted:
73 var obj interface{}
74 obj, ok := d.Object.(cache.DeletedFinalStateUnknown)
75 if !ok {
76 var err error
77 metaObj, ok := d.Object.(metav1.Object)
78 if !ok {
79 return fmt.Errorf("unexpected object %v", d.Object)
80 }
81 obj, err = convert(metaObj)
82 if err != nil {
83 return err
84 }
85 }
86
87 if err := clientState.Delete(obj); err != nil {
88 return err
89 }
90 h.OnDelete(obj)
91 }
92 }
93 return nil
94 }
95 }
96}