grafana/pkg/services/store/resolver/service.go
Dan Cech 9f6144059a
Storage: Switch from tenant to namespace & remove GRN (#79250)
* remove GRN and switch tenant to namespace

* clean up remaining references

* simplify and remove inconsistency in With* parameters

* parse listing keys so we can use db index

* bump the schema version

---------

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2023-12-11 12:26:05 -05:00

126 lines
3.4 KiB
Go

package resolver
import (
"context"
"fmt"
"time"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/store/entity"
)
const (
WarningNotImplemented = "not implemented"
WarningDatasourcePluginNotFound = "datasource plugin not found"
WarningTypeNotSpecified = "type not specified"
WarningPluginNotFound = "plugin not found"
)
// for testing
var getNow = func() time.Time { return time.Now() }
type ResolutionInfo struct {
OK bool `json:"ok"`
Key string `json:"key,omitempty"` // k8s key
Warning string `json:"kind,omitempty"` // old syntax? (name>uid) references a renamed object?
Timestamp time.Time `json:"timestamp,omitempty"`
}
type EntityReferenceResolver interface {
Resolve(ctx context.Context, ref *entity.EntityExternalReference) (ResolutionInfo, error)
}
func ProvideEntityReferenceResolver(ds datasources.DataSourceService, pluginStore pluginstore.Store) EntityReferenceResolver {
return &standardReferenceResolver{
pluginStore: pluginStore,
ds: dsCache{
ds: ds,
pluginStore: pluginStore,
},
}
}
type standardReferenceResolver struct {
pluginStore pluginstore.Store
ds dsCache
}
func (r *standardReferenceResolver) Resolve(ctx context.Context, ref *entity.EntityExternalReference) (ResolutionInfo, error) {
if ref == nil {
return ResolutionInfo{OK: false, Timestamp: getNow()}, fmt.Errorf("ref is nil")
}
switch ref.Family {
case entity.StandardKindDataSource:
return r.resolveDatasource(ctx, ref)
case entity.ExternalEntityReferencePlugin:
return r.resolvePlugin(ctx, ref)
// case entity.ExternalEntityReferenceRuntime:
// return ResolutionInfo{
// OK: false,
// Timestamp: getNow(),
// Warning: WarningNotImplemented,
// }, nil
}
return ResolutionInfo{
OK: false,
Timestamp: getNow(),
Warning: WarningNotImplemented,
}, nil
}
func (r *standardReferenceResolver) resolveDatasource(ctx context.Context, ref *entity.EntityExternalReference) (ResolutionInfo, error) {
ds, err := r.ds.getDS(ctx, ref.Identifier)
if err != nil || ds == nil || ds.UID == "" {
return ResolutionInfo{
OK: false,
Timestamp: r.ds.timestamp,
}, err
}
res := ResolutionInfo{
OK: true,
Timestamp: r.ds.timestamp,
Key: ds.UID, // TODO!
}
if !ds.PluginExists {
res.OK = false
res.Warning = WarningDatasourcePluginNotFound
} else if ref.Type == "" {
ref.Type = ds.Type // awkward! but makes the reporting accurate for dashboards before schemaVersion 36
res.Warning = WarningTypeNotSpecified
} else if ref.Type != ds.Type {
res.Warning = fmt.Sprintf("type mismatch (expect:%s, found:%s)", ref.Type, ds.Type)
}
return res, nil
}
func (r *standardReferenceResolver) resolvePlugin(ctx context.Context, ref *entity.EntityExternalReference) (ResolutionInfo, error) {
p, ok := r.pluginStore.Plugin(ctx, ref.Identifier)
if !ok {
return ResolutionInfo{
OK: false,
Timestamp: getNow(),
Warning: WarningPluginNotFound,
}, nil
}
if p.Type != plugins.Type(ref.Type) {
return ResolutionInfo{
OK: false,
Timestamp: getNow(),
Warning: fmt.Sprintf("expected type: %s, found%s", ref.Type, p.Type),
}, nil
}
return ResolutionInfo{
OK: true,
Timestamp: getNow(),
}, nil
}