The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/store/resolver/service.go

125 lines
3.4 KiB

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
}