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:
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user