DataSources: Add datasource fetching + querying interface (#80749)

* first pass

* separate oss + enterprise

* tidy things up

* add ctx

* fix tests

* use standalone svcs

* mv plugin context provide

* fix wire

* fix import
This commit is contained in:
Will Browne
2024-01-19 15:56:52 +01:00
committed by GitHub
parent bb0fa4f99a
commit 3f30cbf91c
21 changed files with 342 additions and 196 deletions
+3 -47
View File
@@ -2,18 +2,13 @@ package datasource
import (
"context"
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
)
var (
@@ -27,7 +22,7 @@ var (
type connectionAccess struct {
resourceInfo common.ResourceInfo
tableConverter rest.TableConvertor
builder *DataSourceAPIBuilder
builder Querier
}
func (s *connectionAccess) New() runtime.Object {
@@ -57,48 +52,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) {
ns := request.NamespaceValue(ctx)
ds, err := s.builder.getDataSource(ctx, name)
if err != nil {
return nil, err
}
return s.asConnection(ds, ns)
return s.builder.Datasource(ctx, name)
}
func (s *connectionAccess) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ns := request.NamespaceValue(ctx)
if ns == "" {
// require a namespace so we do not need to support reverse mappings (yet)
return nil, fmt.Errorf("missing namespace in request URL")
}
result := &v0alpha1.DataSourceConnectionList{
Items: []v0alpha1.DataSourceConnection{},
}
vals, err := s.builder.getDataSources(ctx)
if err == nil {
for _, ds := range vals {
v, _ := s.asConnection(ds, ns)
result.Items = append(result.Items, *v)
}
}
return result, err
}
func (s *connectionAccess) asConnection(ds *datasources.DataSource, ns string) (*v0alpha1.DataSourceConnection, error) {
v := &v0alpha1.DataSourceConnection{
TypeMeta: s.resourceInfo.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
return s.builder.Datasources(ctx)
}
@@ -0,0 +1,11 @@
package datasource
import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/backend"
)
type PluginContextProvider interface {
PluginContextForDataSource(ctx context.Context, pluginID, name string) (backend.PluginContext, error)
}
+169
View File
@@ -0,0 +1,169 @@
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
}
+34 -91
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -19,39 +18,32 @@ import (
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/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
grafanaapiserver "github.com/grafana/grafana/pkg/services/grafana-apiserver"
"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/pluginstore"
"github.com/grafana/grafana/pkg/setting"
)
var _ grafanaapiserver.APIGroupBuilder = (*DataSourceAPIBuilder)(nil)
// This is used just so wire has something unique to return
// DataSourceAPIBuilder is used just so wire has something unique to return
type DataSourceAPIBuilder struct {
connectionResourceInfo common.ResourceInfo
plugin plugins.JSONData
client plugins.Client
dsService datasources.DataSourceService
dsCache datasources.CacheService
pluginJSON plugins.JSONData
querier Querier
pluginContext PluginContextProvider
accessControl accesscontrol.AccessControl
}
func RegisterAPIService(
cfg *setting.Cfg,
querierProvider QuerierProvider,
features featuremgmt.FeatureToggles,
apiregistration grafanaapiserver.APIRegistrar,
pluginClient plugins.Client,
apiRegistrar grafanaapiserver.APIRegistrar,
pluginContext PluginContextProvider,
pluginStore pluginstore.Store,
dsService datasources.DataSourceService,
dsCache datasources.CacheService,
accessControl accesscontrol.AccessControl,
) (*DataSourceAPIBuilder, error) {
// This requires devmode!
@@ -71,31 +63,35 @@ func RegisterAPIService(
continue // skip this one
}
builder, err = NewDataSourceAPIBuilder(ds.JSONData, pluginClient, dsService, dsCache, accessControl)
builder, err = NewDataSourceAPIBuilder(ds.JSONData, querierProvider, pluginContext, accessControl)
if err != nil {
return nil, err
}
apiregistration.RegisterAPI(builder)
apiRegistrar.RegisterAPI(builder)
}
return builder, nil // only used for wire
}
func NewDataSourceAPIBuilder(
plugin plugins.JSONData,
client plugins.Client,
dsService datasources.DataSourceService,
dsCache datasources.CacheService,
querierProvider QuerierProvider,
pluginContext PluginContextProvider,
accessControl accesscontrol.AccessControl) (*DataSourceAPIBuilder, error) {
group, err := getDatasourceGroupNameFromPluginID(plugin.ID)
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: v0alpha1.GenericConnectionResourceInfo.WithGroupAndShortName(group, plugin.ID+"-connection"),
plugin: plugin,
client: client,
dsService: dsService,
dsCache: dsCache,
connectionResourceInfo: ri,
pluginJSON: plugin,
querier: querier,
pluginContext: pluginContext,
accessControl: accessControl,
}, nil
}
@@ -135,16 +131,24 @@ func (b *DataSourceAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
return scheme.SetVersionPriority(gv)
}
func resourceFromPluginID(pluginID string) (common.ResourceInfo, error) {
group, err := getDatasourceGroupNameFromPluginID(pluginID)
if err != nil {
return common.ResourceInfo{}, err
}
return v0alpha1.GenericConnectionResourceInfo.WithGroupAndShortName(group, pluginID+"-connection"), nil
}
func (b *DataSourceAPIBuilder) GetAPIGroupInfo(
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
optsGetter generic.RESTOptionsGetter,
_ generic.RESTOptionsGetter,
) (*genericapiserver.APIGroupInfo, error) {
storage := map[string]rest.Storage{}
conn := b.connectionResourceInfo
storage[conn.StoragePath()] = &connectionAccess{
builder: b,
builder: b.querier,
resourceInfo: conn,
tableConverter: utils.NewTableConverter(
conn.GroupResource(),
@@ -175,8 +179,8 @@ func (b *DataSourceAPIBuilder) GetAPIGroupInfo(
storage[conn.StoragePath("resource")] = &subResourceREST{builder: b}
// Frontend proxy
if len(b.plugin.Routes) > 0 {
storage[conn.StoragePath("proxy")] = &subProxyREST{builder: b}
if len(b.pluginJSON.Routes) > 0 {
storage[conn.StoragePath("proxy")] = &subProxyREST{pluginJSON: b.pluginJSON}
}
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(
@@ -195,64 +199,3 @@ func (b *DataSourceAPIBuilder) GetOpenAPIDefinitions() openapi.GetOpenAPIDefinit
func (b *DataSourceAPIBuilder) GetAPIRoutes() *grafanaapiserver.APIRoutes {
return nil
}
func (b *DataSourceAPIBuilder) getDataSourcePluginContext(ctx context.Context, name string) (*backend.PluginContext, 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 := b.dsCache.GetDatasourceByUID(ctx, name, user, false)
if err != nil {
return nil, err
}
settings := backend.DataSourceInstanceSettings{}
settings.ID = ds.ID
settings.UID = ds.UID
settings.Name = ds.Name
settings.URL = ds.URL
settings.Updated = ds.Updated
settings.User = ds.User
settings.JSONData, err = ds.JsonData.ToDB()
if err != nil {
return nil, err
}
settings.DecryptedSecureJSONData, err = b.dsService.DecryptedValues(ctx, ds)
if err != nil {
return nil, err
}
return &backend.PluginContext{
OrgID: info.OrgID,
PluginID: b.plugin.ID,
PluginVersion: b.plugin.Info.Version,
User: &backend.User{},
AppInstanceSettings: &backend.AppInstanceSettings{},
DataSourceInstanceSettings: &settings,
}, nil
}
func (b *DataSourceAPIBuilder) getDataSource(ctx context.Context, name string) (*datasources.DataSource, error) {
user, err := appcontext.User(ctx)
if err != nil {
return nil, err
}
return b.dsCache.GetDatasourceByUID(ctx, name, user, false)
}
func (b *DataSourceAPIBuilder) getDataSources(ctx context.Context) ([]*datasources.DataSource, error) {
orgId, err := request.OrgIDForList(ctx)
if err != nil {
return nil, err
}
return b.dsService.GetDataSourcesByType(ctx, &datasources.GetDataSourcesByTypeQuery{
OrgID: orgId,
Type: b.plugin.ID,
})
}
+28 -13
View File
@@ -4,19 +4,25 @@ import (
"context"
"fmt"
"github.com/grafana/grafana-plugin-sdk-go/backend"
common "github.com/grafana/grafana/pkg/apis/common/v0alpha1"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/setting"
testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource"
)
// This is a helper function to create a new datasource API server for a group
// NewStandaloneDatasource is a helper function to create a new datasource API server for a group.
// This currently has no dependencies and only works for testdata. In future iterations
// this will include here (or elsewhere) versions that can load config from HG api or
// the remote SQL directly
// the remote SQL directly.
func NewStandaloneDatasource(group string) (*DataSourceAPIBuilder, error) {
pluginID := "grafana-testdata-datasource"
if group != "testdata.datasource.grafana.app" {
return nil, fmt.Errorf("only testadata is currently supported")
return nil, fmt.Errorf("only %s is currently supported", pluginID)
}
pluginId := "grafana-testdata-datasource"
cfg, err := setting.NewCfgFromArgs(setting.CommandLineArgs{
// TODO: Add support for args?
@@ -25,21 +31,30 @@ func NewStandaloneDatasource(group string) (*DataSourceAPIBuilder, error) {
return nil, err
}
accessControl, pluginstoreService, dsService, cacheServiceImpl, err := apiBuilderServices(cfg, pluginId)
_, pluginStore, dsService, dsCache, err := apiBuilderServices(cfg, pluginID)
if err != nil {
return nil, err
}
testdataPlugin, found := pluginstoreService.Plugin(context.Background(), pluginId)
if !found {
return nil, fmt.Errorf("plugin %s not found", pluginId)
td, exists := pluginStore.Plugin(context.Background(), pluginID)
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(
testdataPlugin.JSONData,
testdatasource.ProvideService(),
dsService,
cacheServiceImpl,
accessControl,
td.JSONData,
NewQuerierProvider(testsDataQuerierFactory),
&TestDataPluginContextProvider{},
acimpl.ProvideAccessControl(cfg),
)
}
type TestDataPluginContextProvider struct{}
func (p *TestDataPluginContextProvider) PluginContextForDataSource(_ context.Context, _, _ string) (backend.PluginContext, error) {
return backend.PluginContext{}, nil
}
@@ -77,8 +77,8 @@ func apiBuilderServices(cfg *setting.Cfg, pluginID string) (
if err != nil {
return nil, nil, nil, nil, err
}
bundleregistryService := bundleregistry.ProvideService()
usageStats, err := service.ProvideService(cfg, kvStore, routeRegisterImpl, tracingService, accessControl, acimplService, bundleregistryService)
bundleRegistry := bundleregistry.ProvideService()
usageStats, err := service.ProvideService(cfg, kvStore, routeRegisterImpl, tracingService, accessControl, acimplService, bundleRegistry)
if err != nil {
return nil, nil, nil, nil, err
}
@@ -88,32 +88,32 @@ func apiBuilderServices(cfg *setting.Cfg, pluginID string) (
if err != nil {
return nil, nil, nil, nil, err
}
osskmsprovidersService := osskmsproviders.ProvideService(serviceService, cfg, featureToggles)
secretsService, err := manager.ProvideSecretsService(secretsStoreImpl, osskmsprovidersService, serviceService, cfg, featureToggles, usageStats)
kmsProviders := osskmsproviders.ProvideService(serviceService, cfg, featureToggles)
secretsService, err := manager.ProvideSecretsService(secretsStoreImpl, kmsProviders, serviceService, cfg, featureToggles, usageStats)
if err != nil {
return nil, nil, nil, nil, err
}
ossImpl := setting.ProvideProvider(cfg)
configCfg, err := config.ProvideConfig(ossImpl, cfg, featureToggles)
pluginCfg, err := config.ProvideConfig(ossImpl, cfg, featureToggles)
if err != nil {
return nil, nil, nil, nil, err
}
inMemory := registry.ProvideService()
pluginRegistry := registry.ProvideService()
quotaService := quotaimpl.ProvideService(sqlStore, cfg)
loaderLoader, err := createLoader(configCfg, inMemory)
pluginLoader, err := createLoader(pluginCfg, pluginRegistry)
if err != nil {
return nil, nil, nil, nil, err
}
pluginstoreService, err := pluginstore.ProvideService(inMemory, newPluginSource(cfg, pluginID), loaderLoader)
pluginStore, err := pluginstore.ProvideService(pluginRegistry, newPluginSource(cfg, pluginID), pluginLoader)
if err != nil {
return nil, nil, nil, nil, err
}
secretsKVStore, err := kvstoreService.ProvideService(sqlStore, secretsService, pluginstoreService, kvStore, featureToggles, cfg)
secretsKVStore, err := kvstoreService.ProvideService(sqlStore, secretsService, pluginStore, kvStore, featureToggles, cfg)
if err != nil {
return nil, nil, nil, nil, err
}
datasourcePermissionsService := ossaccesscontrol.ProvideDatasourcePermissionsService()
service13, err := datasourceService.ProvideService(sqlStore, secretsService, secretsKVStore, cfg, featureToggles, accessControl, datasourcePermissionsService, quotaService, pluginstoreService)
dsPermissionsService := ossaccesscontrol.ProvideDatasourcePermissionsService()
dsService, err := datasourceService.ProvideService(sqlStore, secretsService, secretsKVStore, cfg, featureToggles, accessControl, dsPermissionsService, quotaService, pluginStore)
if err != nil {
return nil, nil, nil, nil, err
}
@@ -121,7 +121,7 @@ func apiBuilderServices(cfg *setting.Cfg, pluginID string) (
ossProvider := guardian.ProvideGuardian()
cacheServiceImpl := datasourceService.ProvideCacheService(cacheService, sqlStore, ossProvider)
return accessControl, pluginstoreService, service13, cacheServiceImpl, nil
return accessControl, pluginStore, dsService, cacheServiceImpl, nil
}
var _ sources.Registry = (*pluginSource)(nil)
+3 -3
View File
@@ -35,14 +35,14 @@ 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.getDataSourcePluginContext(ctx, name)
pluginCtx, err := r.builder.pluginContext.PluginContextForDataSource(ctx, r.builder.pluginJSON.ID, name)
if err != nil {
responder.Error(err)
return
}
healthResponse, err := r.builder.client.CheckHealth(ctx, &backend.CheckHealthRequest{
PluginContext: *pluginCtx,
healthResponse, err := r.builder.querier.Health(ctx, &backend.CheckHealthRequest{
PluginContext: pluginCtx,
})
if err != nil {
responder.Error(err)
+5 -8
View File
@@ -8,10 +8,12 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/rest"
"github.com/grafana/grafana/pkg/plugins"
)
type subProxyREST struct {
builder *DataSourceAPIBuilder
pluginJSON plugins.JSONData
}
var _ = rest.Connecter(&subProxyREST{})
@@ -25,7 +27,7 @@ func (r *subProxyREST) Destroy() {}
func (r *subProxyREST) ConnectMethods() []string {
unique := map[string]bool{}
methods := []string{}
for _, r := range r.builder.plugin.Routes {
for _, r := range r.pluginJSON.Routes {
if unique[r.Method] {
continue
}
@@ -40,12 +42,7 @@ func (r *subProxyREST) NewConnectOptions() (runtime.Object, bool, string) {
}
func (r *subProxyREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
pluginCtx, err := r.builder.getDataSourcePluginContext(ctx, name)
if err != nil {
return nil, err
}
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
responder.Error(fmt.Errorf("TODO, proxy: " + pluginCtx.PluginID))
responder.Error(fmt.Errorf("TODO, proxy: " + r.pluginJSON.ID))
}), nil
}
+3 -3
View File
@@ -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.getDataSourcePluginContext(ctx, name)
pluginCtx, err := r.builder.pluginContext.PluginContextForDataSource(ctx, r.builder.pluginJSON.ID, name)
if err != nil {
return nil, err
}
@@ -83,8 +83,8 @@ func (r *subQueryREST) Connect(ctx context.Context, name string, opts runtime.Ob
return
}
queryResponse, err := r.builder.client.QueryData(ctx, &backend.QueryDataRequest{
PluginContext: *pluginCtx,
queryResponse, err := r.builder.querier.Query(ctx, &backend.QueryDataRequest{
PluginContext: pluginCtx,
Queries: queries,
// Headers: // from context
})
+3 -3
View File
@@ -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.getDataSourcePluginContext(ctx, name)
pluginCtx, err := r.builder.pluginContext.PluginContextForDataSource(ctx, r.builder.pluginJSON.ID, name)
if err != nil {
return nil, err
}
@@ -65,8 +65,8 @@ func (r *subResourceREST) Connect(ctx context.Context, name string, opts runtime
}
path := req.URL.Path[idx+len("/resource"):]
err = r.builder.client.CallResource(ctx, &backend.CallResourceRequest{
PluginContext: *pluginCtx,
err = r.builder.querier.Resource(ctx, &backend.CallResourceRequest{
PluginContext: pluginCtx,
Path: path,
Method: req.Method,
Body: body,