Plugins: Remove support for deprecated backend plugin protocol version (#34127)

* 33959: Remove support for deprecated backend plugin protocol (v1)

* 33959: Remove unused methods

* 33959: Remove some additional unused code

* 33959: Remove some additional unused code

* 33959: Remove datasource plugin wrapper with test

* 33959:Remove DefaultProtocolVersion
This commit is contained in:
idafurjes 2021-05-19 08:57:48 +02:00 committed by GitHub
parent 5042dc3b52
commit 1e8e7e34f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 14 additions and 468 deletions

1
go.mod
View File

@ -51,7 +51,6 @@ require (
github.com/gosimple/slug v1.9.0 github.com/gosimple/slug v1.9.0
github.com/grafana/grafana-aws-sdk v0.4.0 github.com/grafana/grafana-aws-sdk v0.4.0
github.com/grafana/grafana-live-sdk v0.0.6 github.com/grafana/grafana-live-sdk v0.0.6
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
github.com/grafana/grafana-plugin-sdk-go v0.98.0 github.com/grafana/grafana-plugin-sdk-go v0.98.0
github.com/grafana/loki v1.6.2-0.20210510132741-f408e05ad426 github.com/grafana/loki v1.6.2-0.20210510132741-f408e05ad426
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0

4
go.sum
View File

@ -922,8 +922,6 @@ github.com/grafana/grafana-aws-sdk v0.4.0 h1:JmTaXfOJ/ydHSWH9kEt8Yhfb9kAhIW4LUOO
github.com/grafana/grafana-aws-sdk v0.4.0/go.mod h1:+pPo5U+pX0zWimR7YBc7ASeSQfbRkcTyQYqMiAj7G5U= github.com/grafana/grafana-aws-sdk v0.4.0/go.mod h1:+pPo5U+pX0zWimR7YBc7ASeSQfbRkcTyQYqMiAj7G5U=
github.com/grafana/grafana-live-sdk v0.0.6 h1:P1QFn0ZradOJp3zVpfG0STZMP+pgZrW0e0zvpqOrYVI= github.com/grafana/grafana-live-sdk v0.0.6 h1:P1QFn0ZradOJp3zVpfG0STZMP+pgZrW0e0zvpqOrYVI=
github.com/grafana/grafana-live-sdk v0.0.6/go.mod h1:f15hHmWyLdFjmuWLsjeKeZnq/HnNQ3QkoPcaEww45AY= github.com/grafana/grafana-live-sdk v0.0.6/go.mod h1:f15hHmWyLdFjmuWLsjeKeZnq/HnNQ3QkoPcaEww45AY=
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 h1:SPdxCL9BChFTlyi0Khv64vdCW4TMna8+sxL7+Chx+Ag=
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4/go.mod h1:nc0XxBzjeGcrMltCDw269LoWF9S8ibhgxolCdA1R8To=
github.com/grafana/grafana-plugin-sdk-go v0.79.0/go.mod h1:NvxLzGkVhnoBKwzkst6CFfpMFKwAdIUZ1q8ssuLeF60= github.com/grafana/grafana-plugin-sdk-go v0.79.0/go.mod h1:NvxLzGkVhnoBKwzkst6CFfpMFKwAdIUZ1q8ssuLeF60=
github.com/grafana/grafana-plugin-sdk-go v0.91.0/go.mod h1:Ot3k7nY7P6DXmUsDgKvNB7oG1v7PRyTdmnYVoS554bU= github.com/grafana/grafana-plugin-sdk-go v0.91.0/go.mod h1:Ot3k7nY7P6DXmUsDgKvNB7oG1v7PRyTdmnYVoS554bU=
github.com/grafana/grafana-plugin-sdk-go v0.98.0 h1:LW69nbYfteelPcyogFNozAbJyaLksKdPtO3t4i3shMQ= github.com/grafana/grafana-plugin-sdk-go v0.98.0 h1:LW69nbYfteelPcyogFNozAbJyaLksKdPtO3t4i3shMQ=
@ -992,7 +990,6 @@ github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-plugin v1.2.2/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= github.com/hashicorp/go-plugin v1.2.2/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A= github.com/hashicorp/go-plugin v1.4.0 h1:b0O7rs5uiJ99Iu9HugEzsM67afboErkHUWddUSpUO3A=
github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
@ -2140,7 +2137,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -3,8 +3,6 @@ package grpcplugin
import ( import (
"os/exec" "os/exec"
datasourceV1 "github.com/grafana/grafana-plugin-model/go/datasource"
rendererV1 "github.com/grafana/grafana-plugin-model/go/renderer"
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin" "github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin"
@ -12,19 +10,12 @@ import (
goplugin "github.com/hashicorp/go-plugin" goplugin "github.com/hashicorp/go-plugin"
) )
const (
// DefaultProtocolVersion is the protocol version assumed for legacy clients that don't specify
// a particular version or version 1 during their handshake. This is currently the version used
// since Grafana launched support for backend plugins.
DefaultProtocolVersion = 1
)
// Handshake is the HandshakeConfig used to configure clients and servers. // Handshake is the HandshakeConfig used to configure clients and servers.
var handshake = goplugin.HandshakeConfig{ var handshake = goplugin.HandshakeConfig{
// The ProtocolVersion is the version that must match between Grafana core // The ProtocolVersion is the version that must match between Grafana core
// and Grafana plugins. This should be bumped whenever a (breaking) change // and Grafana plugins. This should be bumped whenever a (breaking) change
// happens in one or the other that makes it so that they can't safely communicate. // happens in one or the other that makes it so that they can't safely communicate.
ProtocolVersion: DefaultProtocolVersion, ProtocolVersion: grpcplugin.ProtocolVersion,
// The magic cookie values should NEVER be changed. // The magic cookie values should NEVER be changed.
MagicCookieKey: grpcplugin.MagicCookieKey, MagicCookieKey: grpcplugin.MagicCookieKey,
@ -47,15 +38,11 @@ func newClientConfig(executablePath string, env []string, logger log.Logger,
} }
} }
// LegacyStartFunc callback function called when a plugin with old plugin protocol is started.
type LegacyStartFunc func(pluginID string, client *LegacyClient, logger log.Logger) error
// StartFunc callback function called when a plugin with current plugin protocol version is started. // StartFunc callback function called when a plugin with current plugin protocol version is started.
type StartFunc func(pluginID string, client *Client, logger log.Logger) error type StartFunc func(pluginID string, client *Client, logger log.Logger) error
// PluginStartFuncs functions called for plugin when started. // PluginStartFuncs functions called for plugin when started.
type PluginStartFuncs struct { type PluginStartFuncs struct {
OnLegacyStart LegacyStartFunc
OnStart StartFunc OnStart StartFunc
} }
@ -86,9 +73,6 @@ func NewBackendPlugin(pluginID, executablePath string, startFns PluginStartFuncs
executablePath: executablePath, executablePath: executablePath,
managed: true, managed: true,
versionedPlugins: map[int]goplugin.PluginSet{ versionedPlugins: map[int]goplugin.PluginSet{
DefaultProtocolVersion: {
pluginID: &datasourceV1.DatasourcePluginImpl{},
},
grpcplugin.ProtocolVersion: getV2PluginSet(), grpcplugin.ProtocolVersion: getV2PluginSet(),
}, },
startFns: startFns, startFns: startFns,
@ -102,21 +86,12 @@ func NewRendererPlugin(pluginID, executablePath string, startFns PluginStartFunc
executablePath: executablePath, executablePath: executablePath,
managed: false, managed: false,
versionedPlugins: map[int]goplugin.PluginSet{ versionedPlugins: map[int]goplugin.PluginSet{
DefaultProtocolVersion: {
pluginID: &rendererV1.RendererPluginImpl{},
},
grpcplugin.ProtocolVersion: getV2PluginSet(), grpcplugin.ProtocolVersion: getV2PluginSet(),
}, },
startFns: startFns, startFns: startFns,
}) })
} }
// LegacyClient client for communicating with a plugin using the v1 plugin protocol.
type LegacyClient struct {
DatasourcePlugin datasourceV1.DatasourcePlugin
RendererPlugin rendererV1.RendererPlugin
}
// Client client for communicating with a plugin using the current (v2) plugin protocol. // Client client for communicating with a plugin using the current (v2) plugin protocol.
type Client struct { type Client struct {
DataPlugin grpcplugin.DataClient DataPlugin grpcplugin.DataClient

View File

@ -1,97 +0,0 @@
package grpcplugin
import (
"context"
datasourceV1 "github.com/grafana/grafana-plugin-model/go/datasource"
rendererV1 "github.com/grafana/grafana-plugin-model/go/renderer"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/instrumentation"
"github.com/hashicorp/go-plugin"
)
type clientV1 struct {
logger log.Logger
datasourceV1.DatasourcePlugin
rendererV1.RendererPlugin
}
func newClientV1(descriptor PluginDescriptor, logger log.Logger, rpcClient plugin.ClientProtocol) (pluginClient, error) {
logger.Warn("Plugin uses a deprecated version of Grafana's backend plugin system which will be removed in a future release. " +
"Consider upgrading to a newer plugin version or reach out to the plugin repository/developer and request an upgrade.")
raw, err := rpcClient.Dispense(descriptor.pluginID)
if err != nil {
return nil, err
}
c := clientV1{
logger: logger,
}
if plugin, ok := raw.(datasourceV1.DatasourcePlugin); ok {
c.DatasourcePlugin = instrumentDatasourcePluginV1(plugin)
}
if plugin, ok := raw.(rendererV1.RendererPlugin); ok {
c.RendererPlugin = plugin
}
if descriptor.startFns.OnLegacyStart != nil {
legacyClient := &LegacyClient{
DatasourcePlugin: c.DatasourcePlugin,
RendererPlugin: c.RendererPlugin,
}
if err := descriptor.startFns.OnLegacyStart(descriptor.pluginID, legacyClient, logger); err != nil {
return nil, err
}
}
return &c, nil
}
func (c *clientV1) CollectMetrics(ctx context.Context) (*backend.CollectMetricsResult, error) {
return nil, backendplugin.ErrMethodNotImplemented
}
func (c *clientV1) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
return nil, backendplugin.ErrMethodNotImplemented
}
func (c *clientV1) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
return backendplugin.ErrMethodNotImplemented
}
func (c *clientV1) SubscribeStream(ctx context.Context, request *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
return nil, backendplugin.ErrMethodNotImplemented
}
func (c *clientV1) PublishStream(ctx context.Context, request *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
return nil, backendplugin.ErrMethodNotImplemented
}
func (c *clientV1) RunStream(ctx context.Context, request *backend.RunStreamRequest, sender backend.StreamPacketSender) error {
return backendplugin.ErrMethodNotImplemented
}
type datasourceV1QueryFunc func(ctx context.Context, req *datasourceV1.DatasourceRequest) (*datasourceV1.DatasourceResponse, error)
func (fn datasourceV1QueryFunc) Query(ctx context.Context, req *datasourceV1.DatasourceRequest) (*datasourceV1.DatasourceResponse, error) {
return fn(ctx, req)
}
func instrumentDatasourcePluginV1(plugin datasourceV1.DatasourcePlugin) datasourceV1.DatasourcePlugin {
if plugin == nil {
return nil
}
return datasourceV1QueryFunc(func(ctx context.Context, req *datasourceV1.DatasourceRequest) (*datasourceV1.DatasourceResponse, error) {
var resp *datasourceV1.DatasourceResponse
err := instrumentation.InstrumentQueryDataRequest(req.Datasource.Type, func() (innerErr error) {
resp, innerErr = plugin.Query(ctx, req)
return
})
return resp, err
})
}

View File

@ -59,17 +59,13 @@ func (p *grpcPlugin) Start(ctx context.Context) error {
return err return err
} }
if p.client.NegotiatedVersion() > 1 { if p.client.NegotiatedVersion() < 2 {
return errors.New("plugin protocol version not supported")
}
p.pluginClient, err = newClientV2(p.descriptor, p.logger, rpcClient) p.pluginClient, err = newClientV2(p.descriptor, p.logger, rpcClient)
if err != nil { if err != nil {
return err return err
} }
} else {
p.pluginClient, err = newClientV1(p.descriptor, p.logger, rpcClient)
if err != nil {
return err
}
}
if p.pluginClient == nil { if p.pluginClient == nil {
return errors.New("no compatible plugin implementation found") return errors.New("no compatible plugin implementation found")

View File

@ -34,7 +34,6 @@ type DataSourcePlugin struct {
SDK bool `json:"sdk,omitempty"` SDK bool `json:"sdk,omitempty"`
client *grpcplugin.Client client *grpcplugin.Client
legacyClient *grpcplugin.LegacyClient
logger log.Logger logger log.Logger
} }
@ -48,7 +47,6 @@ func (p *DataSourcePlugin) Load(decoder *json.Decoder, base *PluginBase, backend
cmd := ComposePluginStartCommand(p.Executable) cmd := ComposePluginStartCommand(p.Executable)
fullpath := filepath.Join(base.PluginDir, cmd) fullpath := filepath.Join(base.PluginDir, cmd)
factory := grpcplugin.NewBackendPlugin(p.Id, fullpath, grpcplugin.PluginStartFuncs{ factory := grpcplugin.NewBackendPlugin(p.Id, fullpath, grpcplugin.PluginStartFuncs{
OnLegacyStart: p.onLegacyPluginStart,
OnStart: p.onPluginStart, OnStart: p.onPluginStart,
}) })
if err := backendPluginManager.RegisterAndStart(context.Background(), p.Id, factory); err != nil { if err := backendPluginManager.RegisterAndStart(context.Background(), p.Id, factory); err != nil {
@ -64,24 +62,12 @@ func (p *DataSourcePlugin) DataQuery(ctx context.Context, dsInfo *models.DataSou
return DataResponse{}, fmt.Errorf("plugin %q can't handle data queries", p.Id) return DataResponse{}, fmt.Errorf("plugin %q can't handle data queries", p.Id)
} }
if p.client != nil {
endpoint := newDataSourcePluginWrapperV2(p.logger, p.Id, p.Type, p.client.DataPlugin) endpoint := newDataSourcePluginWrapperV2(p.logger, p.Id, p.Type, p.client.DataPlugin)
return endpoint.Query(ctx, dsInfo, query) return endpoint.Query(ctx, dsInfo, query)
}
endpoint := newDataSourcePluginWrapper(p.logger, p.legacyClient.DatasourcePlugin)
return endpoint.Query(ctx, dsInfo, query)
}
func (p *DataSourcePlugin) onLegacyPluginStart(pluginID string, client *grpcplugin.LegacyClient, logger log.Logger) error {
p.legacyClient = client
p.logger = logger
return nil
} }
func (p *DataSourcePlugin) CanHandleDataQueries() bool { func (p *DataSourcePlugin) CanHandleDataQueries() bool {
return p.client != nil || p.legacyClient != nil return p.client != nil
} }
func (p *DataSourcePlugin) onPluginStart(pluginID string, client *grpcplugin.Client, logger log.Logger) error { func (p *DataSourcePlugin) onPluginStart(pluginID string, client *grpcplugin.Client, logger log.Logger) error {

View File

@ -1,172 +0,0 @@
package plugins
import (
"context"
"errors"
"fmt"
"github.com/grafana/grafana-plugin-model/go/datasource"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
)
func newDataSourcePluginWrapper(log log.Logger, plugin datasource.DatasourcePlugin) *DatasourcePluginWrapper {
return &DatasourcePluginWrapper{DatasourcePlugin: plugin, logger: log}
}
type DatasourcePluginWrapper struct {
datasource.DatasourcePlugin
logger log.Logger
}
func (tw *DatasourcePluginWrapper) Query(ctx context.Context, ds *models.DataSource, query DataQuery) (DataResponse, error) {
jsonData, err := ds.JsonData.MarshalJSON()
if err != nil {
return DataResponse{}, err
}
pbQuery := &datasource.DatasourceRequest{
Datasource: &datasource.DatasourceInfo{
Name: ds.Name,
Type: ds.Type,
Url: ds.Url,
Id: ds.Id,
OrgId: ds.OrgId,
JsonData: string(jsonData),
DecryptedSecureJsonData: ds.SecureJsonData.Decrypt(),
},
TimeRange: &datasource.TimeRange{
FromRaw: query.TimeRange.From,
ToRaw: query.TimeRange.To,
ToEpochMs: query.TimeRange.GetToAsMsEpoch(),
FromEpochMs: query.TimeRange.GetFromAsMsEpoch(),
},
Queries: []*datasource.Query{},
}
for _, q := range query.Queries {
modelJson, err := q.Model.MarshalJSON()
if err != nil {
return DataResponse{}, err
}
pbQuery.Queries = append(pbQuery.Queries, &datasource.Query{
ModelJson: string(modelJson),
IntervalMs: q.IntervalMS,
RefId: q.RefID,
MaxDataPoints: q.MaxDataPoints,
})
}
pbres, err := tw.DatasourcePlugin.Query(ctx, pbQuery)
if err != nil {
return DataResponse{}, err
}
res := DataResponse{
Results: map[string]DataQueryResult{},
}
for _, r := range pbres.Results {
qr := DataQueryResult{
RefID: r.RefId,
Series: []DataTimeSeries{},
Tables: []DataTable{},
}
if r.Error != "" {
qr.Error = errors.New(r.Error)
qr.ErrorString = r.Error
}
if r.MetaJson != "" {
metaJson, err := simplejson.NewJson([]byte(r.MetaJson))
if err != nil {
tw.logger.Error("Error parsing JSON Meta field: " + err.Error())
}
qr.Meta = metaJson
}
for _, s := range r.GetSeries() {
points := DataTimeSeriesPoints{}
for _, p := range s.Points {
po := DataTimePoint{null.FloatFrom(p.Value), null.FloatFrom(float64(p.Timestamp))}
points = append(points, po)
}
qr.Series = append(qr.Series, DataTimeSeries{
Name: s.Name,
Tags: s.Tags,
Points: points,
})
}
mappedTables, err := tw.mapTables(r)
if err != nil {
return DataResponse{}, err
}
qr.Tables = mappedTables
res.Results[r.RefId] = qr
}
return res, nil
}
func (tw *DatasourcePluginWrapper) mapTables(r *datasource.QueryResult) ([]DataTable, error) {
var tables []DataTable
for _, t := range r.GetTables() {
mappedTable, err := tw.mapTable(t)
if err != nil {
return nil, err
}
tables = append(tables, mappedTable)
}
return tables, nil
}
func (tw *DatasourcePluginWrapper) mapTable(t *datasource.Table) (DataTable, error) {
table := DataTable{}
for _, c := range t.GetColumns() {
table.Columns = append(table.Columns, DataTableColumn{
Text: c.Name,
})
}
table.Rows = make([]DataRowValues, 0)
for _, r := range t.GetRows() {
row := DataRowValues{}
for _, rv := range r.Values {
mappedRw, err := tw.mapRowValue(rv)
if err != nil {
return table, err
}
row = append(row, mappedRw)
}
table.Rows = append(table.Rows, row)
}
return table, nil
}
func (tw *DatasourcePluginWrapper) mapRowValue(rv *datasource.RowValue) (interface{}, error) {
switch rv.Kind {
case datasource.RowValue_TYPE_NULL:
return nil, nil
case datasource.RowValue_TYPE_INT64:
return rv.Int64Value, nil
case datasource.RowValue_TYPE_BOOL:
return rv.BoolValue, nil
case datasource.RowValue_TYPE_STRING:
return rv.StringValue, nil
case datasource.RowValue_TYPE_DOUBLE:
return rv.DoubleValue, nil
case datasource.RowValue_TYPE_BYTES:
return rv.BytesValue, nil
default:
return nil, fmt.Errorf("unsupported row value %v from plugin", rv.Kind)
}
}

View File

@ -1,86 +0,0 @@
package plugins
import (
"testing"
"github.com/grafana/grafana-plugin-model/go/datasource"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/stretchr/testify/require"
)
func TestMapTables(t *testing.T) {
dpw := newDataSourcePluginWrapper(log.New("test-logger"), nil)
var qr = &datasource.QueryResult{}
qr.Tables = append(qr.Tables, &datasource.Table{
Columns: []*datasource.TableColumn{},
Rows: nil,
})
have, err := dpw.mapTables(qr)
require.NoError(t, err)
require.Len(t, have, 1)
}
func TestMapTable(t *testing.T) {
dpw := newDataSourcePluginWrapper(log.New("test-logger"), nil)
source := &datasource.Table{
Columns: []*datasource.TableColumn{{Name: "column1"}, {Name: "column2"}},
Rows: []*datasource.TableRow{{
Values: []*datasource.RowValue{
{
Kind: datasource.RowValue_TYPE_BOOL,
BoolValue: true,
},
{
Kind: datasource.RowValue_TYPE_INT64,
Int64Value: 42,
},
},
}},
}
want := DataTable{
Columns: []DataTableColumn{{Text: "column1"}, {Text: "column2"}},
}
have, err := dpw.mapTable(source)
require.NoError(t, err)
require.Equal(t, want.Columns, have.Columns)
require.Len(t, have.Rows, 1)
require.Len(t, have.Rows[0], 2)
}
func TestMappingRowValue(t *testing.T) {
dpw := newDataSourcePluginWrapper(log.New("test-logger"), nil)
boolRowValue, err := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_BOOL, BoolValue: true})
require.NoError(t, err)
haveBool, ok := boolRowValue.(bool)
require.True(t, ok)
require.True(t, haveBool)
intRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_INT64, Int64Value: 42})
haveInt, ok := intRowValue.(int64)
require.True(t, ok)
require.Equal(t, int64(42), haveInt)
stringRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_STRING, StringValue: "grafana"})
haveString, ok := stringRowValue.(string)
require.True(t, ok)
require.Equal(t, "grafana", haveString)
doubleRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_DOUBLE, DoubleValue: 1.5})
haveDouble, ok := doubleRowValue.(float64)
require.True(t, ok)
require.Equal(t, 1.5, haveDouble)
bytesRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_BYTES, BytesValue: []byte{66}})
haveBytes, ok := bytesRowValue.([]byte)
require.True(t, ok)
require.Equal(t, []byte{66}, haveBytes)
haveNil, err := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_NULL})
require.NoError(t, err)
require.Nil(t, haveNil)
}

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"path/filepath" "path/filepath"
pluginModel "github.com/grafana/grafana-plugin-model/go/renderer"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/grpcplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin/grpcplugin"
@ -17,7 +16,6 @@ type RendererPlugin struct {
FrontendPluginBase FrontendPluginBase
Executable string `json:"executable,omitempty"` Executable string `json:"executable,omitempty"`
GrpcPluginV1 pluginModel.RendererPlugin
GrpcPluginV2 pluginextensionv2.RendererPlugin GrpcPluginV2 pluginextensionv2.RendererPlugin
backendPluginManager backendplugin.Manager backendPluginManager backendplugin.Manager
} }
@ -33,7 +31,6 @@ func (r *RendererPlugin) Load(decoder *json.Decoder, base *PluginBase,
cmd := ComposePluginStartCommand("plugin_start") cmd := ComposePluginStartCommand("plugin_start")
fullpath := filepath.Join(base.PluginDir, cmd) fullpath := filepath.Join(base.PluginDir, cmd)
factory := grpcplugin.NewRendererPlugin(r.Id, fullpath, grpcplugin.PluginStartFuncs{ factory := grpcplugin.NewRendererPlugin(r.Id, fullpath, grpcplugin.PluginStartFuncs{
OnLegacyStart: r.onLegacyPluginStart,
OnStart: r.onPluginStart, OnStart: r.onPluginStart,
}) })
if err := backendPluginManager.Register(r.Id, factory); err != nil { if err := backendPluginManager.Register(r.Id, factory); err != nil {
@ -51,11 +48,6 @@ func (r *RendererPlugin) Start(ctx context.Context) error {
return nil return nil
} }
func (r *RendererPlugin) onLegacyPluginStart(pluginID string, client *grpcplugin.LegacyClient, logger log.Logger) error {
r.GrpcPluginV1 = client.RendererPlugin
return nil
}
func (r *RendererPlugin) onPluginStart(pluginID string, client *grpcplugin.Client, logger log.Logger) error { func (r *RendererPlugin) onPluginStart(pluginID string, client *grpcplugin.Client, logger log.Logger) error {
r.GrpcPluginV2 = client.RendererPlugin r.GrpcPluginV2 = client.RendererPlugin
return nil return nil

View File

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"time" "time"
pluginModel "github.com/grafana/grafana-plugin-model/go/renderer"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2" "github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
) )
@ -19,48 +18,6 @@ func (rs *RenderingService) renderViaPlugin(ctx context.Context, renderKey strin
ctx, cancel := context.WithTimeout(ctx, opts.Timeout+time.Second*2) ctx, cancel := context.WithTimeout(ctx, opts.Timeout+time.Second*2)
defer cancel() defer cancel()
if rs.pluginInfo.GrpcPluginV2 != nil {
return rs.renderViaPluginV2(ctx, renderKey, opts)
}
return rs.renderViaPluginV1(ctx, renderKey, opts)
}
func (rs *RenderingService) renderViaPluginV1(ctx context.Context, renderKey string, opts Opts) (*RenderResult, error) {
filePath, err := rs.getNewFilePath(RenderPNG)
if err != nil {
return nil, err
}
req := &pluginModel.RenderRequest{
Url: rs.getURL(opts.Path),
Width: int32(opts.Width),
Height: int32(opts.Height),
FilePath: filePath,
Timeout: int32(opts.Timeout.Seconds()),
RenderKey: renderKey,
Encoding: opts.Encoding,
Timezone: isoTimeOffsetToPosixTz(opts.Timezone),
Domain: rs.domain,
}
rs.log.Debug("calling renderer plugin", "req", req)
rsp, err := rs.pluginInfo.GrpcPluginV1.Render(ctx, req)
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
rs.log.Info("Rendering timed out")
return nil, ErrTimeout
}
if err != nil {
return nil, err
}
if rsp.Error != "" {
return nil, fmt.Errorf("rendering failed: %v", rsp.Error)
}
return &RenderResult{FilePath: filePath}, nil
}
func (rs *RenderingService) renderViaPluginV2(ctx context.Context, renderKey string, opts Opts) (*RenderResult, error) {
filePath, err := rs.getNewFilePath(RenderPNG) filePath, err := rs.getNewFilePath(RenderPNG)
if err != nil { if err != nil {
return nil, err return nil, err