datasources: querier: handle the grafana-ds (#103980)
* datasources: querier: handle the grafana-ds * updated dependencies
This commit is contained in:
@@ -19,9 +19,11 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query/clientapi"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/adapters"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafanads"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
@@ -90,6 +92,23 @@ func (d *pluginClient) CanQueryDataSource(ctx context.Context, uid string) (bool
|
||||
return d.ac.Evaluate(ctx, user, evaluate)
|
||||
}
|
||||
|
||||
// this handles the special `--grafana--` data source
|
||||
func getGrafanaDataSourceSettings(ctx context.Context) (*backend.DataSourceInstanceSettings, error) {
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds := grafanads.DataSourceModel(user.GetOrgID())
|
||||
|
||||
decryptFunc := func(ds *datasources.DataSource) (map[string]string, error) {
|
||||
// we do not need to handle any secrets
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return adapters.ModelToInstanceSettings(ds, decryptFunc)
|
||||
}
|
||||
|
||||
// ExecuteQueryData implements QueryHelper.
|
||||
func (d *pluginClient) QueryData(ctx context.Context, req data.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
queries, dsRef, err := data.ToDataSourceQueries(req)
|
||||
@@ -109,8 +128,16 @@ func (d *pluginClient) QueryData(ctx context.Context, req data.QueryDataRequest)
|
||||
return nil, k8sForbiddenError
|
||||
}
|
||||
|
||||
// NOTE: this depends on uid unique across datasources
|
||||
settings, err := d.pCtxProvider.GetDataSourceInstanceSettings(ctx, dsRef.UID)
|
||||
var settings *backend.DataSourceInstanceSettings
|
||||
|
||||
// we need to special-case the "--grafana--" data source
|
||||
if dsRef.UID == grafanads.DatasourceUID {
|
||||
settings, err = getGrafanaDataSourceSettings(ctx)
|
||||
} else {
|
||||
// NOTE: this depends on uid unique across datasources
|
||||
settings, err = d.pCtxProvider.GetDataSourceInstanceSettings(ctx, dsRef.UID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// there is no better way to differentiate between plugin-not-found and other-error
|
||||
if errors.Is(err, datasources.ErrDataSourceNotFound) {
|
||||
|
||||
@@ -237,6 +237,18 @@ func (p *queryParser) getValidDataSourceRef(ctx context.Context, ds *data.DataSo
|
||||
}
|
||||
return p.legacy.GetDataSourceFromDeprecatedFields(ctx, "", id)
|
||||
}
|
||||
|
||||
// we need to special-case the "grafana" data source
|
||||
if ds.UID == "grafana" {
|
||||
return &data.DataSourceRef{
|
||||
// it does not really matter what `type` we set here,
|
||||
// we will always detect this case by `uid` later.
|
||||
// here we go with what the data source's plugin.json says.
|
||||
Type: "grafana",
|
||||
UID: "grafana",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ds.Type == "" {
|
||||
if ds.UID == "" {
|
||||
return nil, fmt.Errorf("missing name/uid in data source reference")
|
||||
|
||||
@@ -3,6 +3,7 @@ package query
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
@@ -200,6 +201,59 @@ func TestSqlInputs(t *testing.T) {
|
||||
require.Equal(t, parsedRequestInfo.SqlInputs["B"], struct{}{})
|
||||
}
|
||||
|
||||
func TestGrafanaDS(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
parser := newQueryParser(expr.NewExpressionQueryReader(featuremgmt.WithFeatures()),
|
||||
&noLegacyRetriever{}, tracing.InitializeTracerForTest(), log.NewNopLogger())
|
||||
|
||||
t.Run("grafana ds without type", func(t *testing.T) {
|
||||
parsed, err := parser.parseRequest(ctx, &query.QueryDataRequest{
|
||||
QueryDataRequest: data.QueryDataRequest{
|
||||
Queries: []data.DataQuery{{
|
||||
CommonQueryProperties: data.CommonQueryProperties{
|
||||
RefID: "A",
|
||||
Datasource: &data.DataSourceRef{
|
||||
UID: "grafana",
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, parsed.Requests, 1)
|
||||
require.Equal(t, "grafana", parsed.Requests[0].PluginId)
|
||||
require.Equal(t, "grafana", parsed.Requests[0].UID)
|
||||
})
|
||||
|
||||
t.Run("grafana ds with different type", func(t *testing.T) {
|
||||
parsed, err := parser.parseRequest(ctx, &query.QueryDataRequest{
|
||||
QueryDataRequest: data.QueryDataRequest{
|
||||
Queries: []data.DataQuery{{
|
||||
CommonQueryProperties: data.CommonQueryProperties{
|
||||
RefID: "A",
|
||||
Datasource: &data.DataSourceRef{
|
||||
UID: "grafana",
|
||||
Type: "datasource",
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, parsed.Requests, 1)
|
||||
require.Equal(t, "grafana", parsed.Requests[0].PluginId)
|
||||
require.Equal(t, "grafana", parsed.Requests[0].UID)
|
||||
})
|
||||
}
|
||||
|
||||
type noLegacyRetriever struct{}
|
||||
|
||||
var errNoLegacy = errors.New("legacy dds retriever reached, it should not")
|
||||
|
||||
func (s *noLegacyRetriever) GetDataSourceFromDeprecatedFields(ctx context.Context, name string, id int64) (*data.DataSourceRef, error) {
|
||||
return nil, errNoLegacy
|
||||
}
|
||||
|
||||
type legacyDataSourceRetriever struct{}
|
||||
|
||||
func (s *legacyDataSourceRetriever) GetDataSourceFromDeprecatedFields(ctx context.Context, name string, id int64) (*data.DataSourceRef, error) {
|
||||
|
||||
Reference in New Issue
Block a user