mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
5042dc3b52
commit
1e8e7e34f1
1
go.mod
1
go.mod
@ -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
4
go.sum
@ -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=
|
||||||
|
@ -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,16 +38,12 @@ 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PluginDescriptor is a descriptor used for registering backend plugins.
|
// PluginDescriptor is a descriptor used for registering backend plugins.
|
||||||
@ -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
|
||||||
|
@ -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
|
|
||||||
})
|
|
||||||
}
|
|
@ -59,16 +59,12 @@ func (p *grpcPlugin) Start(ctx context.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.client.NegotiatedVersion() > 1 {
|
if p.client.NegotiatedVersion() < 2 {
|
||||||
p.pluginClient, err = newClientV2(p.descriptor, p.logger, rpcClient)
|
return errors.New("plugin protocol version not supported")
|
||||||
if err != nil {
|
}
|
||||||
return err
|
p.pluginClient, err = newClientV2(p.descriptor, p.logger, rpcClient)
|
||||||
}
|
if err != nil {
|
||||||
} else {
|
return err
|
||||||
p.pluginClient, err = newClientV1(p.descriptor, p.logger, rpcClient)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.pluginClient == nil {
|
if p.pluginClient == nil {
|
||||||
|
@ -33,9 +33,8 @@ type DataSourcePlugin struct {
|
|||||||
Executable string `json:"executable,omitempty"`
|
Executable string `json:"executable,omitempty"`
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DataSourcePlugin) Load(decoder *json.Decoder, base *PluginBase, backendPluginManager backendplugin.Manager) (
|
func (p *DataSourcePlugin) Load(decoder *json.Decoder, base *PluginBase, backendPluginManager backendplugin.Manager) (
|
||||||
@ -48,8 +47,7 @@ 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 {
|
||||||
return nil, errutil.Wrapf(err, "failed to register backend plugin")
|
return nil, errutil.Wrapf(err, "failed to register backend plugin")
|
||||||
@ -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)
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoint := newDataSourcePluginWrapper(p.logger, p.legacyClient.DatasourcePlugin)
|
|
||||||
return endpoint.Query(ctx, dsInfo, query)
|
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 {
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
@ -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,8 +31,7 @@ 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 {
|
||||||
return nil, errutil.Wrapf(err, "failed to register backend plugin")
|
return nil, errutil.Wrapf(err, "failed to register backend plugin")
|
||||||
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user