blob: f8276317e48c1a3af4ad23f66540d5f7666291ac [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,
Jan Schära48bd3c2024-07-29 17:22:18 +020045 Process: builder(clientState, h),
46 }
47 return clientState, cache.New(cfg)
48}
49
50// DefaultProcessor is based on the Process function from
51// cache.NewIndexerInformer except it does a conversion.
52func DefaultProcessor(convert ToFunc) ProcessorBuilder {
53 return func(clientState cache.Indexer, h cache.ResourceEventHandler) cache.ProcessFunc {
54 return func(obj interface{}, isInitialList bool) error {
55 for _, d := range obj.(cache.Deltas) {
56 switch d.Type {
57 case cache.Sync, cache.Added, cache.Updated:
58 metaObj := d.Object.(metav1.Object)
59 obj, err := convert(metaObj)
60 if err != nil {
61 return err
62 }
63 if old, exists, err := clientState.Get(obj); err == nil && exists {
64 if err := clientState.Update(obj); err != nil {
65 return err
66 }
67 h.OnUpdate(old, obj)
68 } else {
69 if err := clientState.Add(obj); err != nil {
70 return err
71 }
72 h.OnAdd(obj, isInitialList)
73 }
74 case cache.Deleted:
75 var obj interface{}
76 obj, ok := d.Object.(cache.DeletedFinalStateUnknown)
77 if !ok {
78 var err error
79 metaObj, ok := d.Object.(metav1.Object)
80 if !ok {
81 return fmt.Errorf("unexpected object %v", d.Object)
82 }
83 obj, err = convert(metaObj)
84 if err != nil {
85 return err
86 }
87 }
88
89 if err := clientState.Delete(obj); err != nil {
90 return err
91 }
92 h.OnDelete(obj)
93 }
94 }
95 return nil
96 }
97 }
98}