mirror of https://github.com/grafana/grafana.git
				
				
				
			Plugins: Bring back coreplugin package (#29064)
Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
		
							parent
							
								
									18f3969fdb
								
							
						
					
					
						commit
						8f9e5a839f
					
				|  | @ -0,0 +1,83 @@ | |||
| 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 | ||||
| } | ||||
|  | @ -0,0 +1,67 @@ | |||
| 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) | ||||
| 	}) | ||||
| } | ||||
|  | @ -0,0 +1,113 @@ | |||
| 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 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue