grafana/pkg/services/datasources/service/legacy.go
2024-03-08 18:12:59 +02:00

91 lines
2.4 KiB
Go

package service
import (
"context"
"errors"
"fmt"
"sync"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
"github.com/grafana/grafana/pkg/infra/appcontext"
"github.com/grafana/grafana/pkg/services/datasources"
)
// LegacyDataSourceRetriever supports finding a reference to datasources using the name or internal ID
type LegacyDataSourceLookup interface {
// Find the UID from either the name or internal id
// NOTE the orgID will be fetched from the context
GetDataSourceFromDeprecatedFields(ctx context.Context, name string, id int64) (*data.DataSourceRef, error)
}
var (
_ DataSourceRetriever = (*Service)(nil)
_ LegacyDataSourceLookup = (*cachingLegacyDataSourceLookup)(nil)
_ LegacyDataSourceLookup = (*NoopLegacyDataSourcLookup)(nil)
)
// NoopLegacyDataSourceRetriever does not even try to lookup, it returns a raw reference
type NoopLegacyDataSourcLookup struct {
Ref *data.DataSourceRef
}
func (s *NoopLegacyDataSourcLookup) GetDataSourceFromDeprecatedFields(ctx context.Context, name string, id int64) (*data.DataSourceRef, error) {
return s.Ref, nil
}
type cachingLegacyDataSourceLookup struct {
retriever DataSourceRetriever
cache map[string]cachedValue
cacheMu sync.Mutex
}
type cachedValue struct {
ref *data.DataSourceRef
err error
}
func ProvideLegacyDataSourceLookup(p *Service) LegacyDataSourceLookup {
return &cachingLegacyDataSourceLookup{
retriever: p,
cache: make(map[string]cachedValue),
}
}
func (s *cachingLegacyDataSourceLookup) GetDataSourceFromDeprecatedFields(ctx context.Context, name string, id int64) (*data.DataSourceRef, error) {
if id == 0 && name == "" {
return nil, fmt.Errorf("either name or ID must be set")
}
user, err := appcontext.User(ctx)
if err != nil {
return nil, err
}
key := fmt.Sprintf("%d/%s/%d", user.OrgID, name, id)
s.cacheMu.Lock()
defer s.cacheMu.Unlock()
v, ok := s.cache[key]
if ok {
return v.ref, v.err
}
ds, err := s.retriever.GetDataSource(ctx, &datasources.GetDataSourceQuery{
OrgID: user.OrgID,
Name: name,
ID: id,
})
if errors.Is(err, datasources.ErrDataSourceNotFound) && name != "" {
ds, err = s.retriever.GetDataSource(ctx, &datasources.GetDataSourceQuery{
OrgID: user.OrgID,
UID: name, // Sometimes name is actually the UID :(
})
}
v = cachedValue{
err: err,
}
if ds != nil {
v.ref = &data.DataSourceRef{Type: ds.Type, UID: ds.UID}
}
return v.ref, v.err
}