|
|
|
|
@ -12,6 +12,7 @@ import ( |
|
|
|
|
"github.com/grafana/grafana/pkg/infra/db" |
|
|
|
|
glog "github.com/grafana/grafana/pkg/infra/log" |
|
|
|
|
"github.com/grafana/grafana/pkg/registry" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/secrets" |
|
|
|
|
"github.com/grafana/grafana/pkg/setting" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
@ -29,8 +30,14 @@ const ( |
|
|
|
|
ServiceName = "RemoteCache" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func ProvideService(cfg *setting.Cfg, sqlStore db.DB) (*RemoteCache, error) { |
|
|
|
|
client, err := createClient(cfg.RemoteCacheOptions, sqlStore) |
|
|
|
|
func ProvideService(cfg *setting.Cfg, sqlStore db.DB, secretsService secrets.Service) (*RemoteCache, error) { |
|
|
|
|
var codec codec |
|
|
|
|
if cfg.RemoteCacheOptions.Encryption { |
|
|
|
|
codec = &encryptionCodec{secretsService} |
|
|
|
|
} else { |
|
|
|
|
codec = &gobCodec{} |
|
|
|
|
} |
|
|
|
|
client, err := createClient(cfg.RemoteCacheOptions, sqlStore, codec) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
@ -97,14 +104,14 @@ func (ds *RemoteCache) Run(ctx context.Context) error { |
|
|
|
|
return ctx.Err() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func createClient(opts *setting.RemoteCacheOptions, sqlstore db.DB) (cache CacheStorage, err error) { |
|
|
|
|
func createClient(opts *setting.RemoteCacheOptions, sqlstore db.DB, codec codec) (cache CacheStorage, err error) { |
|
|
|
|
switch opts.Name { |
|
|
|
|
case redisCacheType: |
|
|
|
|
cache, err = newRedisStorage(opts) |
|
|
|
|
cache, err = newRedisStorage(opts, codec) |
|
|
|
|
case memcachedCacheType: |
|
|
|
|
cache = newMemcachedStorage(opts) |
|
|
|
|
cache = newMemcachedStorage(opts, codec) |
|
|
|
|
case databaseCacheType: |
|
|
|
|
cache = newDatabaseCache(sqlstore) |
|
|
|
|
cache = newDatabaseCache(sqlstore, codec) |
|
|
|
|
default: |
|
|
|
|
return nil, ErrInvalidCacheType |
|
|
|
|
} |
|
|
|
|
@ -131,17 +138,46 @@ type cachedItem struct { |
|
|
|
|
Val interface{} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func encodeGob(item *cachedItem) ([]byte, error) { |
|
|
|
|
type codec interface { |
|
|
|
|
Encode(context.Context, *cachedItem) ([]byte, error) |
|
|
|
|
Decode(context.Context, []byte, *cachedItem) error |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type gobCodec struct{} |
|
|
|
|
|
|
|
|
|
func (c *gobCodec) Encode(_ context.Context, item *cachedItem) ([]byte, error) { |
|
|
|
|
buf := bytes.NewBuffer(nil) |
|
|
|
|
err := gob.NewEncoder(buf).Encode(item) |
|
|
|
|
return buf.Bytes(), err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func decodeGob(data []byte, out *cachedItem) error { |
|
|
|
|
func (c *gobCodec) Decode(_ context.Context, data []byte, out *cachedItem) error { |
|
|
|
|
buf := bytes.NewBuffer(data) |
|
|
|
|
return gob.NewDecoder(buf).Decode(&out) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type encryptionCodec struct { |
|
|
|
|
secretsService secrets.Service |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *encryptionCodec) Encode(ctx context.Context, item *cachedItem) ([]byte, error) { |
|
|
|
|
buf := bytes.NewBuffer(nil) |
|
|
|
|
err := gob.NewEncoder(buf).Encode(item) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
return c.secretsService.Encrypt(ctx, buf.Bytes(), secrets.WithoutScope()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *encryptionCodec) Decode(ctx context.Context, data []byte, out *cachedItem) error { |
|
|
|
|
decrypted, err := c.secretsService.Decrypt(ctx, data) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
buf := bytes.NewBuffer(decrypted) |
|
|
|
|
return gob.NewDecoder(buf).Decode(&out) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type prefixCacheStorage struct { |
|
|
|
|
cache CacheStorage |
|
|
|
|
prefix string |
|
|
|
|
|