github.com/cilium/cilium@v1.16.2/pkg/bgpv1/manager/store/resource_store.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package store 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/cilium/hive/cell" 11 "github.com/cilium/hive/job" 12 k8sRuntime "k8s.io/apimachinery/pkg/runtime" 13 14 "github.com/cilium/cilium/pkg/bgpv1/agent/signaler" 15 "github.com/cilium/cilium/pkg/k8s/resource" 16 "github.com/cilium/cilium/pkg/lock" 17 "github.com/cilium/cilium/pkg/time" 18 ) 19 20 // BGPCPResourceStore is a wrapper around the resource.Store for the BGP Control Plane reconcilers usage. 21 // It automatically signals the BGP Control Plane whenever an event happens on the resource. 22 type BGPCPResourceStore[T k8sRuntime.Object] interface { 23 // GetByKey returns the latest version of the object with given key. 24 GetByKey(key resource.Key) (item T, exists bool, err error) 25 26 // List returns all items currently in the store. 27 List() (items []T, err error) 28 } 29 30 var _ BGPCPResourceStore[*k8sRuntime.Unknown] = (*bgpCPResourceStore[*k8sRuntime.Unknown])(nil) 31 32 type bgpCPResourceStoreParams[T k8sRuntime.Object] struct { 33 cell.In 34 35 Lifecycle cell.Lifecycle 36 Health cell.Health 37 JobGroup job.Group 38 Resource resource.Resource[T] 39 Signaler *signaler.BGPCPSignaler 40 } 41 42 // bgpCPResourceStore takes a resource.Resource[T] and watches for events. It can still be used as a normal Store, 43 // but in addition to that it will signal the BGP Control plane upon each event via the passed BGPCPSignaler. 44 type bgpCPResourceStore[T k8sRuntime.Object] struct { 45 store resource.Store[T] 46 47 resource resource.Resource[T] 48 signaler *signaler.BGPCPSignaler 49 50 mu lock.Mutex 51 } 52 53 func NewBGPCPResourceStore[T k8sRuntime.Object](params bgpCPResourceStoreParams[T]) BGPCPResourceStore[T] { 54 if params.Resource == nil { 55 return nil 56 } 57 58 s := &bgpCPResourceStore[T]{ 59 resource: params.Resource, 60 signaler: params.Signaler, 61 } 62 63 params.JobGroup.Add( 64 job.OneShot("bgpcp-resource-store-events", 65 func(ctx context.Context, health cell.Health) (err error) { 66 s.store, err = s.resource.Store(ctx) 67 if err != nil { 68 return fmt.Errorf("error creating resource store: %w", err) 69 } 70 for event := range s.resource.Events(ctx) { 71 s.signaler.Event(struct{}{}) 72 event.Done(nil) 73 } 74 return nil 75 }, 76 job.WithRetry(3, &job.ExponentialBackoff{Min: 100 * time.Millisecond, Max: time.Second}), 77 job.WithShutdown()), 78 ) 79 80 return s 81 } 82 83 // List returns all items currently in the store. 84 func (s *bgpCPResourceStore[T]) List() (items []T, err error) { 85 s.mu.Lock() 86 defer s.mu.Unlock() 87 88 if s.store == nil { 89 return nil, ErrStoreUninitialized 90 } 91 92 return s.store.List(), nil 93 } 94 95 // GetByKey returns the latest version of the object with given key. 96 func (s *bgpCPResourceStore[T]) GetByKey(key resource.Key) (item T, exists bool, err error) { 97 s.mu.Lock() 98 defer s.mu.Unlock() 99 100 if s.store == nil { 101 var empty T 102 return empty, false, ErrStoreUninitialized 103 } 104 105 return s.store.GetByKey(key) 106 }