mirror of https://github.com/grafana/grafana
Chore: Refactor backend plugin manager/tsdb query data (#34944)
Move QueryData method into backend plugin manager which HandleRequest uses to query data from plugin SDK supported data sources. This allowed us to remove a lot of code no longer needed. Ref #21510 Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>pull/34946/head
parent
56e0efbb56
commit
b3e9087557
@ -1,116 +0,0 @@ |
|||||||
package coreplugin |
|
||||||
|
|
||||||
import ( |
|
||||||
"context" |
|
||||||
"time" |
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend" |
|
||||||
"github.com/grafana/grafana/pkg/infra/log" |
|
||||||
"github.com/grafana/grafana/pkg/models" |
|
||||||
"github.com/grafana/grafana/pkg/plugins" |
|
||||||
"github.com/grafana/grafana/pkg/plugins/adapters" |
|
||||||
) |
|
||||||
|
|
||||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
|
||||||
func newQueryEndpointAdapter(pluginID string, logger log.Logger, handler backend.QueryDataHandler) plugins.DataPlugin { |
|
||||||
return &queryEndpointAdapter{ |
|
||||||
pluginID: pluginID, |
|
||||||
logger: logger, |
|
||||||
handler: handler, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
type queryEndpointAdapter struct { |
|
||||||
pluginID string |
|
||||||
logger log.Logger |
|
||||||
handler backend.QueryDataHandler |
|
||||||
} |
|
||||||
|
|
||||||
func modelToInstanceSettings(ds *models.DataSource) (*backend.DataSourceInstanceSettings, error) { |
|
||||||
jsonDataBytes, err := ds.JsonData.MarshalJSON() |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
return &backend.DataSourceInstanceSettings{ |
|
||||||
ID: ds.Id, |
|
||||||
Name: ds.Name, |
|
||||||
URL: ds.Url, |
|
||||||
Database: ds.Database, |
|
||||||
User: ds.User, |
|
||||||
BasicAuthEnabled: ds.BasicAuth, |
|
||||||
BasicAuthUser: ds.BasicAuthUser, |
|
||||||
JSONData: jsonDataBytes, |
|
||||||
DecryptedSecureJSONData: ds.DecryptedValues(), |
|
||||||
Updated: ds.Updated, |
|
||||||
}, nil |
|
||||||
} |
|
||||||
|
|
||||||
// nolint:staticcheck // plugins.DataQuery deprecated
|
|
||||||
func (a *queryEndpointAdapter) DataQuery(ctx context.Context, ds *models.DataSource, query plugins.DataQuery) ( |
|
||||||
plugins.DataResponse, error) { |
|
||||||
instanceSettings, err := modelToInstanceSettings(ds) |
|
||||||
if err != nil { |
|
||||||
return plugins.DataResponse{}, err |
|
||||||
} |
|
||||||
|
|
||||||
req := &backend.QueryDataRequest{ |
|
||||||
PluginContext: backend.PluginContext{ |
|
||||||
OrgID: ds.OrgId, |
|
||||||
PluginID: a.pluginID, |
|
||||||
User: adapters.BackendUserFromSignedInUser(query.User), |
|
||||||
DataSourceInstanceSettings: instanceSettings, |
|
||||||
}, |
|
||||||
Queries: []backend.DataQuery{}, |
|
||||||
Headers: query.Headers, |
|
||||||
} |
|
||||||
|
|
||||||
for _, q := range query.Queries { |
|
||||||
modelJSON, err := q.Model.MarshalJSON() |
|
||||||
if err != nil { |
|
||||||
return plugins.DataResponse{}, err |
|
||||||
} |
|
||||||
req.Queries = append(req.Queries, backend.DataQuery{ |
|
||||||
RefID: q.RefID, |
|
||||||
Interval: time.Duration(q.IntervalMS) * time.Millisecond, |
|
||||||
MaxDataPoints: q.MaxDataPoints, |
|
||||||
TimeRange: backend.TimeRange{ |
|
||||||
From: query.TimeRange.GetFromAsTimeUTC(), |
|
||||||
To: query.TimeRange.GetToAsTimeUTC(), |
|
||||||
}, |
|
||||||
QueryType: q.QueryType, |
|
||||||
JSON: modelJSON, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
resp, err := a.handler.QueryData(ctx, req) |
|
||||||
if err != nil { |
|
||||||
return plugins.DataResponse{}, err |
|
||||||
} |
|
||||||
|
|
||||||
tR := plugins.DataResponse{ |
|
||||||
Results: make(map[string]plugins.DataQueryResult, len(resp.Responses)), |
|
||||||
} |
|
||||||
|
|
||||||
for refID, r := range resp.Responses { |
|
||||||
qr := plugins.DataQueryResult{ |
|
||||||
RefID: refID, |
|
||||||
} |
|
||||||
|
|
||||||
for _, f := range r.Frames { |
|
||||||
if f.RefID == "" { |
|
||||||
f.RefID = refID |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
qr.Dataframes = plugins.NewDecodedDataFrames(r.Frames) |
|
||||||
|
|
||||||
if r.Error != nil { |
|
||||||
qr.Error = r.Error |
|
||||||
} |
|
||||||
|
|
||||||
tR.Results[refID] = qr |
|
||||||
} |
|
||||||
|
|
||||||
return tR, nil |
|
||||||
} |
|
@ -1,99 +0,0 @@ |
|||||||
package plugins |
|
||||||
|
|
||||||
import ( |
|
||||||
"context" |
|
||||||
"fmt" |
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend" |
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin" |
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2" |
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson" |
|
||||||
"github.com/grafana/grafana/pkg/infra/log" |
|
||||||
"github.com/grafana/grafana/pkg/models" |
|
||||||
"github.com/grafana/grafana/pkg/plugins/adapters" |
|
||||||
"github.com/grafana/grafana/pkg/services/oauthtoken" |
|
||||||
) |
|
||||||
|
|
||||||
func newDataSourcePluginWrapperV2(log log.Logger, pluginId, pluginType string, dataClient grpcplugin.DataClient) *DatasourcePluginWrapperV2 { |
|
||||||
return &DatasourcePluginWrapperV2{DataClient: dataClient, logger: log, pluginId: pluginId, pluginType: pluginType} |
|
||||||
} |
|
||||||
|
|
||||||
type DatasourcePluginWrapperV2 struct { |
|
||||||
grpcplugin.DataClient |
|
||||||
logger log.Logger |
|
||||||
pluginId string |
|
||||||
pluginType string |
|
||||||
} |
|
||||||
|
|
||||||
func (tw *DatasourcePluginWrapperV2) Query(ctx context.Context, ds *models.DataSource, query DataQuery) (DataResponse, error) { |
|
||||||
instanceSettings, err := adapters.ModelToInstanceSettings(ds) |
|
||||||
if err != nil { |
|
||||||
return DataResponse{}, err |
|
||||||
} |
|
||||||
|
|
||||||
if query.Headers == nil { |
|
||||||
query.Headers = make(map[string]string) |
|
||||||
} |
|
||||||
|
|
||||||
if oauthtoken.IsOAuthPassThruEnabled(ds) { |
|
||||||
if token := oauthtoken.GetCurrentOAuthToken(ctx, query.User); token != nil { |
|
||||||
delete(query.Headers, "Authorization") |
|
||||||
query.Headers["Authorization"] = fmt.Sprintf("%s %s", token.Type(), token.AccessToken) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pbQuery := &pluginv2.QueryDataRequest{ |
|
||||||
PluginContext: &pluginv2.PluginContext{ |
|
||||||
OrgId: ds.OrgId, |
|
||||||
PluginId: tw.pluginId, |
|
||||||
User: backend.ToProto().User(adapters.BackendUserFromSignedInUser(query.User)), |
|
||||||
DataSourceInstanceSettings: backend.ToProto().DataSourceInstanceSettings(instanceSettings), |
|
||||||
}, |
|
||||||
Queries: []*pluginv2.DataQuery{}, |
|
||||||
Headers: query.Headers, |
|
||||||
} |
|
||||||
|
|
||||||
for _, q := range query.Queries { |
|
||||||
modelJSON, err := q.Model.MarshalJSON() |
|
||||||
if err != nil { |
|
||||||
return DataResponse{}, err |
|
||||||
} |
|
||||||
pbQuery.Queries = append(pbQuery.Queries, &pluginv2.DataQuery{ |
|
||||||
Json: modelJSON, |
|
||||||
IntervalMS: q.IntervalMS, |
|
||||||
RefId: q.RefID, |
|
||||||
MaxDataPoints: q.MaxDataPoints, |
|
||||||
TimeRange: &pluginv2.TimeRange{ |
|
||||||
ToEpochMS: query.TimeRange.GetToAsMsEpoch(), |
|
||||||
FromEpochMS: query.TimeRange.GetFromAsMsEpoch(), |
|
||||||
}, |
|
||||||
QueryType: q.QueryType, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
pbRes, err := tw.DataClient.QueryData(ctx, pbQuery) |
|
||||||
if err != nil { |
|
||||||
return DataResponse{}, err |
|
||||||
} |
|
||||||
|
|
||||||
tR := DataResponse{ |
|
||||||
Results: make(map[string]DataQueryResult, len(pbRes.Responses)), |
|
||||||
} |
|
||||||
|
|
||||||
for refID, pRes := range pbRes.Responses { |
|
||||||
qr := DataQueryResult{ |
|
||||||
RefID: refID, |
|
||||||
Dataframes: NewEncodedDataFrames(pRes.Frames), |
|
||||||
} |
|
||||||
if len(pRes.JsonMeta) != 0 { |
|
||||||
qr.Meta = simplejson.NewFromAny(pRes.JsonMeta) |
|
||||||
} |
|
||||||
if pRes.Error != "" { |
|
||||||
qr.Error = fmt.Errorf(pRes.Error) |
|
||||||
qr.ErrorString = pRes.Error |
|
||||||
} |
|
||||||
tR.Results[refID] = qr |
|
||||||
} |
|
||||||
|
|
||||||
return tR, nil |
|
||||||
} |
|
@ -0,0 +1,115 @@ |
|||||||
|
package tsdb |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend" |
||||||
|
"github.com/grafana/grafana/pkg/models" |
||||||
|
"github.com/grafana/grafana/pkg/plugins" |
||||||
|
"github.com/grafana/grafana/pkg/plugins/adapters" |
||||||
|
"github.com/grafana/grafana/pkg/services/oauthtoken" |
||||||
|
) |
||||||
|
|
||||||
|
// nolint:staticcheck // plugins.DataQuery deprecated
|
||||||
|
func dataPluginQueryAdapter(pluginID string, handler backend.QueryDataHandler) plugins.DataPluginFunc { |
||||||
|
return plugins.DataPluginFunc(func(ctx context.Context, ds *models.DataSource, query plugins.DataQuery) (plugins.DataResponse, error) { |
||||||
|
instanceSettings, err := modelToInstanceSettings(ds) |
||||||
|
if err != nil { |
||||||
|
return plugins.DataResponse{}, err |
||||||
|
} |
||||||
|
|
||||||
|
if query.Headers == nil { |
||||||
|
query.Headers = make(map[string]string) |
||||||
|
} |
||||||
|
|
||||||
|
if oauthtoken.IsOAuthPassThruEnabled(ds) { |
||||||
|
if token := oauthtoken.GetCurrentOAuthToken(ctx, query.User); token != nil { |
||||||
|
delete(query.Headers, "Authorization") |
||||||
|
query.Headers["Authorization"] = fmt.Sprintf("%s %s", token.Type(), token.AccessToken) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
req := &backend.QueryDataRequest{ |
||||||
|
PluginContext: backend.PluginContext{ |
||||||
|
OrgID: ds.OrgId, |
||||||
|
PluginID: pluginID, |
||||||
|
User: adapters.BackendUserFromSignedInUser(query.User), |
||||||
|
DataSourceInstanceSettings: instanceSettings, |
||||||
|
}, |
||||||
|
Queries: []backend.DataQuery{}, |
||||||
|
Headers: query.Headers, |
||||||
|
} |
||||||
|
|
||||||
|
for _, q := range query.Queries { |
||||||
|
modelJSON, err := q.Model.MarshalJSON() |
||||||
|
if err != nil { |
||||||
|
return plugins.DataResponse{}, err |
||||||
|
} |
||||||
|
req.Queries = append(req.Queries, backend.DataQuery{ |
||||||
|
RefID: q.RefID, |
||||||
|
Interval: time.Duration(q.IntervalMS) * time.Millisecond, |
||||||
|
MaxDataPoints: q.MaxDataPoints, |
||||||
|
TimeRange: backend.TimeRange{ |
||||||
|
From: query.TimeRange.GetFromAsTimeUTC(), |
||||||
|
To: query.TimeRange.GetToAsTimeUTC(), |
||||||
|
}, |
||||||
|
QueryType: q.QueryType, |
||||||
|
JSON: modelJSON, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
resp, err := handler.QueryData(ctx, req) |
||||||
|
if err != nil { |
||||||
|
return plugins.DataResponse{}, err |
||||||
|
} |
||||||
|
|
||||||
|
tR := plugins.DataResponse{ |
||||||
|
Results: make(map[string]plugins.DataQueryResult, len(resp.Responses)), |
||||||
|
} |
||||||
|
|
||||||
|
for refID, r := range resp.Responses { |
||||||
|
qr := plugins.DataQueryResult{ |
||||||
|
RefID: refID, |
||||||
|
} |
||||||
|
|
||||||
|
for _, f := range r.Frames { |
||||||
|
if f.RefID == "" { |
||||||
|
f.RefID = refID |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
qr.Dataframes = plugins.NewDecodedDataFrames(r.Frames) |
||||||
|
|
||||||
|
if r.Error != nil { |
||||||
|
qr.Error = r.Error |
||||||
|
} |
||||||
|
|
||||||
|
tR.Results[refID] = qr |
||||||
|
} |
||||||
|
|
||||||
|
return tR, nil |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
func modelToInstanceSettings(ds *models.DataSource) (*backend.DataSourceInstanceSettings, error) { |
||||||
|
jsonDataBytes, err := ds.JsonData.MarshalJSON() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return &backend.DataSourceInstanceSettings{ |
||||||
|
ID: ds.Id, |
||||||
|
Name: ds.Name, |
||||||
|
URL: ds.Url, |
||||||
|
Database: ds.Database, |
||||||
|
User: ds.User, |
||||||
|
BasicAuthEnabled: ds.BasicAuth, |
||||||
|
BasicAuthUser: ds.BasicAuthUser, |
||||||
|
JSONData: jsonDataBytes, |
||||||
|
DecryptedSecureJSONData: ds.DecryptedValues(), |
||||||
|
Updated: ds.Updated, |
||||||
|
UID: ds.Uid, |
||||||
|
}, nil |
||||||
|
} |
Loading…
Reference in new issue