From a9610514706535940e96ac3f4defa63a71a583a4 Mon Sep 17 00:00:00 2001 From: Sunny Date: Thu, 17 Oct 2024 14:15:43 +0000 Subject: [PATCH 1/4] Simplify the cache - Remove dependency on kubernetes. - Simplify the Store interface to only have Get, Set and Delete. - Add new RecordCacheEvent() method in the cache implementations for recording the cache events, hit or miss, along with labels of the associated flux object being reconciled. The labels name, namespace and kind for this metric are not required to be configured when creating the cache. They are predefined in the created metrics recorder, similar to the runtime metrics recorder for the rest of flux. RecordCacheEvent() has to be called by the caller of cache operations explicitly along with the label information of the associated object being reconciled. The cache no longer has the knowledge of the object being reconciled, decoupled. - With the decoupled cache and reconciling object for metrics, the storeOptions no longer need to have the generic type defined. Simplifying the usage. - Add new DeleteCacheEvent() method in the cache implementations for deleting the cache events, hit or miss, which are associated with the object being reconciled. When the reconciling object is deleted, these metrics associated with the object must also be deleted. - Updated all the tests to use simple string cache. - Get() now returns a pointer instead of a separate exists boolean. If the pointer is nil, the item is not found in the cache. - Get() takes a key and returns a cached item for it. GetByKey() is removed as Get() does the same. Signed-off-by: Sunny --- cache/cache.go | 163 +++++----------- cache/cache_test.go | 436 ++++++++++++++++-------------------------- cache/doc.go | 53 +++++ cache/errors.go | 11 +- cache/go.mod | 46 +---- cache/go.sum | 197 +------------------ cache/lru.go | 130 ++++--------- cache/lru_test.go | 416 ++++++++++++---------------------------- cache/metrics.go | 40 +--- cache/metrics_test.go | 6 +- cache/store.go | 110 ++--------- 11 files changed, 473 insertions(+), 1135 deletions(-) create mode 100644 cache/doc.go diff --git a/cache/cache.go b/cache/cache.go index 3e68f733..f5934f80 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -32,22 +32,17 @@ const ( defaultInterval = time.Minute ) -// Cache[T] is a thread-safe in-memory key/object store. -// It can be used to store objects with optional expiration. -// A function to extract the key from the object must be provided. -// Use the New function to create a new cache that is ready to use. +// Cache[T] is a thread-safe in-memory key/value store. +// It can be used to store items with optional expiration. type Cache[T any] struct { *cache[T] - // keyFunc is used to make the key for objects stored in and retrieved from index, and - // should be deterministic. - keyFunc KeyFunc[T] } // item is an item stored in the cache. type item[T any] struct { key string - // object is the item's object. - object T + // value is the item's value. + value T // expiresAt is the item's expiration time. expiresAt time.Time } @@ -61,11 +56,10 @@ type cache[T any] struct { // It is initially true, and set to false when the items are not sorted. sorted bool // capacity is the maximum number of index the cache can hold. - capacity int - metrics *cacheMetrics - labelsFunc GetLvsFunc[T] - janitor *janitor[T] - closed bool + capacity int + metrics *cacheMetrics + janitor *janitor[T] + closed bool mu sync.RWMutex } @@ -73,18 +67,17 @@ type cache[T any] struct { var _ Expirable[any] = &Cache[any]{} // New creates a new cache with the given configuration. -func New[T any](capacity int, keyFunc KeyFunc[T], opts ...Options[T]) (*Cache[T], error) { +func New[T any](capacity int, opts ...Options) (*Cache[T], error) { opt, err := makeOptions(opts...) if err != nil { return nil, fmt.Errorf("failed to apply options: %w", err) } c := &cache[T]{ - index: make(map[string]*item[T]), - items: make([]*item[T], 0, capacity), - sorted: true, - capacity: capacity, - labelsFunc: opt.labelsFunc, + index: make(map[string]*item[T]), + items: make([]*item[T], 0, capacity), + sorted: true, + capacity: capacity, janitor: &janitor[T]{ interval: opt.interval, stop: make(chan bool), @@ -92,10 +85,10 @@ func New[T any](capacity int, keyFunc KeyFunc[T], opts ...Options[T]) (*Cache[T] } if opt.registerer != nil { - c.metrics = newCacheMetrics(opt.registerer, opt.extraLabels...) + c.metrics = newCacheMetrics(opt.registerer) } - C := &Cache[T]{cache: c, keyFunc: keyFunc} + C := &Cache[T]{cache: c} if opt.interval > 0 { go c.janitor.run(c) @@ -104,8 +97,8 @@ func New[T any](capacity int, keyFunc KeyFunc[T], opts ...Options[T]) (*Cache[T] return C, nil } -func makeOptions[T any](opts ...Options[T]) (*storeOptions[T], error) { - opt := storeOptions[T]{} +func makeOptions(opts ...Options) (*storeOptions, error) { + opt := storeOptions{} for _, o := range opts { err := o(&opt) if err != nil { @@ -131,14 +124,8 @@ func (c *Cache[T]) Close() error { } // Set an item in the cache, existing index will be overwritten. -// If the cache is full, Add will return an error. -func (c *Cache[T]) Set(object T) error { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return &CacheError{Reason: ErrInvalidKey, Err: err} - } - +// If the cache is full, an error is returned. +func (c *Cache[T]) Set(key string, value T) error { c.mu.Lock() if c.closed { c.mu.Unlock() @@ -147,14 +134,14 @@ func (c *Cache[T]) Set(object T) error { } _, found := c.index[key] if found { - c.set(key, object) + c.set(key, value) c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) return nil } if c.capacity > 0 && len(c.index) < c.capacity { - c.set(key, object) + c.set(key, value) c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) recordItemIncrement(c.metrics) @@ -165,10 +152,10 @@ func (c *Cache[T]) Set(object T) error { return ErrCacheFull } -func (c *cache[T]) set(key string, object T) { +func (c *cache[T]) set(key string, value T) { item := item[T]{ key: key, - object: object, + value: value, expiresAt: time.Now().Add(noExpiration), } @@ -181,86 +168,41 @@ func (c *cache[T]) set(key string, object T) { c.items = append(c.items, &item) } -// Get an item from the cache. Returns the item or nil, and a bool indicating -// whether the key was found. -func (c *Cache[T]) Get(object T) (item T, exists bool, err error) { - var res T - lvs := []string{} - if c.labelsFunc != nil { - lvs, err = c.labelsFunc(object, len(c.metrics.getExtraLabels())) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return res, false, &CacheError{Reason: ErrInvalidLabels, Err: err} - } - } - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return res, false, &CacheError{Reason: ErrInvalidKey, Err: err} - } - item, found, err := c.get(key) - if err != nil { - return res, false, err - } - if !found { - recordEvent(c.metrics, CacheEventTypeMiss, lvs...) - return res, false, nil - } - recordEvent(c.metrics, CacheEventTypeHit, lvs...) - return item, true, nil -} - -// GetByKey returns the object for the given key. -func (c *Cache[T]) GetByKey(key string) (T, bool, error) { - var res T - index, found, err := c.get(key) - if err != nil { - return res, false, err - } - if !found { - recordEvent(c.metrics, CacheEventTypeMiss) - return res, false, nil - } - - recordEvent(c.metrics, CacheEventTypeHit) - return index, true, nil -} - -func (c *cache[T]) get(key string) (T, bool, error) { - var res T +// Get returns a pointer to an item in the cache for the given key. If no item +// is found, it's a nil pointer. +// The caller can record cache hit or miss based on the result with +// Cache.RecordCacheEvent(). +func (c *Cache[T]) Get(key string) (*T, error) { c.mu.RLock() if c.closed { c.mu.RUnlock() recordRequest(c.metrics, StatusFailure) - return res, false, ErrCacheClosed + return nil, ErrCacheClosed } item, found := c.index[key] if !found { c.mu.RUnlock() recordRequest(c.metrics, StatusSuccess) - return res, false, nil + return nil, nil } if !item.expiresAt.IsZero() { if item.expiresAt.Compare(time.Now()) < 0 { c.mu.RUnlock() recordRequest(c.metrics, StatusSuccess) - return res, false, nil + return nil, nil } } c.mu.RUnlock() recordRequest(c.metrics, StatusSuccess) - return item.object, true, nil + // Copy the value to prevent writes to the cached item. + r := item.value + return &r, nil } // Delete an item from the cache. Does nothing if the key is not in the cache. // It actually sets the item expiration to `now“, so that it will be deleted at // the cleanup. -func (c *Cache[T]) Delete(object T) error { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return &CacheError{Reason: ErrInvalidKey, Err: err} - } +func (c *Cache[T]) Delete(key string) error { c.mu.Lock() if c.closed { c.mu.Unlock() @@ -355,13 +297,7 @@ func (c *cache[T]) Resize(size int) (int, error) { } // HasExpired returns true if the item has expired. -func (c *Cache[T]) HasExpired(object T) (bool, error) { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return false, &CacheError{Reason: ErrInvalidKey, Err: err} - } - +func (c *Cache[T]) HasExpired(key string) (bool, error) { c.mu.RLock() if c.closed { c.mu.RUnlock() @@ -387,13 +323,7 @@ func (c *Cache[T]) HasExpired(object T) (bool, error) { } // SetExpiration sets the expiration for the given key. -func (c *Cache[T]) SetExpiration(object T, expiration time.Time) error { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return &CacheError{Reason: ErrInvalidKey, Err: err} - } - +func (c *Cache[T]) SetExpiration(key string, expiration time.Time) error { c.mu.Lock() if c.closed { c.mu.Unlock() @@ -417,12 +347,7 @@ func (c *Cache[T]) SetExpiration(object T, expiration time.Time) error { // GetExpiration returns the expiration for the given key. // Returns zero if the key is not in the cache or the item // has already expired. -func (c *Cache[T]) GetExpiration(object T) (time.Time, error) { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return time.Time{}, &CacheError{Reason: ErrInvalidKey, Err: err} - } +func (c *Cache[T]) GetExpiration(key string) (time.Time, error) { c.mu.RLock() if c.closed { c.mu.RUnlock() @@ -481,6 +406,18 @@ func (c *cache[T]) deleteExpired() { c.mu.Unlock() } +// RecordCacheEvent records a cache event (cache_miss or cache_hit) with kind, +// name and namespace of the associated object being reconciled. +func (c *Cache[T]) RecordCacheEvent(event, kind, name, namespace string) { + recordCacheEvent(c.metrics, event, kind, name, namespace) +} + +// DeleteCacheEvent deletes the cache event (cache_miss or cache_hit) metric for +// the associated object being reconciled, given their kind, name and namespace. +func (c *Cache[T]) DeleteCacheEvent(event, kind, name, namespace string) { + deleteCacheEvent(c.metrics, event, kind, name, namespace) +} + type janitor[T any] struct { interval time.Duration stop chan bool diff --git a/cache/cache_test.go b/cache/cache_test.go index 62dfe393..e1474dfc 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -23,94 +23,68 @@ import ( "testing" "time" - "github.com/fluxcd/cli-utils/pkg/object" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - kc "k8s.io/client-go/tools/cache" ) func TestCache(t *testing.T) { t.Run("Add and update keys", func(t *testing.T) { g := NewWithT(t) // create a cache that can hold 2 items and have no cleanup - cache, err := New(3, kc.MetaNamespaceKeyFunc, - WithMetricsRegisterer[any](prometheus.NewPedanticRegistry()), - WithCleanupInterval[any](1*time.Second)) + cache, err := New[string](3, + WithMetricsRegisterer(prometheus.NewPedanticRegistry()), + WithCleanupInterval(1*time.Second)) g.Expect(err).ToNot(HaveOccurred()) - obj := &metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test", - }, - } - // Get an Item from the cache - _, found, err := cache.Get(obj) + key1 := "key1" + value1 := "val1" + got, err := cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeFalse()) + g.Expect(got).To(BeNil()) // Add an item to the cache - err = cache.Set(obj) + err = cache.Set(key1, value1) g.Expect(err).ToNot(HaveOccurred()) // Get the item from the cache - item, found, err := cache.Get(obj) + got, err = cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue()) - g.Expect(item).To(Equal(obj)) + g.Expect(*got).To(Equal(value1)) + + // Writing to the obtained value doesn't update the cache. + *got = "val2" + got2, err := cache.Get(key1) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(*got2).To(Equal(value1)) - obj2 := &metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test2", - }, - } // Add another item to the cache - err = cache.Set(obj2) + key2 := "key2" + value2 := "val2" + err = cache.Set(key2, value2) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns/test", "test-ns/test2")) + g.Expect(cache.ListKeys()).To(ConsistOf(key1, key2)) // Get the item from the cache - item, found, err = cache.GetByKey("test-ns/test2") + got, err = cache.Get(key2) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue()) - g.Expect(item).To(Equal(obj2)) - - //Update an item in the cache - obj3 := &metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test3", - }, - } - err = cache.Set(obj3) + g.Expect(*got).To(Equal(value2)) + + // Update an item in the cache + key3 := "key3" + value3 := "val3" + value4 := "val4" + err = cache.Set(key3, value3) g.Expect(err).ToNot(HaveOccurred()) // Replace an item in the cache - obj3.Labels = map[string]string{"pp.kubernetes.io/created-by: ": "flux"} - err = cache.Set(obj3) + err = cache.Set(key3, value4) g.Expect(err).ToNot(HaveOccurred()) // Get the item from the cache - item, found, err = cache.Get(obj3) + got, err = cache.Get(key3) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue()) - g.Expect(item).To(Equal(obj3)) + g.Expect(*got).To(Equal(value4)) // cleanup the cache cache.Clear() @@ -124,183 +98,134 @@ func TestCache(t *testing.T) { t.Run("Add expiring keys", func(t *testing.T) { g := NewWithT(t) // new cache with a cleanup interval of 1 second - cache, err := New(2, IdentifiableObjectKeyFunc, - WithCleanupInterval[IdentifiableObject](1*time.Second), - WithMetricsRegisterer[IdentifiableObject](prometheus.NewPedanticRegistry())) + + cache, err := New[string](2, + WithCleanupInterval(1*time.Second), + WithMetricsRegisterer(prometheus.NewPedanticRegistry())) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: struct { - token string - }{ - token: "test-token", - }, - } + key := "key1" + value := "val1" - err = cache.Set(obj) + err = cache.Set(key, value) g.Expect(err).ToNot(HaveOccurred()) // set expiration time to 2 seconds - err = cache.SetExpiration(obj, time.Now().Add(2*time.Second)) + err = cache.SetExpiration(key, time.Now().Add(2*time.Second)) g.Expect(err).ToNot(HaveOccurred()) // Get the item from the cache - item, found, err := cache.Get(obj) + item, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue()) - g.Expect(item).To(Equal(obj)) + g.Expect(*item).To(Equal(value)) // wait for the item to expire time.Sleep(3 * time.Second) // Get the item from the cache - item, found, err = cache.Get(obj) + item, err = cache.Get(key) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(item).To(BeNil()) + }) + + t.Run("Cache of integer value", func(t *testing.T) { + g := NewWithT(t) + + cache, err := New[int](3, WithMetricsRegisterer(prometheus.NewPedanticRegistry())) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeFalse()) - g.Expect(item.Object).To(BeNil()) + + key := "key1" + g.Expect(cache.Set(key, 4)).To(Succeed()) + + got, err := cache.Get(key) + g.Expect(err).To(Succeed()) + g.Expect(*got).To(Equal(4)) }) } -func Test_Cache_Add(t *testing.T) { +func Test_Cache_Set(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := New[IdentifiableObject](1, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg), - WithCleanupInterval[IdentifiableObject](10*time.Millisecond)) + cache, err := New[string](1, + WithMetricsRegisterer(reg), + WithCleanupInterval(10*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - err = cache.Set(obj) + key1 := "key1" + value1 := "val1" + err = cache.Set(key1, value1) g.Expect(err).ToNot(HaveOccurred()) - err = cache.SetExpiration(obj, time.Now().Add(10*time.Millisecond)) + err = cache.SetExpiration(key1, time.Now().Add(10*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) + g.Expect(cache.ListKeys()).To(ConsistOf(key1)) // try adding the same object again, it should overwrite the existing one - err = cache.Set(obj) + err = cache.Set(key1, value1) g.Expect(err).ToNot(HaveOccurred()) // wait for the item to expire time.Sleep(20 * time.Millisecond) - ok, err := cache.HasExpired(obj) + ok, err := cache.HasExpired(key1) g.Expect(err).ToNot(HaveOccurred()) g.Expect(ok).To(BeTrue()) // add another object - obj.Name = "test2" - err = cache.Set(obj) + key2 := "key2" + value2 := "val2" + err = cache.Set(key2, value2) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test2_test-group_TestObject")) - - // validate metrics - validateMetrics(reg, ` - # HELP gotk_cache_evictions_total Total number of cache evictions. - # TYPE gotk_cache_evictions_total counter - gotk_cache_evictions_total 1 - # HELP gotk_cache_requests_total Total number of cache requests partioned by success or failure. - # TYPE gotk_cache_requests_total counter - gotk_cache_requests_total{status="success"} 7 - # HELP gotk_cached_items Total number of items in the cache. - # TYPE gotk_cached_items gauge - gotk_cached_items 1 -`, t) -} + g.Expect(cache.ListKeys()).To(ConsistOf(key2)) -func Test_Cache_Update(t *testing.T) { - g := NewWithT(t) - reg := prometheus.NewPedanticRegistry() - cache, err := New[IdentifiableObject](1, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg)) + // Update the value of existing item. + value3 := "val3" + err = cache.Set(key2, value3) g.Expect(err).ToNot(HaveOccurred()) - - // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - err = cache.Set(obj) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) - - obj.Object = "test-token2" - err = cache.Set(obj) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) - g.Expect(cache.index["test-ns_test_test-group_TestObject"].object.Object).To(Equal("test-token2")) + g.Expect(cache.ListKeys()).To(ConsistOf(key2)) + g.Expect(cache.index[key2].value).To(Equal(value3)) // validate metrics validateMetrics(reg, ` # HELP gotk_cache_evictions_total Total number of cache evictions. # TYPE gotk_cache_evictions_total counter - gotk_cache_evictions_total 0 + gotk_cache_evictions_total 1 # HELP gotk_cache_requests_total Total number of cache requests partioned by success or failure. # TYPE gotk_cache_requests_total counter - gotk_cache_requests_total{status="success"} 4 + gotk_cache_requests_total{status="success"} 9 # HELP gotk_cached_items Total number of items in the cache. # TYPE gotk_cached_items gauge gotk_cached_items 1 - `, t) +`, t) } func Test_Cache_Get(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := New[IdentifiableObject](5, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg), - WithMetricsLabels[IdentifiableObject](IdentifiableObjectLabels, IdentifiableObjectLVSFunc)) + cache, err := New[string](5, WithMetricsRegisterer(reg)) g.Expect(err).ToNot(HaveOccurred()) + // Reconciling object label values for cache event metric. + recObjKind := "TestObject" + recObjName := "test" + recObjNamespace := "test-ns" + // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } + key := "key1" + value := "val1" - _, found, err := cache.Get(obj) + got, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeFalse()) + g.Expect(got).To(BeNil()) + cache.RecordCacheEvent(CacheEventTypeMiss, recObjKind, recObjName, recObjNamespace) - err = cache.Set(obj) + err = cache.Set(key, value) g.Expect(err).ToNot(HaveOccurred()) - item, found, err := cache.Get(obj) + got, err = cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue()) - g.Expect(item).To(Equal(obj)) + g.Expect(*got).To(Equal(value)) + cache.RecordCacheEvent(CacheEventTypeHit, recObjKind, recObjName, recObjNamespace) validateMetrics(reg, ` # HELP gotk_cache_events_total Total number of cache retrieval events for a Gitops Toolkit resource reconciliation. @@ -317,34 +242,41 @@ func Test_Cache_Get(t *testing.T) { # TYPE gotk_cached_items gauge gotk_cached_items 1 `, t) + + cache.DeleteCacheEvent(CacheEventTypeHit, recObjKind, recObjName, recObjNamespace) + cache.DeleteCacheEvent(CacheEventTypeMiss, recObjKind, recObjName, recObjNamespace) + + validateMetrics(reg, ` + # HELP gotk_cache_evictions_total Total number of cache evictions. + # TYPE gotk_cache_evictions_total counter + gotk_cache_evictions_total 0 + # HELP gotk_cache_requests_total Total number of cache requests partioned by success or failure. + # TYPE gotk_cache_requests_total counter + gotk_cache_requests_total{status="success"} 3 + # HELP gotk_cached_items Total number of items in the cache. + # TYPE gotk_cached_items gauge + gotk_cached_items 1 +`, t) + } func Test_Cache_Delete(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := New[IdentifiableObject](5, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg), - WithCleanupInterval[IdentifiableObject](1*time.Millisecond)) + cache, err := New[string](5, + WithMetricsRegisterer(reg), + WithCleanupInterval(1*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } + key := "key1" + value := "value1" - err = cache.Set(obj) + err = cache.Set(key, value) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) + g.Expect(cache.ListKeys()).To(ConsistOf(key)) - err = cache.Delete(obj) + err = cache.Delete(key) g.Expect(err).ToNot(HaveOccurred()) time.Sleep(5 * time.Millisecond) @@ -365,7 +297,8 @@ func Test_Cache_Delete(t *testing.T) { func Test_Cache_deleteExpired(t *testing.T) { type expiringItem struct { - object StoreObject[string] + key string + value string expiresAt time.Time expire bool } @@ -378,17 +311,13 @@ func Test_Cache_deleteExpired(t *testing.T) { name: "non expiring items", items: []expiringItem{ { - object: StoreObject[string]{ - Object: "test-token", - Key: "test", - }, + key: "test", + value: "test-token", expiresAt: time.Now().Add(noExpiration), }, { - object: StoreObject[string]{ - Object: "test-token2", - Key: "test2", - }, + key: "test2", + value: "test-token2", expiresAt: time.Now().Add(noExpiration), }, }, @@ -398,18 +327,14 @@ func Test_Cache_deleteExpired(t *testing.T) { name: "expiring items", items: []expiringItem{ { - object: StoreObject[string]{ - Object: "test-token", - Key: "test", - }, + key: "test", + value: "test-token", expiresAt: time.Now().Add(1 * time.Millisecond), expire: true, }, { - object: StoreObject[string]{ - Object: "test-token2", - Key: "test2", - }, + key: "test2", + value: "test-token2", expiresAt: time.Now().Add(1 * time.Millisecond), expire: true, }, @@ -420,25 +345,19 @@ func Test_Cache_deleteExpired(t *testing.T) { name: "mixed items", items: []expiringItem{ { - object: StoreObject[string]{ - Object: "test-token", - Key: "test", - }, + key: "test", + value: "test-token", expiresAt: time.Now().Add(1 * time.Millisecond), expire: true, }, { - object: StoreObject[string]{ - Object: "test-token2", - Key: "test2", - }, + key: "test2", + value: "test-token2", expiresAt: time.Now().Add(noExpiration), }, { - object: StoreObject[string]{ - Object: "test-token3", - Key: "test3", - }, + key: "test3", + value: "test-token3", expiresAt: time.Now().Add(1 * time.Minute), expire: true, }, @@ -451,16 +370,16 @@ func Test_Cache_deleteExpired(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := New[StoreObject[string]](5, StoreObjectKeyFunc, - WithMetricsRegisterer[StoreObject[string]](reg), - WithCleanupInterval[StoreObject[string]](1*time.Millisecond)) + cache, err := New[string](5, + WithMetricsRegisterer(reg), + WithCleanupInterval(1*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) for _, item := range tt.items { - err := cache.Set(item.object) + err := cache.Set(item.key, item.value) g.Expect(err).ToNot(HaveOccurred()) if item.expire { - err = cache.SetExpiration(item.object, item.expiresAt) + err = cache.SetExpiration(item.key, item.expiresAt) g.Expect(err).ToNot(HaveOccurred()) } } @@ -477,26 +396,18 @@ func Test_Cache_Resize(t *testing.T) { n := 100 g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := New[IdentifiableObject](n, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg), - WithCleanupInterval[IdentifiableObject](10*time.Millisecond)) + + cache, err := New[string](n, + WithMetricsRegisterer(reg), + WithCleanupInterval(10*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) for i := range n { - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: fmt.Sprintf("test-%d", i), - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - err = cache.Set(obj) + key := fmt.Sprintf("test-%d", i) + value := "test-token" + err = cache.Set(key, value) g.Expect(err).ToNot(HaveOccurred()) - err = cache.SetExpiration(obj, time.Now().Add(10*time.Minute)) + err = cache.SetExpiration(key, time.Now().Add(10*time.Minute)) g.Expect(err).ToNot(HaveOccurred()) } @@ -520,12 +431,16 @@ func TestCache_Concurrent(t *testing.T) { ) g := NewWithT(t) // create a cache that can hold 10 items and have no cleanup - cache, err := New(10, IdentifiableObjectKeyFunc, - WithCleanupInterval[IdentifiableObject](1*time.Second), - WithMetricsRegisterer[IdentifiableObject](prometheus.NewPedanticRegistry())) + cache, err := New[string](10, + WithCleanupInterval(1*time.Second), + WithMetricsRegisterer(prometheus.NewPedanticRegistry())) g.Expect(err).ToNot(HaveOccurred()) - objmap := createObjectMap(keysNum) + keymap := map[int]string{} + for i := 0; i < keysNum; i++ { + key := fmt.Sprintf("test-%d", i) + keymap[i] = key + } wg := sync.WaitGroup{} run := make(chan bool) @@ -536,13 +451,13 @@ func TestCache_Concurrent(t *testing.T) { wg.Add(2) go func() { defer wg.Done() - _ = cache.Set(objmap[key]) + _ = cache.Set(keymap[key], "test-token") }() go func() { defer wg.Done() <-run - _, _, _ = cache.Get(objmap[key]) - _ = cache.SetExpiration(objmap[key], time.Now().Add(noExpiration)) + _, _ = cache.Get(keymap[key]) + _ = cache.SetExpiration(keymap[key], time.Now().Add(noExpiration)) }() } close(run) @@ -550,35 +465,12 @@ func TestCache_Concurrent(t *testing.T) { keys, err := cache.ListKeys() g.Expect(err).ToNot(HaveOccurred()) - g.Expect(len(keys)).To(Equal(len(objmap))) + g.Expect(len(keys)).To(Equal(len(keymap))) - for _, obj := range objmap { - val, found, err := cache.Get(obj) + for _, key := range keymap { + val, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue(), "object %s not found", obj.Name) - g.Expect(val).To(Equal(obj)) - } -} - -func createObjectMap(num int) map[int]IdentifiableObject { - objMap := make(map[int]IdentifiableObject) - for i := 0; i < num; i++ { - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: fmt.Sprintf("test-%d", i), - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: struct { - token string - }{ - token: "test-token", - }, - } - objMap[i] = obj + g.Expect(val).ToNot(BeNil(), "object %s not found", key) + g.Expect(*val).To(Equal("test-token")) } - return objMap } diff --git a/cache/doc.go b/cache/doc.go new file mode 100644 index 00000000..699b5c69 --- /dev/null +++ b/cache/doc.go @@ -0,0 +1,53 @@ +/* +Copyright 2024 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package cache provides a Store interface for a cache store, along with two +// implementations of this interface for expiring cache(Cache) and least +// recently used cache(LRU). Expirable defines an interface for cache with +// expiring items. This is also implemented by the expiring cache +// implementation, Cache. +// The Cache and LRU cache implementations are generic cache. The data type of +// the value stored in the cache has to be defined when creating the cache. For +// example, for storing string values in Cache create a string type Cache +// +// cache, err := New[string](10) +// +// The cache implementations are self-instrumenting and export metrics about the +// internal operations of the cache if it is configured with a metrics +// registerer. +// +// cache, err := New[string](10, WithMetricsRegisterer(reg)) +// +// For recording cache hit/miss metrics associated with a Flux object for which +// the cache is used, the caller must explicitly record the cache event based on +// the result of the operation along with the object in the context +// +// got, err := cache.Get("foo") +// // Handle any error. +// ... +// +// if got != nil { +// cache.RecordCacheEvent(CacheEventTypeHit, "GitRepository", "repoA", "testNS") +// } else { +// cache.RecordCacheEvent(CacheEventTypeMiss, "GitRepository", "repoA", "testNS") +// } +// +// When the Flux object associated with the cache metrics is deleted, the +// metrics can be deleted as follows +// +// cache.DeleteCacheEvent(CacheEventTypeHit, "GitRepository", "repoA", "testNS") +// cache.DeleteCacheEvent(CacheEventTypeMiss, "GitRepository", "repoA", "testNS") +package cache diff --git a/cache/errors.go b/cache/errors.go index 2b69055b..b52af260 100644 --- a/cache/errors.go +++ b/cache/errors.go @@ -64,11 +64,8 @@ func (e *CacheError) Unwrap() error { } var ( - ErrNotFound = CacheErrorReason{"NotFound", "object not found"} - ErrAlreadyExists = CacheErrorReason{"AlreadyRxists", "object already exists"} - ErrCacheClosed = CacheErrorReason{"CacheClosed", "cache is closed"} - ErrCacheFull = CacheErrorReason{"CacheFull", "cache is full"} - ErrInvalidSize = CacheErrorReason{"InvalidSize", "invalid size"} - ErrInvalidKey = CacheErrorReason{"InvalidKey", "invalid key"} - ErrInvalidLabels = CacheErrorReason{"InvalidLabels", "invalid labels"} + ErrNotFound = CacheErrorReason{"NotFound", "object not found"} + ErrCacheClosed = CacheErrorReason{"CacheClosed", "cache is closed"} + ErrCacheFull = CacheErrorReason{"CacheFull", "cache is full"} + ErrInvalidSize = CacheErrorReason{"InvalidSize", "invalid size"} ) diff --git a/cache/go.mod b/cache/go.mod index 7870055e..e5aed37c 100644 --- a/cache/go.mod +++ b/cache/go.mod @@ -3,66 +3,24 @@ module github.com/fluxcd/pkg/cache go 1.22.7 require ( - github.com/fluxcd/cli-utils v0.36.0-flux.10 github.com/onsi/gomega v1.36.0 github.com/prometheus/client_golang v1.20.5 - k8s.io/apimachinery v0.31.3 - k8s.io/client-go v0.31.3 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-errors/errors v1.5.1 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect + github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/x448/float16 v0.8.4 // indirect - github.com/xlab/treeprint v1.2.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect golang.org/x/net v0.31.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/time v0.8.0 // indirect google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.31.3 // indirect - k8s.io/cli-runtime v0.31.3 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.18.0 // indirect - sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/cache/go.sum b/cache/go.sum index ccc5765b..592688e3 100644 --- a/cache/go.sum +++ b/cache/go.sum @@ -1,118 +1,30 @@ -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fluxcd/cli-utils v0.36.0-flux.10 h1:kgoj1HP7KBFfIG9CHLFHpA2kCPNlfzCpbscCaAOSClE= -github.com/fluxcd/cli-utils v0.36.0-flux.10/go.mod h1:eWf+UVZmm51EmNmeGkdplVLVsFU4jETfCjoHZq7nUp4= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= -github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= +github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= github.com/onsi/gomega v1.36.0/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -123,115 +35,18 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= -golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= -k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/cli-runtime v0.31.3 h1:fEQD9Xokir78y7pVK/fCJN090/iYNrLHpFbGU4ul9TI= -k8s.io/cli-runtime v0.31.3/go.mod h1:Q2jkyTpl+f6AtodQvgDI8io3jrfr+Z0LyQBPJJ2Btq8= -k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= -k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= -k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= -k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.31.3 h1:3r111pCjPsvnR98oLLxDMwAeM6OPGmPty6gSKaLTQes= -k8s.io/kubectl v0.31.3/go.mod h1:lhMECDCbJN8He12qcKqs2QfmVo9Pue30geovBVpH5fs= -k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno= -k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= -sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= -sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= -sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/cache/lru.go b/cache/lru.go index 4f2337b1..05621b88 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -24,10 +24,10 @@ import ( // node is a node in a doubly linked list // that is used to implement an LRU cache type node[T any] struct { - object T - key string - prev *node[T] - next *node[T] + value T + key string + prev *node[T] + next *node[T] } func (n *node[T]) addNext(node *node[T]) { @@ -38,7 +38,7 @@ func (n *node[T]) addPrev(node *node[T]) { n.prev = node } -// LRU is a thread-safe in-memory key/object store. +// LRU is a thread-safe in-memory key/value store. // All methods are safe for concurrent use. // All operations are O(1). The hash map lookup is O(1) and so is the doubly // linked list insertion/deletion. @@ -62,25 +62,20 @@ func (n *node[T]) addPrev(node *node[T]) { // │ │ // └───────────────────────────────────────────────────┘ // -// A function to extract the key from the object must be provided. // Use the NewLRU function to create a new cache that is ready to use. type LRU[T any] struct { cache map[string]*node[T] capacity int - // keyFunc is used to make the key for objects stored in and retrieved from items, and - // should be deterministic. - keyFunc KeyFunc[T] - metrics *cacheMetrics - labelsFunc GetLvsFunc[T] - head *node[T] - tail *node[T] - mu sync.RWMutex + metrics *cacheMetrics + head *node[T] + tail *node[T] + mu sync.RWMutex } var _ Store[any] = &LRU[any]{} -// NewLRU creates a new LRU cache with the given capacity and keyFunc. -func NewLRU[T any](capacity int, keyFunc KeyFunc[T], opts ...Options[T]) (*LRU[T], error) { +// NewLRU creates a new LRU cache with the given capacity. +func NewLRU[T any](capacity int, opts ...Options) (*LRU[T], error) { opt, err := makeOptions(opts...) if err != nil { return nil, fmt.Errorf("failed to apply options: %w", err) @@ -92,41 +87,33 @@ func NewLRU[T any](capacity int, keyFunc KeyFunc[T], opts ...Options[T]) (*LRU[T tail.addPrev(head) lru := &LRU[T]{ - cache: make(map[string]*node[T]), - keyFunc: keyFunc, - labelsFunc: opt.labelsFunc, - capacity: capacity, - head: head, - tail: tail, + cache: make(map[string]*node[T]), + capacity: capacity, + head: head, + tail: tail, } if opt.registerer != nil { - lru.metrics = newCacheMetrics(opt.registerer, opt.extraLabels...) + lru.metrics = newCacheMetrics(opt.registerer) } return lru, nil } // Set an item in the cache, existing index will be overwritten. -func (c *LRU[T]) Set(object T) error { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return &CacheError{Reason: ErrInvalidKey, Err: err} - } - +func (c *LRU[T]) Set(key string, value T) error { // if node is already in cache, return error c.mu.Lock() newNode, ok := c.cache[key] if ok { c.delete(newNode) - _ = c.add(&node[T]{key: key, object: object}) + _ = c.add(&node[T]{key: key, value: value}) c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) return nil } - evicted := c.add(&node[T]{key: key, object: object}) + evicted := c.add(&node[T]{key: key, value: value}) c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) if evicted { @@ -154,13 +141,7 @@ func (c *LRU[T]) add(node *node[T]) (evicted bool) { } // Delete removes a node from the list -func (c *LRU[T]) Delete(object T) error { - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return &CacheError{Reason: ErrInvalidKey, Err: err} - } - +func (c *LRU[T]) Delete(key string) error { // if node is head or tail, do nothing if key == c.head.key || key == c.tail.key { recordRequest(c.metrics, StatusSuccess) @@ -189,66 +170,25 @@ func (c *LRU[T]) delete(node *node[T]) { delete(c.cache, node.key) } -// Get returns the given object from the cache. -// If the object is not in the cache, it returns false. -func (c *LRU[T]) Get(object T) (item T, exists bool, err error) { - var res T - lvs := []string{} - if c.labelsFunc != nil { - lvs, err = c.labelsFunc(object, len(c.metrics.getExtraLabels())) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return res, false, &CacheError{Reason: ErrInvalidLabels, Err: err} - } - } - key, err := c.keyFunc(object) - if err != nil { - recordRequest(c.metrics, StatusFailure) - return item, false, &CacheError{Reason: ErrInvalidKey, Err: err} - } - - item, exists, err = c.get(key) - if err != nil { - return res, false, ErrInvalidKey - } - if !exists { - recordEvent(c.metrics, CacheEventTypeMiss, lvs...) - return res, false, nil - } - recordEvent(c.metrics, CacheEventTypeHit, lvs...) - return item, true, nil -} - -// GetByKey returns the object for the given key. -func (c *LRU[T]) GetByKey(key string) (T, bool, error) { - var res T - item, found, err := c.get(key) - if err != nil { - return res, false, err - } - if !found { - recordEvent(c.metrics, CacheEventTypeMiss) - return res, false, nil - } - - recordEvent(c.metrics, CacheEventTypeHit) - return item, true, nil -} - -func (c *LRU[T]) get(key string) (item T, exists bool, err error) { - var res T +// Get returns a pointer to an item in the cache for the given key. If no item +// is found, it's a nil pointer. +// The caller can record cache hit or miss based on the result with +// LRU.RecordCacheEvent(). +func (c *LRU[T]) Get(key string) (*T, error) { c.mu.Lock() node, ok := c.cache[key] if !ok { c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) - return res, false, nil + return nil, nil } c.delete(node) _ = c.add(node) c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) - return node.object, true, nil + // Copy the value to prevent writes to the cached item. + r := node.value + return &r, nil } // ListKeys returns a list of keys in the cache. @@ -288,3 +228,15 @@ func (c *LRU[T]) Resize(size int) (int, error) { recordRequest(c.metrics, StatusSuccess) return overflow, nil } + +// RecordCacheEvent records a cache event (cache_miss or cache_hit) with kind, +// name and namespace of the associated object being reconciled. +func (c *LRU[T]) RecordCacheEvent(event, kind, name, namespace string) { + recordCacheEvent(c.metrics, event, kind, name, namespace) +} + +// DeleteCacheEvent deletes the cache event (cache_miss or cache_hit) metric for +// the associated object being reconciled, given their kind, name and namespace. +func (c *LRU[T]) DeleteCacheEvent(event, kind, name, namespace string) { + deleteCacheEvent(c.metrics, event, kind, name, namespace) +} diff --git a/cache/lru_test.go b/cache/lru_test.go index e484171e..f89fba2b 100644 --- a/cache/lru_test.go +++ b/cache/lru_test.go @@ -22,195 +22,57 @@ import ( "sync" "testing" - "github.com/fluxcd/cli-utils/pkg/object" . "github.com/onsi/gomega" "github.com/prometheus/client_golang/prometheus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - kc "k8s.io/client-go/tools/cache" ) func Test_LRU(t *testing.T) { + type keyVal struct { + key string + value string + } testCases := []struct { name string - inputs []*metav1.PartialObjectMetadata - expectedCache map[string]*node[metav1.PartialObjectMetadata] + inputs []keyVal + expectedCache map[string]*node[string] }{ { name: "empty cache", - inputs: []*metav1.PartialObjectMetadata{}, - expectedCache: map[string]*node[metav1.PartialObjectMetadata]{}, + inputs: []keyVal{}, + expectedCache: map[string]*node[string]{}, }, { name: "add one node", - inputs: []*metav1.PartialObjectMetadata{ + inputs: []keyVal{ { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test", - }, + key: "test", + value: "test-token", }, }, - expectedCache: map[string]*node[metav1.PartialObjectMetadata]{ - "test-ns/test": { - object: metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test", - }, - }, - key: "test-ns/test", + expectedCache: map[string]*node[string]{ + "test": { + key: "test", + value: "test-token", }, }, }, { name: "add seven nodes", - inputs: []*metav1.PartialObjectMetadata{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test2", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test3", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test4", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test5", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test6", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test7", - }, - }, + inputs: []keyVal{ + {key: "test", value: "test-token"}, + {key: "test2", value: "test-token"}, + {key: "test3", value: "test-token"}, + {key: "test4", value: "test-token"}, + {key: "test5", value: "test-token"}, + {key: "test6", value: "test-token"}, + {key: "test7", value: "test-token"}, }, - expectedCache: map[string]*node[metav1.PartialObjectMetadata]{ - "test-ns/test3": { - object: metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test3", - }, - }, - key: "test-ns/test3", - }, - "test-ns/test4": { - object: metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test4", - }, - }, - key: "test-ns/test4", - }, - "test-ns/test5": { - object: metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test5", - }, - }, - key: "test-ns/test5", - }, - "test-ns/test6": { - object: metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test6", - }, - }, - key: "test-ns/test6", - }, - "test-ns/test7": { - object: metav1.PartialObjectMetadata{ - TypeMeta: metav1.TypeMeta{ - Kind: "TestObject", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test7", - }, - }, - key: "test-ns/test7", - }, + expectedCache: map[string]*node[string]{ + "test3": {key: "test3", value: "test-token"}, + "test4": {key: "test4", value: "test-token"}, + "test5": {key: "test5", value: "test-token"}, + "test6": {key: "test6", value: "test-token"}, + "test7": {key: "test7", value: "test-token"}, }, }, } @@ -218,11 +80,11 @@ func Test_LRU(t *testing.T) { for _, v := range testCases { t.Run(v.name, func(t *testing.T) { g := NewWithT(t) - cache, err := NewLRU(5, kc.MetaNamespaceKeyFunc, - WithMetricsRegisterer[any](prometheus.NewPedanticRegistry())) + cache, err := NewLRU[string](5, + WithMetricsRegisterer(prometheus.NewPedanticRegistry())) g.Expect(err).ToNot(HaveOccurred()) for _, input := range v.inputs { - err := cache.Set(input) + err := cache.Set(input.key, input.value) g.Expect(err).ToNot(HaveOccurred()) } @@ -237,38 +99,37 @@ func Test_LRU(t *testing.T) { } } -func Test_LRU_Add(t *testing.T) { +func Test_LRU_Set(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := NewLRU[IdentifiableObject](1, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg)) + cache, err := NewLRU[string](1, + WithMetricsRegisterer(reg)) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - err = cache.Set(obj) + key1 := "key1" + value1 := "val1" + err = cache.Set(key1, value1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) + g.Expect(cache.ListKeys()).To(ConsistOf(key1)) // try adding the same object again, it should overwrite the existing one - err = cache.Set(obj) + err = cache.Set(key1, value1) g.Expect(err).ToNot(HaveOccurred()) // add another object - obj.Name = "test2" - err = cache.Set(obj) + key2 := "key2" + value2 := "val2" + err = cache.Set(key2, value2) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test2_test-group_TestObject")) + g.Expect(cache.ListKeys()).To(ConsistOf(key2)) + + // Update the value of existing item. + value3 := "val3" + err = cache.Set(key2, value3) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(cache.ListKeys()).To(ConsistOf(key2)) + g.Expect(cache.cache[key2].value).To(Equal(value3)) // validate metrics validateMetrics(reg, ` @@ -277,88 +138,40 @@ func Test_LRU_Add(t *testing.T) { gotk_cache_evictions_total 1 # HELP gotk_cache_requests_total Total number of cache requests partioned by success or failure. # TYPE gotk_cache_requests_total counter - gotk_cache_requests_total{status="success"} 5 + gotk_cache_requests_total{status="success"} 7 # HELP gotk_cached_items Total number of items in the cache. # TYPE gotk_cached_items gauge gotk_cached_items 1 `, t) } -func Test_LRU_Update(t *testing.T) { - g := NewWithT(t) - reg := prometheus.NewPedanticRegistry() - cache, err := NewLRU[IdentifiableObject](1, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg)) - g.Expect(err).ToNot(HaveOccurred()) - - // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - err = cache.Set(obj) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) - - obj.Object = "test-token2" - err = cache.Set(obj) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(cache.ListKeys()).To(ConsistOf("test-ns_test_test-group_TestObject")) - g.Expect(cache.cache["test-ns_test_test-group_TestObject"].object.Object).To(Equal("test-token2")) - - // validate metrics - validateMetrics(reg, ` - # HELP gotk_cache_evictions_total Total number of cache evictions. - # TYPE gotk_cache_evictions_total counter - gotk_cache_evictions_total 0 - # HELP gotk_cache_requests_total Total number of cache requests partioned by success or failure. - # TYPE gotk_cache_requests_total counter - gotk_cache_requests_total{status="success"} 4 - # HELP gotk_cached_items Total number of items in the cache. - # TYPE gotk_cached_items gauge - gotk_cached_items 1 - `, t) -} - func Test_LRU_Get(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := NewLRU[IdentifiableObject](5, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg), - WithMetricsLabels[IdentifiableObject](IdentifiableObjectLabels, IdentifiableObjectLVSFunc)) + cache, err := NewLRU[string](5, + WithMetricsRegisterer(reg)) g.Expect(err).ToNot(HaveOccurred()) - // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } + // Reconciling object label values for cache event metric. + recObjKind := "TestObject" + recObjName := "test" + recObjNamespace := "test-ns" - _, found, err := cache.Get(obj) + // Add an object representing an expiring token + key1 := "key1" + value1 := "val1" + got, err := cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeFalse()) + g.Expect(got).To(BeNil()) + cache.RecordCacheEvent(CacheEventTypeMiss, recObjKind, recObjName, recObjNamespace) - err = cache.Set(obj) + err = cache.Set(key1, value1) g.Expect(err).ToNot(HaveOccurred()) - item, found, err := cache.Get(obj) + got, err = cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue()) - g.Expect(item).To(Equal(obj)) + g.Expect(*got).To(Equal(value1)) + cache.RecordCacheEvent(CacheEventTypeHit, recObjKind, recObjName, recObjNamespace) validateMetrics(reg, ` # HELP gotk_cache_events_total Total number of cache retrieval events for a Gitops Toolkit resource reconciliation. @@ -375,32 +188,37 @@ func Test_LRU_Get(t *testing.T) { # TYPE gotk_cached_items gauge gotk_cached_items 1 `, t) + + cache.DeleteCacheEvent(CacheEventTypeHit, recObjKind, recObjName, recObjNamespace) + cache.DeleteCacheEvent(CacheEventTypeMiss, recObjKind, recObjName, recObjNamespace) + + validateMetrics(reg, ` + # HELP gotk_cache_evictions_total Total number of cache evictions. + # TYPE gotk_cache_evictions_total counter + gotk_cache_evictions_total 0 + # HELP gotk_cache_requests_total Total number of cache requests partioned by success or failure. + # TYPE gotk_cache_requests_total counter + gotk_cache_requests_total{status="success"} 3 + # HELP gotk_cached_items Total number of items in the cache. + # TYPE gotk_cached_items gauge + gotk_cached_items 1 +`, t) } func Test_LRU_Delete(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := NewLRU[IdentifiableObject](5, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg)) + cache, err := NewLRU[string](5, + WithMetricsRegisterer(reg)) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: "test", - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - - err = cache.Set(obj) + key := "key1" + value := "val1" + err = cache.Set(key, value) g.Expect(err).ToNot(HaveOccurred()) - err = cache.Delete(obj) + err = cache.Delete(key) g.Expect(err).ToNot(HaveOccurred()) g.Expect(cache.ListKeys()).To(BeEmpty()) @@ -421,23 +239,13 @@ func Test_LRU_Resize(t *testing.T) { n := 100 g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := NewLRU[IdentifiableObject](n, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](reg)) + cache, err := NewLRU[string](n, + WithMetricsRegisterer(reg)) g.Expect(err).ToNot(HaveOccurred()) for i := range n { - obj := IdentifiableObject{ - ObjMetadata: object.ObjMetadata{ - Namespace: "test-ns", - Name: fmt.Sprintf("test-%d", i), - GroupKind: schema.GroupKind{ - Group: "test-group", - Kind: "TestObject", - }, - }, - Object: "test-token", - } - err = cache.Set(obj) + key := fmt.Sprintf("test-%d", i) + err = cache.Set(key, "test-token") g.Expect(err).ToNot(HaveOccurred()) } @@ -461,11 +269,15 @@ func TestLRU_Concurrent(t *testing.T) { ) g := NewWithT(t) // create a cache that can hold 10 items and have no cleanup - cache, err := NewLRU(10, IdentifiableObjectKeyFunc, - WithMetricsRegisterer[IdentifiableObject](prometheus.NewPedanticRegistry())) + cache, err := NewLRU[string](10, + WithMetricsRegisterer(prometheus.NewPedanticRegistry())) g.Expect(err).ToNot(HaveOccurred()) - objmap := createObjectMap(keysNum) + keymap := map[int]string{} + for i := 0; i < keysNum; i++ { + key := fmt.Sprintf("test-%d", i) + keymap[i] = key + } wg := sync.WaitGroup{} run := make(chan bool) @@ -476,12 +288,12 @@ func TestLRU_Concurrent(t *testing.T) { wg.Add(2) go func() { defer wg.Done() - _ = cache.Set(objmap[key]) + _ = cache.Set(keymap[key], "test-token") }() go func() { defer wg.Done() <-run - _, _, _ = cache.Get(objmap[key]) + _, _ = cache.Get(keymap[key]) }() } close(run) @@ -489,12 +301,26 @@ func TestLRU_Concurrent(t *testing.T) { keys, err := cache.ListKeys() g.Expect(err).ToNot(HaveOccurred()) - g.Expect(len(keys)).To(Equal(len(objmap))) + g.Expect(len(keys)).To(Equal(len(keymap))) - for _, obj := range objmap { - val, found, err := cache.Get(obj) + for _, key := range keymap { + val, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(found).To(BeTrue(), "object %s not found", obj.Name) - g.Expect(val).To(Equal(obj)) + g.Expect(val).ToNot(BeNil(), "object %s not found", key) + g.Expect(*val).To(Equal("test-token")) } } + +func TestLRU_int(t *testing.T) { + g := NewWithT(t) + + cache, err := NewLRU[int](3, WithMetricsRegisterer(prometheus.NewPedanticRegistry())) + g.Expect(err).ToNot(HaveOccurred()) + + key := "key1" + g.Expect(cache.Set(key, 4)).To(Succeed()) + + got, err := cache.Get(key) + g.Expect(err).To(Succeed()) + g.Expect(*got).To(Equal(4)) +} diff --git a/cache/metrics.go b/cache/metrics.go index c6dd29ea..4750a317 100644 --- a/cache/metrics.go +++ b/cache/metrics.go @@ -17,8 +17,6 @@ limitations under the License. package cache import ( - "fmt" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) @@ -40,12 +38,11 @@ type cacheMetrics struct { cacheItemsGauge prometheus.Gauge cacheRequestsCounter *prometheus.CounterVec cacheEvictionCounter prometheus.Counter - extraLabels []string } // newcacheMetrics returns a new cacheMetrics. -func newCacheMetrics(reg prometheus.Registerer, extraLabels ...string) *cacheMetrics { - labels := append([]string{"event_type"}, extraLabels...) +func newCacheMetrics(reg prometheus.Registerer) *cacheMetrics { + labels := []string{"event_type", "kind", "name", "namespace"} return &cacheMetrics{ cacheEventsCounter: promauto.With(reg).NewCounterVec( prometheus.CounterOpts{ @@ -73,14 +70,9 @@ func newCacheMetrics(reg prometheus.Registerer, extraLabels ...string) *cacheMet Help: "Total number of cache evictions.", }, ), - extraLabels: extraLabels, } } -func (m *cacheMetrics) getExtraLabels() []string { - return m.extraLabels -} - // collectors returns the metrics.Collector objects for the cacheMetrics. func (m *cacheMetrics) collectors() []prometheus.Collector { return []prometheus.Collector{ @@ -151,34 +143,20 @@ func recordDecrement(metrics *cacheMetrics) { } } -func recordEvent(metrics *cacheMetrics, event string, lvs ...string) { +func recordItemIncrement(metrics *cacheMetrics) { if metrics != nil { - metrics.incCacheEvents(event, lvs...) + metrics.incCacheItems() } } -func recordItemIncrement(metrics *cacheMetrics) { +func recordCacheEvent(metrics *cacheMetrics, event, kind, name, namespace string) { if metrics != nil { - metrics.incCacheItems() + metrics.incCacheEvents(event, kind, name, namespace) } } -// IdentifiableObjectLabels are the labels for an IdentifiableObject. -var IdentifiableObjectLabels []string = []string{"name", "namespace", "kind"} - -// GetLvsFunc is a function that returns the label's values for a metric. -type GetLvsFunc[T any] func(obj T, cardinality int) ([]string, error) - -// IdentifiableObjectLVSFunc returns the label's values for a metric for an IdentifiableObject. -func IdentifiableObjectLVSFunc[T any](object T, cardinality int) ([]string, error) { - n, ok := any(object).(IdentifiableObject) - if !ok { - return nil, fmt.Errorf("object is not an IdentifiableObject") - } - lvs := []string{n.Name, n.Namespace, n.GroupKind.Kind} - if len(lvs) != cardinality { - return nil, fmt.Errorf("expected cardinality %d, got %d", cardinality, len(lvs)) +func deleteCacheEvent(metrics *cacheMetrics, event, kind, name, namespace string) { + if metrics != nil { + metrics.deleteCacheEvent(event, kind, name, namespace) } - - return []string{n.Name, n.Namespace, n.GroupKind.Kind}, nil } diff --git a/cache/metrics_test.go b/cache/metrics_test.go index 5a2d90b8..c2291687 100644 --- a/cache/metrics_test.go +++ b/cache/metrics_test.go @@ -28,12 +28,12 @@ import ( func TestCacheMetrics(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - m := newCacheMetrics(reg, IdentifiableObjectLabels...) + m := newCacheMetrics(reg) g.Expect(m).ToNot(BeNil()) // CounterVec is a collection of counters and is not exported until it has counters in it. - m.incCacheEvents(CacheEventTypeHit, []string{"test", "test-ns", "TestObject"}...) - m.incCacheEvents(CacheEventTypeMiss, []string{"test", "test-ns", "TestObject"}...) + m.incCacheEvents(CacheEventTypeHit, []string{"TestObject", "test", "test-ns"}...) + m.incCacheEvents(CacheEventTypeMiss, []string{"TestObject", "test", "test-ns"}...) m.incCacheRequests("success") m.incCacheRequests("failure") diff --git a/cache/store.go b/cache/store.go index ba80e232..464cba3e 100644 --- a/cache/store.go +++ b/cache/store.go @@ -17,122 +17,52 @@ limitations under the License. package cache import ( - "fmt" "time" - "github.com/fluxcd/cli-utils/pkg/object" "github.com/prometheus/client_golang/prometheus" ) // Store is an interface for a cache store. -// It is a generic version of the Kubernetes client-go cache.Store interface. -// See https://pkg.go.dev/k8s.io/client-go/tools/cache#Store -// The implementation should know how to extract a key from an object. type Store[T any] interface { - // Set adds an object to the store. - // It will overwrite the item if it already exists. - Set(object T) error - // Delete deletes an object from the store. - Delete(object T) error - // ListKeys returns a list of keys in the store. - ListKeys() ([]string, error) - // Get returns the object stored in the store. - Get(object T) (item T, exists bool, err error) - // GetByKey returns the object stored in the store by key. - GetByKey(key string) (item T, exists bool, err error) - // Resize resizes the store and returns the number of items removed. - Resize(int) (int, error) + // Set adds an item to the store for the given key. + Set(key string, value T) error + // Get returns an item stored in the store for the given key. + Get(key string) (*T, error) + // Delete deletes an item in the store for the given key. + Delete(key string) error } // Expirable is an interface for a cache store that supports expiration. type Expirable[T any] interface { Store[T] - // SetExpiration sets the expiration time for the object. - SetExpiration(object T, expiresAt time.Time) error - // GetExpiration returns the expiration time for the object in unix time. - GetExpiration(object T) (time.Time, error) - // HasExpired returns true if the object has expired. - HasExpired(object T) (bool, error) + // SetExpiration sets the expiration time for a cached item. + SetExpiration(key string, expiresAt time.Time) error + // GetExpiration returns the expiration time of an item. + GetExpiration(key string) (time.Time, error) + // HasExpired returns if an item has expired. + HasExpired(key string) (bool, error) } -type storeOptions[T any] struct { - interval time.Duration - registerer prometheus.Registerer - extraLabels []string - labelsFunc GetLvsFunc[T] +type storeOptions struct { + interval time.Duration + registerer prometheus.Registerer } // Options is a function that sets the store options. -type Options[T any] func(*storeOptions[T]) error - -// WithMetricsLabels sets the extra labels for the cache metrics. -func WithMetricsLabels[T any](labels []string, f GetLvsFunc[T]) Options[T] { - return func(o *storeOptions[T]) error { - if labels != nil && f == nil { - return fmt.Errorf("labelsFunc must be set if labels are provided") - } - o.extraLabels = labels - o.labelsFunc = f - return nil - } -} +type Options func(*storeOptions) error // WithCleanupInterval sets the interval for the cache cleanup. -func WithCleanupInterval[T any](interval time.Duration) Options[T] { - return func(o *storeOptions[T]) error { +func WithCleanupInterval(interval time.Duration) Options { + return func(o *storeOptions) error { o.interval = interval return nil } } // WithMetricsRegisterer sets the Prometheus registerer for the cache metrics. -func WithMetricsRegisterer[T any](r prometheus.Registerer) Options[T] { - return func(o *storeOptions[T]) error { +func WithMetricsRegisterer(r prometheus.Registerer) Options { + return func(o *storeOptions) error { o.registerer = r return nil } } - -// KeyFunc knows how to make a key from an object. Implementations should be deterministic. -type KeyFunc[T any] func(object T) (string, error) - -// IdentifiableObject is a wrapper for an object with its identifying metadata. -type IdentifiableObject struct { - object.ObjMetadata - // Object is the object that is being stored. - Object any -} - -// ExplicitKey can be passed to IdentifiableObjectKeyFunc if you have the key for -// the objectec but not the object itself. -type ExplicitKey string - -// IdentifiableObjectKeyFunc is a convenient default KeyFunc which knows how to make -// keys from IdentifiableObject objects. -func IdentifiableObjectKeyFunc[T any](object T) (string, error) { - if key, ok := any(object).(ExplicitKey); ok { - return string(key), nil - } - n, ok := any(object).(IdentifiableObject) - if !ok { - return "", fmt.Errorf("object has no meta: %v", object) - } - return n.String(), nil -} - -// StoreObject is a wrapper for an object with its identifying key. -// It is used to store objects in a Store. -// This helper is useful when the object does not have metadata to extract the key from. -// The supplied key can be retrieved with the StoreObjectKeyFunc. -// When the object has metadata, use IdentifiableObject instead if possible. -type StoreObject[T any] struct { - // Object is the object that is being stored. - Object T - // Key is the key for the object. - Key string -} - -// StoreObjectKeyFunc returns the key for a StoreObject. -func StoreObjectKeyFunc[T any](object StoreObject[T]) (string, error) { - return object.Key, nil -} From 061b9acc5363c1e84ebe18a6fef1de851185c33c Mon Sep 17 00:00:00 2001 From: Sunny Date: Mon, 28 Oct 2024 18:57:44 +0000 Subject: [PATCH 2/4] cache: Allow setting cache metrics prefix Custom prefix allows using multiple instances of the cache in an application with unique metrics. Signed-off-by: Sunny --- cache/cache.go | 2 +- cache/cache_test.go | 4 +++- cache/lru.go | 2 +- cache/lru_test.go | 9 ++++++--- cache/metrics.go | 12 +++++++----- cache/metrics_test.go | 2 +- cache/store.go | 13 +++++++++++-- 7 files changed, 30 insertions(+), 14 deletions(-) diff --git a/cache/cache.go b/cache/cache.go index f5934f80..d42ba127 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -85,7 +85,7 @@ func New[T any](capacity int, opts ...Options) (*Cache[T], error) { } if opt.registerer != nil { - c.metrics = newCacheMetrics(opt.registerer) + c.metrics = newCacheMetrics(opt.metricsPrefix, opt.registerer) } C := &Cache[T]{cache: c} diff --git a/cache/cache_test.go b/cache/cache_test.go index e1474dfc..5d5d3c6c 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -149,6 +149,7 @@ func Test_Cache_Set(t *testing.T) { reg := prometheus.NewPedanticRegistry() cache, err := New[string](1, WithMetricsRegisterer(reg), + WithMetricsPrefix("gotk_"), WithCleanupInterval(10*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) @@ -202,7 +203,7 @@ func Test_Cache_Set(t *testing.T) { func Test_Cache_Get(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - cache, err := New[string](5, WithMetricsRegisterer(reg)) + cache, err := New[string](5, WithMetricsRegisterer(reg), WithMetricsPrefix("gotk_")) g.Expect(err).ToNot(HaveOccurred()) // Reconciling object label values for cache event metric. @@ -265,6 +266,7 @@ func Test_Cache_Delete(t *testing.T) { reg := prometheus.NewPedanticRegistry() cache, err := New[string](5, WithMetricsRegisterer(reg), + WithMetricsPrefix("gotk_"), WithCleanupInterval(1*time.Millisecond)) g.Expect(err).ToNot(HaveOccurred()) diff --git a/cache/lru.go b/cache/lru.go index 05621b88..561eaf55 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -94,7 +94,7 @@ func NewLRU[T any](capacity int, opts ...Options) (*LRU[T], error) { } if opt.registerer != nil { - lru.metrics = newCacheMetrics(opt.registerer) + lru.metrics = newCacheMetrics(opt.metricsPrefix, opt.registerer) } return lru, nil diff --git a/cache/lru_test.go b/cache/lru_test.go index f89fba2b..57b93c63 100644 --- a/cache/lru_test.go +++ b/cache/lru_test.go @@ -103,7 +103,8 @@ func Test_LRU_Set(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() cache, err := NewLRU[string](1, - WithMetricsRegisterer(reg)) + WithMetricsRegisterer(reg), + WithMetricsPrefix("gotk_")) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token @@ -149,7 +150,8 @@ func Test_LRU_Get(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() cache, err := NewLRU[string](5, - WithMetricsRegisterer(reg)) + WithMetricsRegisterer(reg), + WithMetricsPrefix("gotk_")) g.Expect(err).ToNot(HaveOccurred()) // Reconciling object label values for cache event metric. @@ -209,7 +211,8 @@ func Test_LRU_Delete(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() cache, err := NewLRU[string](5, - WithMetricsRegisterer(reg)) + WithMetricsRegisterer(reg), + WithMetricsPrefix("gotk_")) g.Expect(err).ToNot(HaveOccurred()) // Add an object representing an expiring token diff --git a/cache/metrics.go b/cache/metrics.go index 4750a317..6ea0cfe1 100644 --- a/cache/metrics.go +++ b/cache/metrics.go @@ -17,6 +17,8 @@ limitations under the License. package cache import ( + "fmt" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) @@ -41,32 +43,32 @@ type cacheMetrics struct { } // newcacheMetrics returns a new cacheMetrics. -func newCacheMetrics(reg prometheus.Registerer) *cacheMetrics { +func newCacheMetrics(prefix string, reg prometheus.Registerer) *cacheMetrics { labels := []string{"event_type", "kind", "name", "namespace"} return &cacheMetrics{ cacheEventsCounter: promauto.With(reg).NewCounterVec( prometheus.CounterOpts{ - Name: "gotk_cache_events_total", + Name: fmt.Sprintf("%scache_events_total", prefix), Help: "Total number of cache retrieval events for a Gitops Toolkit resource reconciliation.", }, labels, ), cacheItemsGauge: promauto.With(reg).NewGauge( prometheus.GaugeOpts{ - Name: "gotk_cached_items", + Name: fmt.Sprintf("%scached_items", prefix), Help: "Total number of items in the cache.", }, ), cacheRequestsCounter: promauto.With(reg).NewCounterVec( prometheus.CounterOpts{ - Name: "gotk_cache_requests_total", + Name: fmt.Sprintf("%scache_requests_total", prefix), Help: "Total number of cache requests partioned by success or failure.", }, []string{"status"}, ), cacheEvictionCounter: promauto.With(reg).NewCounter( prometheus.CounterOpts{ - Name: "gotk_cache_evictions_total", + Name: fmt.Sprintf("%scache_evictions_total", prefix), Help: "Total number of cache evictions.", }, ), diff --git a/cache/metrics_test.go b/cache/metrics_test.go index c2291687..76a4a5ba 100644 --- a/cache/metrics_test.go +++ b/cache/metrics_test.go @@ -28,7 +28,7 @@ import ( func TestCacheMetrics(t *testing.T) { g := NewWithT(t) reg := prometheus.NewPedanticRegistry() - m := newCacheMetrics(reg) + m := newCacheMetrics("gotk_", reg) g.Expect(m).ToNot(BeNil()) // CounterVec is a collection of counters and is not exported until it has counters in it. diff --git a/cache/store.go b/cache/store.go index 464cba3e..d0dce133 100644 --- a/cache/store.go +++ b/cache/store.go @@ -44,8 +44,9 @@ type Expirable[T any] interface { } type storeOptions struct { - interval time.Duration - registerer prometheus.Registerer + interval time.Duration + registerer prometheus.Registerer + metricsPrefix string } // Options is a function that sets the store options. @@ -66,3 +67,11 @@ func WithMetricsRegisterer(r prometheus.Registerer) Options { return nil } } + +// WithMetricsPrefix sets the metrics prefix for the cache metrics. +func WithMetricsPrefix(prefix string) Options { + return func(o *storeOptions) error { + o.metricsPrefix = prefix + return nil + } +} From 72d6f8c2228e53caaa00ac7d2a6cb026d62289fb Mon Sep 17 00:00:00 2001 From: Sunny Date: Wed, 27 Nov 2024 15:59:39 +0000 Subject: [PATCH 3/4] oci: Remove cache from auth and int tests code OCI auth token caching will be done in the OCI client. Remove the cache from auth package and its use in the integration tests. Since the cache related changes introduced the auth token expiry time to be returned from the auth provider logins, a new function LoginWithExpiry() is introduced which returns the expiry time. The original Login() remains as it is for backwards compatibility. A higher level client can use LoginWithExpiry() to obtain the TTL of the auth token to use with the cache. Signed-off-by: Sunny --- oci/auth/login/cache.go | 44 -------- oci/auth/login/login.go | 94 +++------------- oci/auth/login/login_test.go | 147 -------------------------- oci/go.mod | 45 +------- oci/go.sum | 145 ------------------------- oci/tests/integration/go.mod | 14 +-- oci/tests/integration/go.sum | 56 ---------- oci/tests/integration/testapp/main.go | 8 +- 8 files changed, 20 insertions(+), 533 deletions(-) delete mode 100644 oci/auth/login/cache.go diff --git a/oci/auth/login/cache.go b/oci/auth/login/cache.go deleted file mode 100644 index 13180ff6..00000000 --- a/oci/auth/login/cache.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2024 The Flux authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package login - -import ( - "time" - - "github.com/google/go-containerregistry/pkg/authn" - - "github.com/fluxcd/pkg/cache" -) - -func cacheObject[T authn.Authenticator](store cache.Expirable[cache.StoreObject[T]], auth T, key string, expiresAt time.Time) error { - obj := cache.StoreObject[T]{ - Object: auth, - Key: key, - } - - err := store.Set(obj) - if err != nil { - return err - } - - return store.SetExpiration(obj, expiresAt) -} - -func getObjectFromCache[T authn.Authenticator](cache cache.Expirable[cache.StoreObject[T]], key string) (T, bool, error) { - val, exists, err := cache.GetByKey(key) - return val.Object, exists, err -} diff --git a/oci/auth/login/login.go b/oci/auth/login/login.go index 9ffaef94..60f31968 100644 --- a/oci/auth/login/login.go +++ b/oci/auth/login/login.go @@ -21,12 +21,12 @@ import ( "fmt" "net/url" "strings" + "time" "github.com/go-logr/logr" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" - "github.com/fluxcd/pkg/cache" "github.com/fluxcd/pkg/oci" "github.com/fluxcd/pkg/oci/auth/aws" "github.com/fluxcd/pkg/oci/auth/azure" @@ -70,8 +70,6 @@ type ProviderOptions struct { // AzureAutoLogin enables automatic attempt to get credentials for images in // ACR. AzureAutoLogin bool - // Cache is a cache for storing auth configurations. - Cache cache.Expirable[cache.StoreObject[authn.Authenticator]] } // Manager is a login manager for various registry providers. @@ -141,65 +139,24 @@ func (m *Manager) WithACRClient(c *azure.Client) *Manager { // Login performs authentication against a registry and returns the Authenticator. // For generic registry provider, it is no-op. func (m *Manager) Login(ctx context.Context, url string, ref name.Reference, opts ProviderOptions) (authn.Authenticator, error) { - provider := ImageRegistryProvider(url, ref) - var ( - key string - err error - ) - if opts.Cache != nil { - key, err = m.keyFromURL(url, provider) - if err != nil { - logr.FromContextOrDiscard(ctx).Error(err, "failed to get cache key") - } else { - auth, exists, err := getObjectFromCache(opts.Cache, key) - if err != nil { - logr.FromContextOrDiscard(ctx).Error(err, "failed to get auth object from cache") - } - if exists { - return auth, nil - } - } - } + auth, _, err := m.LoginWithExpiry(ctx, url, ref, opts) + return auth, err +} +// LoginWithExpiry performs authentication against a registry and returns the +// Authenticator along with the auth expiry time. +// For generic registry provider, it is no-op. +func (m *Manager) LoginWithExpiry(ctx context.Context, url string, ref name.Reference, opts ProviderOptions) (authn.Authenticator, time.Time, error) { + provider := ImageRegistryProvider(url, ref) switch provider { case oci.ProviderAWS: - auth, expiresAt, err := m.ecr.LoginWithExpiry(ctx, opts.AwsAutoLogin, url) - if err != nil { - return nil, err - } - if opts.Cache != nil { - err := cacheObject(opts.Cache, auth, key, expiresAt) - if err != nil { - logr.FromContextOrDiscard(ctx).Error(err, "failed to cache auth object") - } - } - return auth, nil + return m.ecr.LoginWithExpiry(ctx, opts.AwsAutoLogin, url) case oci.ProviderGCP: - auth, expiresAt, err := m.gcr.LoginWithExpiry(ctx, opts.GcpAutoLogin, url, ref) - if err != nil { - return nil, err - } - if opts.Cache != nil { - err := cacheObject(opts.Cache, auth, key, expiresAt) - if err != nil { - logr.FromContextOrDiscard(ctx).Error(err, "failed to cache auth object") - } - } - return auth, nil + return m.gcr.LoginWithExpiry(ctx, opts.GcpAutoLogin, url, ref) case oci.ProviderAzure: - auth, expiresAt, err := m.acr.LoginWithExpiry(ctx, opts.AzureAutoLogin, url, ref) - if err != nil { - return nil, err - } - if opts.Cache != nil { - err := cacheObject(opts.Cache, auth, key, expiresAt) - if err != nil { - logr.FromContextOrDiscard(ctx).Error(err, "failed to cache auth object") - } - } - return auth, nil + return m.acr.LoginWithExpiry(ctx, opts.AzureAutoLogin, url, ref) } - return nil, nil + return nil, time.Time{}, nil } // OIDCLogin attempts to get an Authenticator for the provided URL endpoint. @@ -236,28 +193,3 @@ func (m *Manager) OIDCLogin(ctx context.Context, registryURL string, opts Provid } return nil, nil } - -// keyFromURL returns a key for the cache based on the URL and provider. -// Use this when you don't want to cache the full URL, -// but instead want to cache based on the provider secific way of identifying -// the authentication principal, i.e. the Domain for AWS and Azure, Project for GCP. -func (m *Manager) keyFromURL(ref string, provider oci.Provider) (string, error) { - if !strings.Contains(ref, "://") { - ref = fmt.Sprintf("//%s", ref) - } - u, err := url.Parse(ref) - if err != nil { - return "", err - } - switch provider { - case oci.ProviderAWS, oci.ProviderAzure: - return u.Host, nil - case oci.ProviderGCP: - paths := strings.Split(u.Path, "/") - if len(paths) > 1 { - return fmt.Sprintf("%s/%s", u.Host, paths[1]), nil - } - return u.Host, nil - } - return "", nil -} diff --git a/oci/auth/login/login_test.go b/oci/auth/login/login_test.go index 2aebdfab..b23be1dc 100644 --- a/oci/auth/login/login_test.go +++ b/oci/auth/login/login_test.go @@ -18,20 +18,16 @@ package login import ( "context" - "fmt" "net/http" "net/http/httptest" "strings" "testing" - "time" awssdk "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/credentials" - "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" . "github.com/onsi/gomega" - "github.com/fluxcd/pkg/cache" "github.com/fluxcd/pkg/oci" "github.com/fluxcd/pkg/oci/auth/aws" "github.com/fluxcd/pkg/oci/auth/azure" @@ -165,146 +161,3 @@ func TestLogin(t *testing.T) { }) } } - -func TestLogin_WithCache(t *testing.T) { - timestamp := time.Now().Add(10 * time.Second).Unix() - tests := []struct { - name string - responseBody string - statusCode int - providerOpts ProviderOptions - beforeFunc func(serverURL string, mgr *Manager, image *string) - wantErr bool - }{ - { - name: "ecr", - responseBody: fmt.Sprintf(`{"authorizationData": [{"authorizationToken": "c29tZS1rZXk6c29tZS1zZWNyZXQ=","expiresAt": %d}]}`, timestamp), - providerOpts: ProviderOptions{AwsAutoLogin: true}, - beforeFunc: func(serverURL string, mgr *Manager, image *string) { - // Create ECR client and configure the manager. - ecrClient := aws.NewClient() - cfg := awssdk.NewConfig() - cfg.EndpointResolverWithOptions = awssdk.EndpointResolverWithOptionsFunc( - func(service, region string, options ...interface{}) (awssdk.Endpoint, error) { - return awssdk.Endpoint{URL: serverURL}, nil - }) - cfg.Credentials = credentials.NewStaticCredentialsProvider("x", "y", "z") - ecrClient.WithConfig(cfg) - - mgr.WithECRClient(ecrClient) - - *image = "012345678901.dkr.ecr.us-east-1.amazonaws.com/foo:v1" - }, - }, - { - name: "gcr", - responseBody: `{"access_token": "some-token","expires_in": 10, "token_type": "foo"}`, - providerOpts: ProviderOptions{GcpAutoLogin: true}, - beforeFunc: func(serverURL string, mgr *Manager, image *string) { - // Create GCR client and configure the manager. - gcrClient := gcp.NewClient().WithTokenURL(serverURL) - mgr.WithGCRClient(gcrClient) - - *image = "gcr.io/foo/bar:v1" - }, - }, - { - name: "acr", - responseBody: `{"refresh_token": "bbbbb"}`, - providerOpts: ProviderOptions{AzureAutoLogin: true}, - beforeFunc: func(serverURL string, mgr *Manager, image *string) { - acrClient := azure.NewClient().WithTokenCredential(&azure.FakeTokenCredential{Token: "foo"}).WithScheme("http") - mgr.WithACRClient(acrClient) - - *image = "foo.azurecr.io/bar:v1" - }, - // NOTE: This fails because the azure exchanger uses the image host - // to exchange token which can't be modified here without - // interfering image name based categorization of the login - // provider, that's actually being tested here. This is tested in - // detail in the azure package. - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - // Create test server. - handler := func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte(tt.responseBody)) - } - srv := httptest.NewServer(http.HandlerFunc(handler)) - t.Cleanup(func() { - srv.Close() - }) - - mgr := NewManager() - var image string - - if tt.beforeFunc != nil { - tt.beforeFunc(srv.URL, mgr, &image) - } - - ref, err := name.ParseReference(image) - g.Expect(err).ToNot(HaveOccurred()) - - cache, err := cache.New(5, cache.StoreObjectKeyFunc, - cache.WithCleanupInterval[cache.StoreObject[authn.Authenticator]](1*time.Second)) - g.Expect(err).ToNot(HaveOccurred()) - - tt.providerOpts.Cache = cache - - _, err = mgr.Login(context.TODO(), image, ref, tt.providerOpts) - if tt.wantErr { - g.Expect(err).To(HaveOccurred()) - } else { - key, err := mgr.keyFromURL(image, ImageRegistryProvider(image, ref)) - g.Expect(err).ToNot(HaveOccurred()) - auth, exists, err := getObjectFromCache(cache, key) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(exists).To(BeTrue()) - g.Expect(auth).ToNot(BeNil()) - obj, _, err := cache.GetByKey(key) - g.Expect(err).ToNot(HaveOccurred()) - expiration, err := cache.GetExpiration(obj) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(expiration).ToNot(BeZero()) - g.Expect(expiration).To(BeTemporally("~", time.Unix(timestamp, 0), 1*time.Second)) - } - }) - } -} - -func Test_keyFromURL(t *testing.T) { - tests := []struct { - name string - image string - want string - }{ - {"gcr", "gcr.io/foo/bar:v1", "gcr.io/foo"}, - {"ecr", "012345678901.dkr.ecr.us-east-1.amazonaws.com/foo:v1", "012345678901.dkr.ecr.us-east-1.amazonaws.com"}, - {"ecr-root", "012345678901.dkr.ecr.us-east-1.amazonaws.com", "012345678901.dkr.ecr.us-east-1.amazonaws.com"}, - {"ecr-root with slash", "012345678901.dkr.ecr.us-east-1.amazonaws.com/", "012345678901.dkr.ecr.us-east-1.amazonaws.com"}, - {"gcr", "gcr.io/foo/bar:v1", "gcr.io/foo"}, - {"gcr-root", "gcr.io", "gcr.io"}, - {"acr", "foo.azurecr.io/bar:v1", "foo.azurecr.io"}, - {"acr-root", "foo.azurecr.io", "foo.azurecr.io"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - // Trim suffix to allow parsing it as reference without modifying - // the given image address. - ref, err := name.ParseReference(strings.TrimSuffix(tt.image, "/")) - g.Expect(err).ToNot(HaveOccurred()) - key, err := NewManager().keyFromURL(tt.image, ImageRegistryProvider(tt.image, ref)) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(key).To(Equal(tt.want)) - }) - } -} diff --git a/oci/go.mod b/oci/go.mod index 0ea3af34..3f8f90b0 100644 --- a/oci/go.mod +++ b/oci/go.mod @@ -3,7 +3,6 @@ module github.com/fluxcd/pkg/oci go 1.22.7 replace ( - github.com/fluxcd/pkg/cache => ../cache github.com/fluxcd/pkg/sourceignore => ../sourceignore github.com/fluxcd/pkg/tar => ../tar github.com/fluxcd/pkg/version => ../version @@ -18,7 +17,6 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.17.32 github.com/aws/aws-sdk-go-v2/service/ecr v1.33.0 github.com/distribution/distribution/v3 v3.0.0-beta.1 - github.com/fluxcd/pkg/cache v0.0.4 github.com/fluxcd/pkg/sourceignore v0.8.1 github.com/fluxcd/pkg/tar v0.8.1 github.com/fluxcd/pkg/version v0.4.1 @@ -42,7 +40,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect github.com/aws/smithy-go v1.20.4 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/bshuster-repo/logrus-logstash-hook v1.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -57,49 +54,32 @@ require ( github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-metrics v0.0.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fluxcd/cli-utils v0.36.0-flux.10 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-errors/errors v1.5.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-git/go-git/v5 v5.12.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.4 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect - github.com/imdario/mergo v0.3.15 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/onsi/ginkgo/v2 v2.22.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -109,9 +89,8 @@ require ( github.com/redis/go-redis/v9 v9.1.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.10.0 // indirect github.com/vbatts/tar-split v0.11.3 // indirect - github.com/x448/float16 v0.8.4 // indirect - github.com/xlab/treeprint v1.2.0 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.53.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.53.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect @@ -135,31 +114,15 @@ require ( go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.29.0 // indirect golang.org/x/net v0.31.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.27.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.31.3 // indirect - k8s.io/apimachinery v0.31.3 // indirect - k8s.io/cli-runtime v0.31.3 // indirect - k8s.io/client-go v0.31.3 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.18.0 // indirect - sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/oci/go.sum b/oci/go.sum index d6804816..dbf2d797 100644 --- a/oci/go.sum +++ b/oci/go.sum @@ -4,13 +4,9 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -47,8 +43,6 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= @@ -61,15 +55,12 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.3.2 h1:QhZu5AxQ+o1XZH0Ye05YzvJ0kAdK6VQc0z9NNMek7gc= github.com/cyphar/filepath-securejoin v0.3.2/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -92,18 +83,8 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/cli-utils v0.36.0-flux.10 h1:kgoj1HP7KBFfIG9CHLFHpA2kCPNlfzCpbscCaAOSClE= -github.com/fluxcd/cli-utils v0.36.0-flux.10/go.mod h1:eWf+UVZmm51EmNmeGkdplVLVsFU4jETfCjoHZq7nUp4= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= -github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= @@ -118,62 +99,36 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -182,55 +137,29 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= @@ -239,8 +168,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -276,11 +203,7 @@ github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0Niuqvtf github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -293,8 +216,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -306,12 +227,6 @@ github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/contrib/bridges/prometheus v0.53.0 h1:BdkKDtcrHThgjcEia1737OUuFdP6xzBKAMx2sNZCkvE= go.opentelemetry.io/contrib/bridges/prometheus v0.53.0/go.mod h1:ZkhVxcJgeXlL/lVyT/vxNHVFiSG5qOaDwYaSgD8IfZo= go.opentelemetry.io/contrib/exporters/autoexport v0.53.0 h1:13K+tY7E8GJInkrvRiPAhC0gi/7vKjzDNhtmCf+QXG8= @@ -358,58 +273,30 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= @@ -422,10 +309,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -437,31 +320,3 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= -k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= -k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/cli-runtime v0.31.3 h1:fEQD9Xokir78y7pVK/fCJN090/iYNrLHpFbGU4ul9TI= -k8s.io/cli-runtime v0.31.3/go.mod h1:Q2jkyTpl+f6AtodQvgDI8io3jrfr+Z0LyQBPJJ2Btq8= -k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= -k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= -k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= -k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.31.3 h1:3r111pCjPsvnR98oLLxDMwAeM6OPGmPty6gSKaLTQes= -k8s.io/kubectl v0.31.3/go.mod h1:lhMECDCbJN8He12qcKqs2QfmVo9Pue30geovBVpH5fs= -k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno= -k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= -sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= -sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= -sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/oci/tests/integration/go.mod b/oci/tests/integration/go.mod index 3f8bc9d6..bff62839 100644 --- a/oci/tests/integration/go.mod +++ b/oci/tests/integration/go.mod @@ -4,7 +4,6 @@ go 1.22.7 replace ( github.com/fluxcd/pkg/auth => ../../../auth - github.com/fluxcd/pkg/cache => ../../../cache github.com/fluxcd/pkg/git => ../../../git github.com/fluxcd/pkg/git/gogit => ../../../git/gogit github.com/fluxcd/pkg/oci => ../../ @@ -12,7 +11,6 @@ replace ( require ( github.com/fluxcd/pkg/auth v0.0.1 - github.com/fluxcd/pkg/cache v0.0.4 github.com/fluxcd/pkg/git v0.21.0 github.com/fluxcd/pkg/git/gogit v0.19.0 github.com/fluxcd/pkg/oci v0.40.0 @@ -54,7 +52,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect github.com/aws/smithy-go v1.20.4 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/bradleyfalzon/ghinstallation/v2 v2.12.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.5.0 // indirect @@ -66,12 +63,11 @@ require ( github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/fluxcd/cli-utils v0.36.0-flux.10 // indirect github.com/fluxcd/pkg/ssh v0.14.1 // indirect github.com/fluxcd/pkg/version v0.4.1 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-errors/errors v1.5.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -89,7 +85,7 @@ require ( github.com/google/go-github/v66 v66.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -107,7 +103,6 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect @@ -125,7 +120,6 @@ require ( github.com/vbatts/tar-split v0.11.3 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - github.com/xlab/treeprint v1.2.0 // indirect github.com/zclconf/go-cty v1.14.4 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect @@ -142,20 +136,16 @@ require ( golang.org/x/tools v0.28.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.31.3 // indirect - k8s.io/cli-runtime v0.31.3 // indirect k8s.io/client-go v0.31.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.18.0 // indirect - sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/oci/tests/integration/go.sum b/oci/tests/integration/go.sum index 80cd75ac..5dee6df6 100644 --- a/oci/tests/integration/go.sum +++ b/oci/tests/integration/go.sum @@ -8,15 +8,11 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvUL github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= -github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= @@ -60,14 +56,10 @@ github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bradleyfalzon/ghinstallation/v2 v2.12.0 h1:k8oVjGhZel2qmCUsYwSE34jPNT9DL2wCBOtugsHv26g= github.com/bradleyfalzon/ghinstallation/v2 v2.12.0/go.mod h1:V4gJcNyAftH0rXpRp1SUVUuh+ACxOH1xOk/ZzkRHltg= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= @@ -98,10 +90,6 @@ github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fluxcd/cli-utils v0.36.0-flux.10 h1:kgoj1HP7KBFfIG9CHLFHpA2kCPNlfzCpbscCaAOSClE= -github.com/fluxcd/cli-utils v0.36.0-flux.10/go.mod h1:eWf+UVZmm51EmNmeGkdplVLVsFU4jETfCjoHZq7nUp4= github.com/fluxcd/gitkit v0.6.0 h1:iNg5LTx6ePo+Pl0ZwqHTAkhbUHxGVSY3YCxCdw7VIFg= github.com/fluxcd/gitkit v0.6.0/go.mod h1:svOHuKi0fO9HoawdK4HfHAJJseZDHHjk7I3ihnCIqNo= github.com/fluxcd/pkg/gittestserver v0.13.1 h1:5rXF8ANlk6wtAsvqH7tI7gaO2zhMySftf7ALh0AhfU4= @@ -116,8 +104,6 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= -github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= -github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= @@ -151,8 +137,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -170,15 +154,9 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -195,8 +173,6 @@ github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7 github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -225,31 +201,19 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/microsoft/azure-devops-go-api/azuredevops/v7 v7.1.0 h1:mmJCWLe63QvybxhW1iBmQWEaCKdc4SKgALfTNZ+OphU= github.com/microsoft/azure-devops-go-api/azuredevops/v7 v7.1.0/go.mod h1:mDunUZ1IUJdJIRHvFb+LPBUtxe3AYB5MI6BMXNg8194= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= -github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= @@ -258,8 +222,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -281,8 +243,6 @@ github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0 github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= @@ -292,15 +252,11 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -317,8 +273,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= -github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= @@ -417,28 +371,18 @@ k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/cli-runtime v0.31.3 h1:fEQD9Xokir78y7pVK/fCJN090/iYNrLHpFbGU4ul9TI= -k8s.io/cli-runtime v0.31.3/go.mod h1:Q2jkyTpl+f6AtodQvgDI8io3jrfr+Z0LyQBPJJ2Btq8= k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= -k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= -k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.31.3 h1:3r111pCjPsvnR98oLLxDMwAeM6OPGmPty6gSKaLTQes= -k8s.io/kubectl v0.31.3/go.mod h1:lhMECDCbJN8He12qcKqs2QfmVo9Pue30geovBVpH5fs= k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno= k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= -sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= -sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= -sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/oci/tests/integration/testapp/main.go b/oci/tests/integration/testapp/main.go index bf92cf9a..e970088e 100644 --- a/oci/tests/integration/testapp/main.go +++ b/oci/tests/integration/testapp/main.go @@ -34,7 +34,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/fluxcd/pkg/auth/azure" - "github.com/fluxcd/pkg/cache" "github.com/fluxcd/pkg/git" "github.com/fluxcd/pkg/git/gogit" "github.com/fluxcd/pkg/git/repository" @@ -69,16 +68,10 @@ func main() { } func checkOci(ctx context.Context) { - cache, err := cache.New(5, cache.StoreObjectKeyFunc, - cache.WithCleanupInterval[cache.StoreObject[authn.Authenticator]](1*time.Second)) - if err != nil { - panic(err) - } opts := login.ProviderOptions{ AwsAutoLogin: true, GcpAutoLogin: true, AzureAutoLogin: true, - Cache: cache, } if *repo == "" { @@ -88,6 +81,7 @@ func checkOci(ctx context.Context) { var loginURL string var auth authn.Authenticator var ref name.Reference + var err error if *registry != "" { // Registry and repository are separate. From a29e42fdb280485d329255d10741bdab4e3dd479 Mon Sep 17 00:00:00 2001 From: Sunny Date: Wed, 27 Nov 2024 16:59:26 +0000 Subject: [PATCH 4/4] cache: Return ErrNotFound error from Get() Previously, when an item is not found in the cache, no error was returned and instead the returned value was expected to be checked for nil to determine if the object was found or not. Considering that other cache functions like GetExpiration() and SetExpiration() return ErrNotFound for items not in cache, it's more consistent to return ErrNotFound for Get() as well. Returning ErrNotFound from Get() makes it clear that the object was not found, instead of needing to check the obtained value. There is no more need to return a pointer to the item. Return the item value instead. This changes the Store interface method signature for Get(). Signed-off-by: Sunny --- cache/cache.go | 17 ++++++++--------- cache/cache_test.go | 31 +++++++++++++++---------------- cache/doc.go | 6 +++--- cache/lru.go | 13 ++++++------- cache/lru_test.go | 11 +++++------ cache/store.go | 2 +- 6 files changed, 38 insertions(+), 42 deletions(-) diff --git a/cache/cache.go b/cache/cache.go index d42ba127..af5ba8d4 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -168,35 +168,34 @@ func (c *cache[T]) set(key string, value T) { c.items = append(c.items, &item) } -// Get returns a pointer to an item in the cache for the given key. If no item -// is found, it's a nil pointer. +// Get returns an item in the cache for the given key. If no item is found, an +// error is returned. // The caller can record cache hit or miss based on the result with // Cache.RecordCacheEvent(). -func (c *Cache[T]) Get(key string) (*T, error) { +func (c *Cache[T]) Get(key string) (T, error) { + var res T c.mu.RLock() if c.closed { c.mu.RUnlock() recordRequest(c.metrics, StatusFailure) - return nil, ErrCacheClosed + return res, ErrCacheClosed } item, found := c.index[key] if !found { c.mu.RUnlock() recordRequest(c.metrics, StatusSuccess) - return nil, nil + return res, ErrNotFound } if !item.expiresAt.IsZero() { if item.expiresAt.Compare(time.Now()) < 0 { c.mu.RUnlock() recordRequest(c.metrics, StatusSuccess) - return nil, nil + return res, ErrNotFound } } c.mu.RUnlock() recordRequest(c.metrics, StatusSuccess) - // Copy the value to prevent writes to the cached item. - r := item.value - return &r, nil + return item.value, nil } // Delete an item from the cache. Does nothing if the key is not in the cache. diff --git a/cache/cache_test.go b/cache/cache_test.go index 5d5d3c6c..509801b1 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -40,8 +40,8 @@ func TestCache(t *testing.T) { key1 := "key1" value1 := "val1" got, err := cache.Get(key1) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(got).To(BeNil()) + g.Expect(err).To(Equal(ErrNotFound)) + g.Expect(got).To(BeEmpty()) // Add an item to the cache err = cache.Set(key1, value1) @@ -50,13 +50,13 @@ func TestCache(t *testing.T) { // Get the item from the cache got, err = cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*got).To(Equal(value1)) + g.Expect(got).To(Equal(value1)) // Writing to the obtained value doesn't update the cache. - *got = "val2" + got = "val2" got2, err := cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*got2).To(Equal(value1)) + g.Expect(got2).To(Equal(value1)) // Add another item to the cache key2 := "key2" @@ -68,7 +68,7 @@ func TestCache(t *testing.T) { // Get the item from the cache got, err = cache.Get(key2) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*got).To(Equal(value2)) + g.Expect(got).To(Equal(value2)) // Update an item in the cache key3 := "key3" @@ -84,7 +84,7 @@ func TestCache(t *testing.T) { // Get the item from the cache got, err = cache.Get(key3) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*got).To(Equal(value4)) + g.Expect(got).To(Equal(value4)) // cleanup the cache cache.Clear() @@ -118,15 +118,15 @@ func TestCache(t *testing.T) { // Get the item from the cache item, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*item).To(Equal(value)) + g.Expect(item).To(Equal(value)) // wait for the item to expire time.Sleep(3 * time.Second) // Get the item from the cache item, err = cache.Get(key) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(item).To(BeNil()) + g.Expect(err).To(Equal(ErrNotFound)) + g.Expect(item).To(BeEmpty()) }) t.Run("Cache of integer value", func(t *testing.T) { @@ -140,7 +140,7 @@ func TestCache(t *testing.T) { got, err := cache.Get(key) g.Expect(err).To(Succeed()) - g.Expect(*got).To(Equal(4)) + g.Expect(got).To(Equal(4)) }) } @@ -216,8 +216,8 @@ func Test_Cache_Get(t *testing.T) { value := "val1" got, err := cache.Get(key) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(got).To(BeNil()) + g.Expect(err).To(Equal(ErrNotFound)) + g.Expect(got).To(BeEmpty()) cache.RecordCacheEvent(CacheEventTypeMiss, recObjKind, recObjName, recObjNamespace) err = cache.Set(key, value) @@ -225,7 +225,7 @@ func Test_Cache_Get(t *testing.T) { got, err = cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*got).To(Equal(value)) + g.Expect(got).To(Equal(value)) cache.RecordCacheEvent(CacheEventTypeHit, recObjKind, recObjName, recObjNamespace) validateMetrics(reg, ` @@ -472,7 +472,6 @@ func TestCache_Concurrent(t *testing.T) { for _, key := range keymap { val, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(val).ToNot(BeNil(), "object %s not found", key) - g.Expect(*val).To(Equal("test-token")) + g.Expect(val).To(Equal("test-token")) } } diff --git a/cache/doc.go b/cache/doc.go index 699b5c69..f1456014 100644 --- a/cache/doc.go +++ b/cache/doc.go @@ -39,10 +39,10 @@ limitations under the License. // // Handle any error. // ... // -// if got != nil { -// cache.RecordCacheEvent(CacheEventTypeHit, "GitRepository", "repoA", "testNS") -// } else { +// if err == ErrNotFound { // cache.RecordCacheEvent(CacheEventTypeMiss, "GitRepository", "repoA", "testNS") +// } else { +// cache.RecordCacheEvent(CacheEventTypeHit, "GitRepository", "repoA", "testNS") // } // // When the Flux object associated with the cache metrics is deleted, the diff --git a/cache/lru.go b/cache/lru.go index 561eaf55..61fc5801 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -170,25 +170,24 @@ func (c *LRU[T]) delete(node *node[T]) { delete(c.cache, node.key) } -// Get returns a pointer to an item in the cache for the given key. If no item -// is found, it's a nil pointer. +// Get returns an item in the cache for the given key. If no item is found, an +// error is returned. // The caller can record cache hit or miss based on the result with // LRU.RecordCacheEvent(). -func (c *LRU[T]) Get(key string) (*T, error) { +func (c *LRU[T]) Get(key string) (T, error) { + var res T c.mu.Lock() node, ok := c.cache[key] if !ok { c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) - return nil, nil + return res, ErrNotFound } c.delete(node) _ = c.add(node) c.mu.Unlock() recordRequest(c.metrics, StatusSuccess) - // Copy the value to prevent writes to the cached item. - r := node.value - return &r, nil + return node.value, nil } // ListKeys returns a list of keys in the cache. diff --git a/cache/lru_test.go b/cache/lru_test.go index 57b93c63..645f0fac 100644 --- a/cache/lru_test.go +++ b/cache/lru_test.go @@ -163,8 +163,8 @@ func Test_LRU_Get(t *testing.T) { key1 := "key1" value1 := "val1" got, err := cache.Get(key1) - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(got).To(BeNil()) + g.Expect(err).To(Equal(ErrNotFound)) + g.Expect(got).To(BeEmpty()) cache.RecordCacheEvent(CacheEventTypeMiss, recObjKind, recObjName, recObjNamespace) err = cache.Set(key1, value1) @@ -172,7 +172,7 @@ func Test_LRU_Get(t *testing.T) { got, err = cache.Get(key1) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(*got).To(Equal(value1)) + g.Expect(got).To(Equal(value1)) cache.RecordCacheEvent(CacheEventTypeHit, recObjKind, recObjName, recObjNamespace) validateMetrics(reg, ` @@ -309,8 +309,7 @@ func TestLRU_Concurrent(t *testing.T) { for _, key := range keymap { val, err := cache.Get(key) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(val).ToNot(BeNil(), "object %s not found", key) - g.Expect(*val).To(Equal("test-token")) + g.Expect(val).To(Equal("test-token")) } } @@ -325,5 +324,5 @@ func TestLRU_int(t *testing.T) { got, err := cache.Get(key) g.Expect(err).To(Succeed()) - g.Expect(*got).To(Equal(4)) + g.Expect(got).To(Equal(4)) } diff --git a/cache/store.go b/cache/store.go index d0dce133..a5207bf9 100644 --- a/cache/store.go +++ b/cache/store.go @@ -27,7 +27,7 @@ type Store[T any] interface { // Set adds an item to the store for the given key. Set(key string, value T) error // Get returns an item stored in the store for the given key. - Get(key string) (*T, error) + Get(key string) (T, error) // Delete deletes an item in the store for the given key. Delete(key string) error }