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  }