mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s/DataSource: Introduce PluginConfigProvider (#80928)
This commit is contained in:
parent
ce84f7c540
commit
c7c594dba0
@ -20,9 +20,10 @@ var (
|
||||
)
|
||||
|
||||
type connectionAccess struct {
|
||||
pluginID string
|
||||
resourceInfo common.ResourceInfo
|
||||
tableConverter rest.TableConvertor
|
||||
builder Querier
|
||||
configs PluginConfigProvider
|
||||
}
|
||||
|
||||
func (s *connectionAccess) New() runtime.Object {
|
||||
@ -52,9 +53,9 @@ func (s *connectionAccess) ConvertToTable(ctx context.Context, object runtime.Ob
|
||||
}
|
||||
|
||||
func (s *connectionAccess) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return s.builder.Datasource(ctx, name)
|
||||
return s.configs.GetDataSource(ctx, s.pluginID, name)
|
||||
}
|
||||
|
||||
func (s *connectionAccess) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
|
||||
return s.builder.Datasources(ctx)
|
||||
return s.configs.ListDatasources(ctx, s.pluginID)
|
||||
}
|
||||
|
@ -2,10 +2,122 @@ package datasource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/infra/appcontext"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
)
|
||||
|
||||
type PluginContextProvider interface {
|
||||
PluginContextForDataSource(ctx context.Context, pluginID, name string) (backend.PluginContext, error)
|
||||
// This provides access to settings saved in the database.
|
||||
// Authorization checks will happen within each function, and the user in ctx will
|
||||
// limit which namespace/tenant/org we are talking to
|
||||
type PluginConfigProvider interface {
|
||||
// GetDataSource gets a specific datasource (that the user in context can see)
|
||||
GetDataSource(ctx context.Context, pluginID, uid string) (*v0alpha1.DataSourceConnection, error)
|
||||
|
||||
// ListDatasources lists all data sources the user in context can see
|
||||
ListDatasources(ctx context.Context, pluginID string) (*v0alpha1.DataSourceConnectionList, error)
|
||||
|
||||
// Return settings (decrypted!) for a specific plugin
|
||||
// This will require "query" permission for the user in context
|
||||
GetDataSourceInstanceSettings(ctx context.Context, pluginID, uid string) (*backend.DataSourceInstanceSettings, error)
|
||||
}
|
||||
|
||||
// PluginContext requires adding system settings (feature flags, etc) to the datasource config
|
||||
type PluginContextWrapper interface {
|
||||
PluginContextForDataSource(ctx context.Context, datasourceSettings *backend.DataSourceInstanceSettings) (backend.PluginContext, error)
|
||||
}
|
||||
|
||||
func ProvideDefaultPluginConfigs(
|
||||
dsService datasources.DataSourceService,
|
||||
dsCache datasources.CacheService,
|
||||
contextProvider *plugincontext.Provider) PluginConfigProvider {
|
||||
return &defaultPluginConfigProvider{
|
||||
dsService: dsService,
|
||||
dsCache: dsCache,
|
||||
contextProvider: contextProvider,
|
||||
}
|
||||
}
|
||||
|
||||
type defaultPluginConfigProvider struct {
|
||||
dsService datasources.DataSourceService
|
||||
dsCache datasources.CacheService
|
||||
contextProvider *plugincontext.Provider
|
||||
}
|
||||
|
||||
var (
|
||||
_ PluginConfigProvider = (*defaultPluginConfigProvider)(nil)
|
||||
)
|
||||
|
||||
func (q *defaultPluginConfigProvider) GetDataSource(ctx context.Context, pluginID, uid string) (*v0alpha1.DataSourceConnection, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := appcontext.User(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := q.dsCache.GetDatasourceByUID(ctx, uid, user, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asConnection(ds, info.Value)
|
||||
}
|
||||
|
||||
func (q *defaultPluginConfigProvider) ListDatasources(ctx context.Context, pluginID string) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dss, err := q.dsService.GetDataSourcesByType(ctx, &datasources.GetDataSourcesByTypeQuery{
|
||||
OrgID: info.OrgID,
|
||||
Type: pluginID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &v0alpha1.DataSourceConnectionList{
|
||||
Items: []v0alpha1.DataSourceConnection{},
|
||||
}
|
||||
for _, ds := range dss {
|
||||
v, _ := asConnection(ds, info.Value)
|
||||
result.Items = append(result.Items, *v)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (q *defaultPluginConfigProvider) GetDataSourceInstanceSettings(ctx context.Context, pluginID, uid string) (*backend.DataSourceInstanceSettings, error) {
|
||||
if q.contextProvider == nil {
|
||||
// NOTE!!! this is only here for the standalone example
|
||||
// if we cleanup imports this can throw an error
|
||||
return nil, nil
|
||||
}
|
||||
return q.contextProvider.GetDataSourceInstanceSettings(ctx, uid)
|
||||
}
|
||||
|
||||
func asConnection(ds *datasources.DataSource, ns string) (*v0alpha1.DataSourceConnection, error) {
|
||||
v := &v0alpha1.DataSourceConnection{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ds.UID,
|
||||
Namespace: ns,
|
||||
CreationTimestamp: metav1.NewTime(ds.Created),
|
||||
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
||||
},
|
||||
Title: ds.Name,
|
||||
}
|
||||
v.UID = utils.CalculateClusterWideUID(v) // indicates if the value changed on the server
|
||||
meta, err := utils.MetaAccessor(v)
|
||||
if err != nil {
|
||||
meta.SetUpdatedTimestamp(&ds.Updated)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
|
@ -1,169 +0,0 @@
|
||||
package datasource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/infra/appcontext"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
|
||||
)
|
||||
|
||||
type QuerierFactoryFunc func(ctx context.Context, ri common.ResourceInfo, pj plugins.JSONData) (Querier, error)
|
||||
|
||||
type QuerierProvider interface {
|
||||
Querier(ctx context.Context, ri common.ResourceInfo, pj plugins.JSONData) (Querier, error)
|
||||
}
|
||||
|
||||
type DefaultQuerierProvider struct {
|
||||
factory QuerierFactoryFunc
|
||||
}
|
||||
|
||||
func ProvideDefaultQuerierProvider(pluginClient plugins.Client, dsService datasources.DataSourceService,
|
||||
dsCache datasources.CacheService) *DefaultQuerierProvider {
|
||||
return NewQuerierProvider(func(ctx context.Context, ri common.ResourceInfo, pj plugins.JSONData) (Querier, error) {
|
||||
return NewDefaultQuerier(ri, pj, pluginClient, dsService, dsCache), nil
|
||||
})
|
||||
}
|
||||
|
||||
func NewQuerierProvider(factory QuerierFactoryFunc) *DefaultQuerierProvider {
|
||||
return &DefaultQuerierProvider{
|
||||
factory: factory,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *DefaultQuerierProvider) Querier(ctx context.Context, ri common.ResourceInfo, pj plugins.JSONData) (Querier, error) {
|
||||
return p.factory(ctx, ri, pj)
|
||||
}
|
||||
|
||||
// Querier is the interface that wraps the Query method.
|
||||
type Querier interface {
|
||||
// Query runs the query on behalf of the user in context.
|
||||
Query(ctx context.Context, query *backend.QueryDataRequest) (*backend.QueryDataResponse, error)
|
||||
// Health checks the health of the plugin.
|
||||
Health(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error)
|
||||
// Resource gets a resource plugin.
|
||||
Resource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error
|
||||
// Datasource gets all data source plugins (with elevated permissions).
|
||||
Datasource(ctx context.Context, name string) (*v0alpha1.DataSourceConnection, error)
|
||||
// Datasources lists all data sources (with elevated permissions).
|
||||
Datasources(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error)
|
||||
}
|
||||
|
||||
type DefaultQuerier struct {
|
||||
connectionResourceInfo common.ResourceInfo
|
||||
pluginJSON plugins.JSONData
|
||||
pluginClient plugins.Client
|
||||
dsService datasources.DataSourceService
|
||||
dsCache datasources.CacheService
|
||||
}
|
||||
|
||||
func NewDefaultQuerier(
|
||||
connectionResourceInfo common.ResourceInfo,
|
||||
pluginJSON plugins.JSONData,
|
||||
pluginClient plugins.Client,
|
||||
dsService datasources.DataSourceService,
|
||||
dsCache datasources.CacheService,
|
||||
) *DefaultQuerier {
|
||||
return &DefaultQuerier{
|
||||
connectionResourceInfo: connectionResourceInfo,
|
||||
pluginJSON: pluginJSON,
|
||||
pluginClient: pluginClient,
|
||||
dsService: dsService,
|
||||
dsCache: dsCache,
|
||||
}
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Query(ctx context.Context, query *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
_, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q.pluginClient.QueryData(ctx, query)
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Resource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
||||
_, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return q.pluginClient.CallResource(ctx, req, sender)
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Health(ctx context.Context, query *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||
_, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q.pluginClient.CheckHealth(ctx, query)
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Datasource(ctx context.Context, name string) (*v0alpha1.DataSourceConnection, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := appcontext.User(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := q.dsCache.GetDatasourceByUID(ctx, name, user, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asConnection(q.connectionResourceInfo.TypeMeta(), ds, info.Value)
|
||||
}
|
||||
|
||||
func (q *DefaultQuerier) Datasources(ctx context.Context) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds, err := q.dsService.GetDataSourcesByType(ctx, &datasources.GetDataSourcesByTypeQuery{
|
||||
OrgID: info.OrgID,
|
||||
Type: q.pluginJSON.ID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asConnectionList(q.connectionResourceInfo.TypeMeta(), ds, info.Value)
|
||||
}
|
||||
|
||||
func asConnection(typeMeta metav1.TypeMeta, ds *datasources.DataSource, ns string) (*v0alpha1.DataSourceConnection, error) {
|
||||
v := &v0alpha1.DataSourceConnection{
|
||||
TypeMeta: typeMeta,
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ds.UID,
|
||||
Namespace: ns,
|
||||
CreationTimestamp: metav1.NewTime(ds.Created),
|
||||
ResourceVersion: fmt.Sprintf("%d", ds.Updated.UnixMilli()),
|
||||
},
|
||||
Title: ds.Name,
|
||||
}
|
||||
v.UID = utils.CalculateClusterWideUID(v) // indicates if the value changed on the server
|
||||
meta, err := utils.MetaAccessor(v)
|
||||
if err != nil {
|
||||
meta.SetUpdatedTimestamp(&ds.Updated)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
|
||||
func asConnectionList(typeMeta metav1.TypeMeta, dss []*datasources.DataSource, ns string) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
result := &v0alpha1.DataSourceConnectionList{
|
||||
Items: []v0alpha1.DataSourceConnection{},
|
||||
}
|
||||
for _, ds := range dss {
|
||||
v, _ := asConnection(typeMeta, ds, ns)
|
||||
result.Items = append(result.Items, *v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
@ -16,6 +16,8 @@ import (
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@ -33,16 +35,18 @@ type DataSourceAPIBuilder struct {
|
||||
connectionResourceInfo common.ResourceInfo
|
||||
|
||||
pluginJSON plugins.JSONData
|
||||
querier Querier
|
||||
pluginContext PluginContextProvider
|
||||
client plugins.Client // will only ever be called with the same pluginid!
|
||||
pluginsConfig PluginConfigProvider
|
||||
contextProvider PluginContextWrapper
|
||||
accessControl accesscontrol.AccessControl
|
||||
}
|
||||
|
||||
func RegisterAPIService(
|
||||
querierProvider QuerierProvider,
|
||||
features featuremgmt.FeatureToggles,
|
||||
apiRegistrar grafanaapiserver.APIRegistrar,
|
||||
pluginContext PluginContextProvider,
|
||||
pluginClient plugins.Client, // access to everything
|
||||
pluginConfigs PluginConfigProvider,
|
||||
contextProvider PluginContextWrapper,
|
||||
pluginStore pluginstore.Store,
|
||||
accessControl accesscontrol.AccessControl,
|
||||
) (*DataSourceAPIBuilder, error) {
|
||||
@ -63,7 +67,12 @@ func RegisterAPIService(
|
||||
continue // skip this one
|
||||
}
|
||||
|
||||
builder, err = NewDataSourceAPIBuilder(ds.JSONData, querierProvider, pluginContext, accessControl)
|
||||
builder, err = NewDataSourceAPIBuilder(ds.JSONData,
|
||||
pluginClient,
|
||||
pluginConfigs,
|
||||
contextProvider,
|
||||
accessControl,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -74,24 +83,21 @@ func RegisterAPIService(
|
||||
|
||||
func NewDataSourceAPIBuilder(
|
||||
plugin plugins.JSONData,
|
||||
querierProvider QuerierProvider,
|
||||
pluginContext PluginContextProvider,
|
||||
client plugins.Client,
|
||||
pluginsConfig PluginConfigProvider,
|
||||
contextProvider PluginContextWrapper,
|
||||
accessControl accesscontrol.AccessControl) (*DataSourceAPIBuilder, error) {
|
||||
ri, err := resourceFromPluginID(plugin.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
querier, err := querierProvider.Querier(context.Background(), ri, plugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DataSourceAPIBuilder{
|
||||
connectionResourceInfo: ri,
|
||||
pluginJSON: plugin,
|
||||
querier: querier,
|
||||
pluginContext: pluginContext,
|
||||
client: client,
|
||||
pluginsConfig: pluginsConfig,
|
||||
contextProvider: contextProvider,
|
||||
accessControl: accessControl,
|
||||
}, nil
|
||||
}
|
||||
@ -148,7 +154,8 @@ func (b *DataSourceAPIBuilder) GetAPIGroupInfo(
|
||||
|
||||
conn := b.connectionResourceInfo
|
||||
storage[conn.StoragePath()] = &connectionAccess{
|
||||
builder: b.querier,
|
||||
pluginID: b.pluginJSON.ID,
|
||||
configs: b.pluginsConfig,
|
||||
resourceInfo: conn,
|
||||
tableConverter: utils.NewTableConverter(
|
||||
conn.GroupResource(),
|
||||
@ -191,6 +198,14 @@ func (b *DataSourceAPIBuilder) GetAPIGroupInfo(
|
||||
return &apiGroupInfo, nil
|
||||
}
|
||||
|
||||
func (b *DataSourceAPIBuilder) getPluginContext(ctx context.Context, uid string) (backend.PluginContext, error) {
|
||||
instance, err := b.pluginsConfig.GetDataSourceInstanceSettings(ctx, b.pluginJSON.ID, uid)
|
||||
if err != nil {
|
||||
return backend.PluginContext{}, err
|
||||
}
|
||||
return b.contextProvider.PluginContextForDataSource(ctx, instance)
|
||||
}
|
||||
|
||||
func (b *DataSourceAPIBuilder) GetOpenAPIDefinitions() openapi.GetOpenAPIDefinitions {
|
||||
return v0alpha1.GetOpenAPIDefinitions
|
||||
}
|
||||
|
@ -5,9 +5,12 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource"
|
||||
)
|
||||
@ -21,6 +24,22 @@ func NewTestDataAPIServer(group string) (*DataSourceAPIBuilder, error) {
|
||||
return nil, fmt.Errorf("only %s is currently supported", pluginID)
|
||||
}
|
||||
|
||||
// Run standalone with zero dependencies
|
||||
if true {
|
||||
return NewDataSourceAPIBuilder(
|
||||
plugins.JSONData{
|
||||
ID: pluginID,
|
||||
},
|
||||
testdatasource.ProvideService(), // the client
|
||||
&testdataPluginConfigProvider{
|
||||
startup: v1.Now(),
|
||||
},
|
||||
&testdataPluginConfigProvider{}, // stub
|
||||
&actest.FakeAccessControl{ExpectedEvaluate: true},
|
||||
)
|
||||
}
|
||||
|
||||
// Otherwise manually wire up access to testdata
|
||||
cfg, err := setting.NewCfgFromArgs(setting.CommandLineArgs{
|
||||
// TODO: Add support for args?
|
||||
})
|
||||
@ -37,21 +56,69 @@ func NewTestDataAPIServer(group string) (*DataSourceAPIBuilder, error) {
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("plugin %s not found", pluginID)
|
||||
}
|
||||
|
||||
var testsDataQuerierFactory QuerierFactoryFunc = func(ctx context.Context, ri common.ResourceInfo, pj plugins.JSONData) (Querier, error) {
|
||||
return NewDefaultQuerier(ri, td.JSONData, testdatasource.ProvideService(), dsService, dsCache), nil
|
||||
}
|
||||
|
||||
return NewDataSourceAPIBuilder(
|
||||
td.JSONData,
|
||||
NewQuerierProvider(testsDataQuerierFactory),
|
||||
&TestDataPluginContextProvider{},
|
||||
testdatasource.ProvideService(), // the client
|
||||
&defaultPluginConfigProvider{
|
||||
dsService: dsService,
|
||||
dsCache: dsCache,
|
||||
},
|
||||
&testdataPluginConfigProvider{}, // stub
|
||||
accessControl,
|
||||
)
|
||||
}
|
||||
|
||||
type TestDataPluginContextProvider struct{}
|
||||
|
||||
func (p *TestDataPluginContextProvider) PluginContextForDataSource(_ context.Context, _, _ string) (backend.PluginContext, error) {
|
||||
return backend.PluginContext{}, nil
|
||||
// Simple stub for standalone testing
|
||||
type testdataPluginConfigProvider struct {
|
||||
startup v1.Time
|
||||
}
|
||||
|
||||
var (
|
||||
_ PluginConfigProvider = (*testdataPluginConfigProvider)(nil)
|
||||
)
|
||||
|
||||
// GetDataSource implements PluginConfigProvider.
|
||||
func (p *testdataPluginConfigProvider) GetDataSource(ctx context.Context, pluginID string, uid string) (*v0alpha1.DataSourceConnection, error) {
|
||||
all, err := p.ListDatasources(ctx, pluginID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for idx, v := range all.Items {
|
||||
if v.Name == uid {
|
||||
return &all.Items[idx], nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
// ListDatasources implements PluginConfigProvider.
|
||||
func (p *testdataPluginConfigProvider) ListDatasources(ctx context.Context, pluginID string) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v0alpha1.DataSourceConnectionList{
|
||||
TypeMeta: v0alpha1.GenericConnectionResourceInfo.TypeMeta(),
|
||||
Items: []v0alpha1.DataSourceConnection{
|
||||
{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "PD8C576611E62080A",
|
||||
Namespace: info.Value, // the raw namespace value
|
||||
CreationTimestamp: p.startup,
|
||||
},
|
||||
Title: "gdev-testdata",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PluginContextForDataSource implements PluginConfigProvider.
|
||||
func (*testdataPluginConfigProvider) GetDataSourceInstanceSettings(ctx context.Context, pluginID, uid string) (*backend.DataSourceInstanceSettings, error) {
|
||||
return &backend.DataSourceInstanceSettings{}, nil
|
||||
}
|
||||
|
||||
// PluginContextWrapper
|
||||
func (*testdataPluginConfigProvider) PluginContextForDataSource(ctx context.Context, datasourceSettings *backend.DataSourceInstanceSettings) (backend.PluginContext, error) {
|
||||
return backend.PluginContext{DataSourceInstanceSettings: datasourceSettings}, nil
|
||||
}
|
||||
|
@ -35,13 +35,13 @@ func (r *subHealthREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
|
||||
func (r *subHealthREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
pluginCtx, err := r.builder.pluginContext.PluginContextForDataSource(ctx, r.builder.pluginJSON.ID, name)
|
||||
pluginCtx, err := r.builder.getPluginContext(ctx, name)
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
healthResponse, err := r.builder.querier.Health(ctx, &backend.CheckHealthRequest{
|
||||
healthResponse, err := r.builder.client.CheckHealth(ctx, &backend.CheckHealthRequest{
|
||||
PluginContext: pluginCtx,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -71,7 +71,7 @@ func (r *subQueryREST) readQueries(req *http.Request) ([]backend.DataQuery, erro
|
||||
}
|
||||
|
||||
func (r *subQueryREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
pluginCtx, err := r.builder.pluginContext.PluginContextForDataSource(ctx, r.builder.pluginJSON.ID, name)
|
||||
pluginCtx, err := r.builder.getPluginContext(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -83,7 +83,7 @@ func (r *subQueryREST) Connect(ctx context.Context, name string, opts runtime.Ob
|
||||
return
|
||||
}
|
||||
|
||||
queryResponse, err := r.builder.querier.Query(ctx, &backend.QueryDataRequest{
|
||||
queryResponse, err := r.builder.client.QueryData(ctx, &backend.QueryDataRequest{
|
||||
PluginContext: pluginCtx,
|
||||
Queries: queries,
|
||||
// Headers: // from context
|
||||
|
@ -46,7 +46,7 @@ func (r *subResourceREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
}
|
||||
|
||||
func (r *subResourceREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
pluginCtx, err := r.builder.pluginContext.PluginContextForDataSource(ctx, r.builder.pluginJSON.ID, name)
|
||||
pluginCtx, err := r.builder.getPluginContext(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -65,7 +65,7 @@ func (r *subResourceREST) Connect(ctx context.Context, name string, opts runtime
|
||||
}
|
||||
|
||||
path := req.URL.Path[idx+len("/resource"):]
|
||||
err = r.builder.querier.Resource(ctx, &backend.CallResourceRequest{
|
||||
err = r.builder.client.CallResource(ctx, &backend.CallResourceRequest{
|
||||
PluginContext: pluginCtx,
|
||||
Path: path,
|
||||
Method: req.Method,
|
||||
|
@ -15,10 +15,10 @@ import (
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideRegistryServiceSink, // dummy background service that forces registration
|
||||
|
||||
wire.Bind(new(datasource.QuerierProvider), new(*datasource.DefaultQuerierProvider)),
|
||||
datasource.ProvideDefaultQuerierProvider,
|
||||
// read-only datasource abstractions
|
||||
plugincontext.ProvideService,
|
||||
wire.Bind(new(datasource.PluginContextProvider), new(*plugincontext.Provider)),
|
||||
wire.Bind(new(datasource.PluginContextWrapper), new(*plugincontext.Provider)),
|
||||
datasource.ProvideDefaultPluginConfigs,
|
||||
|
||||
// Each must be added here *and* in the ServiceSink above
|
||||
playlist.RegisterAPIService,
|
||||
|
@ -132,9 +132,22 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
|
||||
return pCtx, nil
|
||||
}
|
||||
|
||||
func (p *Provider) GetDataSourceInstanceSettings(ctx context.Context, uid string) (*backend.DataSourceInstanceSettings, error) {
|
||||
user, err := appcontext.User(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds, err := p.dataSourceCache.GetDatasourceByUID(ctx, uid, user, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adapters.ModelToInstanceSettings(ds, p.decryptSecureJsonDataFn(ctx))
|
||||
}
|
||||
|
||||
// PluginContextForDataSource will retrieve plugin context by the provided pluginID and datasource UID / K8s name.
|
||||
// This is intended to be used for datasource API server plugin requests.
|
||||
func (p *Provider) PluginContextForDataSource(ctx context.Context, pluginID, name string) (backend.PluginContext, error) {
|
||||
func (p *Provider) PluginContextForDataSource(ctx context.Context, datasourceSettings *backend.DataSourceInstanceSettings) (backend.PluginContext, error) {
|
||||
pluginID := datasourceSettings.Type
|
||||
plugin, exists := p.pluginStore.Plugin(ctx, pluginID)
|
||||
if !exists {
|
||||
return backend.PluginContext{}, plugins.ErrPluginNotRegistered
|
||||
@ -144,11 +157,6 @@ func (p *Provider) PluginContextForDataSource(ctx context.Context, pluginID, nam
|
||||
if err != nil {
|
||||
return backend.PluginContext{}, err
|
||||
}
|
||||
ds, err := p.dataSourceCache.GetDatasourceByUID(ctx, name, user, false)
|
||||
if err != nil {
|
||||
return backend.PluginContext{}, err
|
||||
}
|
||||
|
||||
pCtx := backend.PluginContext{
|
||||
PluginID: plugin.ID,
|
||||
PluginVersion: plugin.Info.Version,
|
||||
@ -158,10 +166,6 @@ func (p *Provider) PluginContextForDataSource(ctx context.Context, pluginID, nam
|
||||
pCtx.User = adapters.BackendUserFromSignedInUser(user)
|
||||
}
|
||||
|
||||
datasourceSettings, err := adapters.ModelToInstanceSettings(ds, p.decryptSecureJsonDataFn(ctx))
|
||||
if err != nil {
|
||||
return pCtx, err
|
||||
}
|
||||
pCtx.DataSourceInstanceSettings = datasourceSettings
|
||||
|
||||
settings := p.pluginEnvVars.GetConfigMap(ctx, pluginID, plugin.ExternalService)
|
||||
|
Loading…
Reference in New Issue
Block a user