Commit 8f9e5a83 by Arve Knudsen Committed by GitHub

Plugins: Bring back coreplugin package (#29064)

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
parent 18f3969f
package coreplugin
import (
"context"
"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/backendplugin"
"github.com/grafana/grafana/pkg/tsdb"
)
// corePlugin represents a plugin that's part of Grafana core.
// nolint:unused
type corePlugin struct {
pluginID string
logger log.Logger
backend.CheckHealthHandler
backend.CallResourceHandler
backend.QueryDataHandler
}
// New returns a new backendplugin.PluginFactoryFunc for creating a core (built-in) backendplugin.Plugin.
func New(opts backend.ServeOpts) backendplugin.PluginFactoryFunc {
return backendplugin.PluginFactoryFunc(func(pluginID string, logger log.Logger, env []string) (backendplugin.Plugin, error) {
return &corePlugin{
pluginID: pluginID,
logger: logger,
CheckHealthHandler: opts.CheckHealthHandler,
CallResourceHandler: opts.CallResourceHandler,
QueryDataHandler: opts.QueryDataHandler,
}, nil
})
}
func (cp *corePlugin) PluginID() string {
return cp.pluginID
}
func (cp *corePlugin) Logger() log.Logger {
return cp.logger
}
func (cp *corePlugin) Start(ctx context.Context) error {
if cp.QueryDataHandler != nil {
tsdb.RegisterTsdbQueryEndpoint(cp.pluginID, func(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
return newQueryEndpointAdapter(cp.pluginID, cp.logger, backendplugin.InstrumentQueryDataHandler(cp.QueryDataHandler)), nil
})
}
return nil
}
func (cp *corePlugin) Stop(ctx context.Context) error {
return nil
}
func (cp *corePlugin) IsManaged() bool {
return false
}
func (cp *corePlugin) Exited() bool {
return false
}
func (cp *corePlugin) CollectMetrics(ctx context.Context) (*backend.CollectMetricsResult, error) {
return nil, backendplugin.ErrMethodNotImplemented
}
func (cp *corePlugin) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
if cp.CheckHealthHandler != nil {
return cp.CheckHealthHandler.CheckHealth(ctx, req)
}
return nil, backendplugin.ErrMethodNotImplemented
}
func (cp *corePlugin) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if cp.CallResourceHandler != nil {
return cp.CallResourceHandler.CallResource(ctx, req, sender)
}
return backendplugin.ErrMethodNotImplemented
}
package coreplugin_test
import (
"context"
"testing"
"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/coreplugin"
"github.com/stretchr/testify/require"
)
func TestCorePlugin(t *testing.T) {
t.Run("New core plugin with empty opts should return expected values", func(t *testing.T) {
factory := coreplugin.New(backend.ServeOpts{})
p, err := factory("plugin", log.New("test"), nil)
require.NoError(t, err)
require.NotNil(t, p)
require.NoError(t, p.Start(context.Background()))
require.NoError(t, p.Stop(context.Background()))
require.False(t, p.IsManaged())
require.False(t, p.Exited())
_, err = p.CollectMetrics(context.Background())
require.Equal(t, backendplugin.ErrMethodNotImplemented, err)
_, err = p.CheckHealth(context.Background(), nil)
require.Equal(t, backendplugin.ErrMethodNotImplemented, err)
err = p.CallResource(context.Background(), nil, nil)
require.Equal(t, backendplugin.ErrMethodNotImplemented, err)
})
t.Run("New core plugin with handlers set in opts should return expected values", func(t *testing.T) {
checkHealthCalled := false
callResourceCalled := false
factory := coreplugin.New(backend.ServeOpts{
CheckHealthHandler: backend.CheckHealthHandlerFunc(func(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
checkHealthCalled = true
return nil, nil
}),
CallResourceHandler: backend.CallResourceHandlerFunc(func(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
callResourceCalled = true
return nil
}),
})
p, err := factory("plugin", log.New("test"), nil)
require.NoError(t, err)
require.NotNil(t, p)
require.NoError(t, p.Start(context.Background()))
require.NoError(t, p.Stop(context.Background()))
require.False(t, p.IsManaged())
require.False(t, p.Exited())
_, err = p.CollectMetrics(context.Background())
require.Equal(t, backendplugin.ErrMethodNotImplemented, err)
_, err = p.CheckHealth(context.Background(), &backend.CheckHealthRequest{})
require.NoError(t, err)
require.True(t, checkHealthCalled)
err = p.CallResource(context.Background(), &backend.CallResourceRequest{}, nil)
require.NoError(t, err)
require.True(t, callResourceCalled)
})
}
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/datasource/wrapper"
"github.com/grafana/grafana/pkg/tsdb"
)
func newQueryEndpointAdapter(pluginID string, logger log.Logger, handler backend.QueryDataHandler) tsdb.TsdbQueryEndpoint {
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
}
func (a *queryEndpointAdapter) Query(ctx context.Context, ds *models.DataSource, query *tsdb.TsdbQuery) (*tsdb.Response, error) {
instanceSettings, err := modelToInstanceSettings(ds)
if err != nil {
return nil, err
}
req := &backend.QueryDataRequest{
PluginContext: backend.PluginContext{
OrgID: ds.OrgId,
PluginID: a.pluginID,
User: wrapper.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 nil, 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 nil, err
}
tR := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult, len(resp.Responses)),
}
for refID, r := range resp.Responses {
qr := &tsdb.QueryResult{
RefId: refID,
}
for _, f := range r.Frames {
if f.RefID == "" {
f.RefID = refID
}
}
qr.Dataframes = tsdb.NewDecodedDataFrames(r.Frames)
if r.Error != nil {
qr.Error = r.Error
}
tR.Results[refID] = qr
}
return tR, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment