Plugins: Refactor kvstore usage in signing keys and angular patterns (#73154)

* Initial refactoring work for plugins kvstore

* Replace implementations for keystore and angularstore

* Cleanup

* add interface check

* lint

* fix storeKeyGetter not being called in namespacedstore set

* Fix tests

* Comments

* Add tests

* Fix invalid cap in ListKeys when store is empty

* Update docstrings

* Add setLastUpdatedOnDelete

* Renamed DefaultStoreKeyGetterFunc, add TestDefaultStoreKeyGetter

* Sort imports

* PR review: removed last_updated key

* PR review: Removed setLastUpdatedOnDelete

* Re-added relevant tests

* PR review: Removed SingleKeyStore

* PR review: Removed custom marshaling support

* Renamed marshaler.go to marshal.go

* PR review: removed unused interfaces

* PR review: Moved marshal into namespacedstore.go

* PR review: removed storekeygetter

* Removed unused file cachekvstore.go

* Renamed NamespacedStore to CacheKvStore

* removed todo
This commit is contained in:
Giuseppe Guerra
2023-09-05 16:20:42 +02:00
committed by GitHub
parent 41ca13418b
commit 2e67a9463d
9 changed files with 361 additions and 110 deletions

View File

@ -2,74 +2,42 @@ package angularpatternsstore
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/cachekvstore"
)
type Service interface {
Get(ctx context.Context) (string, bool, error)
Set(ctx context.Context, patterns any) error
GetLastUpdated(ctx context.Context) (time.Time, error)
Get(ctx context.Context) (string, bool, error)
Set(ctx context.Context, value any) error
}
const (
kvNamespace = "plugin.angularpatterns"
keyPatterns = "angular_patterns"
keyLastUpdated = "last_updated"
keyPatterns = "angular_patterns"
)
// KVStoreService allows to cache GCOM angular patterns into the database, as a cache.
type KVStoreService struct {
kv *kvstore.NamespacedKVStore
*cachekvstore.CacheKvStore
}
var _ Service = (*KVStoreService)(nil)
func ProvideService(kv kvstore.KVStore) Service {
return &KVStoreService{
kv: kvstore.WithNamespace(kv, 0, kvNamespace),
CacheKvStore: cachekvstore.NewCacheKvStore(kv, kvNamespace),
}
}
// Get returns the raw cached angular detection patterns. The returned value is a JSON-encoded string.
// If no value is present, the second argument is false and the returned error is nil.
// Get returns the stored angular patterns from the underlying cachekvstore.
func (s *KVStoreService) Get(ctx context.Context) (string, bool, error) {
return s.kv.Get(ctx, keyPatterns)
return s.CacheKvStore.Get(ctx, keyPatterns)
}
// Set sets the cached angular detection patterns and the latest update time to time.Now().
// patterns must implement json.Marshaler.
func (s *KVStoreService) Set(ctx context.Context, patterns any) error {
b, err := json.Marshal(patterns)
if err != nil {
return fmt.Errorf("json marshal: %w", err)
}
if err := s.kv.Set(ctx, keyPatterns, string(b)); err != nil {
return fmt.Errorf("kv set: %w", err)
}
if err := s.kv.Set(ctx, keyLastUpdated, time.Now().Format(time.RFC3339)); err != nil {
return fmt.Errorf("kv last updated set: %w", err)
}
return nil
}
// GetLastUpdated returns the time when Set was last called. If the value cannot be unmarshalled correctly,
// it returns a zero-value time.Time.
func (s *KVStoreService) GetLastUpdated(ctx context.Context) (time.Time, error) {
v, ok, err := s.kv.Get(ctx, keyLastUpdated)
if err != nil {
return time.Time{}, fmt.Errorf("kv get: %w", err)
}
if !ok {
return time.Time{}, nil
}
t, err := time.Parse(time.RFC3339, v)
if err != nil {
// Ignore decode errors, so we can change the format in future versions
// and keep backwards/forwards compatibility
return time.Time{}, nil
}
return t, nil
// Set stores the given angular patterns in the underlying cachekvstore.s
func (s *KVStoreService) Set(ctx context.Context, value any) error {
return s.CacheKvStore.Set(ctx, keyPatterns, value)
}

View File

@ -41,7 +41,8 @@ func TestAngularPatternsStore(t *testing.T) {
})
t.Run("latest update", func(t *testing.T) {
svc := ProvideService(kvstore.NewFakeKVStore())
underlyingKv := kvstore.NewFakeKVStore()
svc := ProvideService(underlyingKv)
t.Run("empty", func(t *testing.T) {
lastUpdated, err := svc.GetLastUpdated(context.Background())
@ -59,7 +60,7 @@ func TestAngularPatternsStore(t *testing.T) {
})
t.Run("invalid timestamp stored", func(t *testing.T) {
err := svc.(*KVStoreService).kv.Set(context.Background(), keyLastUpdated, "abcd")
err := underlyingKv.Set(context.Background(), 0, kvNamespace, "last_updated", "abcd")
require.NoError(t, err)
lastUpdated, err := svc.GetLastUpdated(context.Background())