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