mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Set grafana config, plugin version and user agent on plugin requests (#75171)
* first pass * fixup * remove test line * fix tests * use new fields * fix imports + formatting * fix tests * rollback changes * undo whitespace * apply pr feedback
This commit is contained in:
parent
dd8f88b194
commit
7fca1bde54
2
go.mod
2
go.mod
@ -63,7 +63,7 @@ require (
|
||||
github.com/grafana/cuetsy v0.1.10 // @grafana/grafana-as-code
|
||||
github.com/grafana/grafana-aws-sdk v0.19.1 // @grafana/aws-datasources
|
||||
github.com/grafana/grafana-azure-sdk-go v1.8.1 // @grafana/backend-platform
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.176.0 // @grafana/plugins-platform-backend
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.177.0 // @grafana/plugins-platform-backend
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform
|
||||
github.com/hashicorp/go-hclog v1.5.0 // @grafana/plugins-platform-backend
|
||||
github.com/hashicorp/go-plugin v1.4.9 // @grafana/plugins-platform-backend
|
||||
|
2
go.sum
2
go.sum
@ -1807,6 +1807,8 @@ github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW3
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.176.0 h1:dayiqGR6uJyJBO8rRTp/E7oKsnEjNSS0p7vVkXy/Brw=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.176.0/go.mod h1:9crAQqSzxvPe0VKC/T23cd+2I9TZb43yoOcUL/qZ5FU=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.177.0 h1:ERJ38b91Zw8tkz8MgHio5pVeK7ySaf5+i1I4F28YgWs=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.177.0/go.mod h1:9crAQqSzxvPe0VKC/T23cd+2I9TZb43yoOcUL/qZ5FU=
|
||||
github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo=
|
||||
github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482/go.mod h1:GNcfpy5+SY6RVbNGQW264gC0r336Dm+0zgQ5vt6+M8Y=
|
||||
github.com/grafana/phlare/api v0.1.4-0.20230426005640-f90edba05413 h1:bBzCezZNRyYlJpXTkyZdY4fpPxHZUdyeyRWzhtw/P6I=
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
pluginClient "github.com/grafana/grafana/pkg/plugins/manager/client"
|
||||
pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
||||
@ -52,8 +53,9 @@ func (rv *fakePluginRequestValidator) Validate(dsURL string, req *http.Request)
|
||||
|
||||
// `/ds/query` endpoint test
|
||||
func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
qds := query.ProvideService(
|
||||
setting.NewCfg(),
|
||||
cfg,
|
||||
nil,
|
||||
nil,
|
||||
&fakePluginRequestValidator{},
|
||||
@ -67,7 +69,7 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
return &backend.QueryDataResponse{Responses: resp}, nil
|
||||
},
|
||||
},
|
||||
plugincontext.ProvideService(localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
plugincontext.ProvideService(cfg, localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{
|
||||
JSONData: plugins.JSONData{
|
||||
@ -76,8 +78,7 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, &fakeDatasources.FakeDataSourceService{}, pluginSettings.ProvideService(dbtest.NewFakeDB(),
|
||||
secretstest.NewFakeSecretsService()),
|
||||
),
|
||||
secretstest.NewFakeSecretsService()), pluginFakes.NewFakeLicensingService(), &config.Cfg{}),
|
||||
)
|
||||
serverFeatureEnabled := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.queryDataService = qds
|
||||
@ -110,9 +111,10 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
|
||||
cfg := setting.NewCfg()
|
||||
ds := &fakeDatasources.FakeDataSourceService{SimulatePluginFailure: true}
|
||||
db := &dbtest.FakeDB{ExpectedError: pluginsettings.ErrPluginSettingNotFound}
|
||||
pcp := plugincontext.ProvideService(localcache.ProvideService(),
|
||||
pcp := plugincontext.ProvideService(cfg, localcache.ProvideService(),
|
||||
&pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{
|
||||
@ -122,10 +124,10 @@ func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
ds, pluginSettings.ProvideService(db, secretstest.NewFakeSecretsService()),
|
||||
ds, pluginSettings.ProvideService(db, secretstest.NewFakeSecretsService()), pluginFakes.NewFakeLicensingService(), &config.Cfg{},
|
||||
)
|
||||
qds := query.ProvideService(
|
||||
setting.NewCfg(),
|
||||
cfg,
|
||||
nil,
|
||||
nil,
|
||||
&fakePluginRequestValidator{},
|
||||
@ -284,22 +286,22 @@ func TestDataSourceQueryError(t *testing.T) {
|
||||
},
|
||||
})
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
cfg := setting.NewCfg()
|
||||
r := registry.NewInMemory()
|
||||
err := r.Add(context.Background(), p)
|
||||
require.NoError(t, err)
|
||||
ds := &fakeDatasources.FakeDataSourceService{}
|
||||
hs.queryDataService = query.ProvideService(
|
||||
setting.NewCfg(),
|
||||
cfg,
|
||||
&fakeDatasources.FakeCacheService{},
|
||||
nil,
|
||||
&fakePluginRequestValidator{},
|
||||
pluginClient.ProvideService(r, &config.Cfg{}),
|
||||
plugincontext.ProvideService(localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
plugincontext.ProvideService(cfg, localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{pluginstore.ToGrafanaDTO(p)},
|
||||
},
|
||||
ds, pluginSettings.ProvideService(dbtest.NewFakeDB(),
|
||||
secretstest.NewFakeSecretsService()),
|
||||
),
|
||||
secretstest.NewFakeSecretsService()), pluginFakes.NewFakeLicensingService(), &config.Cfg{}),
|
||||
)
|
||||
hs.QuotaService = quotatest.New(false, nil)
|
||||
})
|
||||
|
@ -43,7 +43,6 @@ func TestCallResource(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
|
||||
cfg.StaticRootPath = staticRootPath
|
||||
cfg.IsFeatureToggleEnabled = func(_ string) bool {
|
||||
return false
|
||||
@ -55,8 +54,8 @@ func TestCallResource(t *testing.T) {
|
||||
|
||||
textCtx := pluginsintegration.CreateIntegrationTestCtx(t, cfg, coreRegistry)
|
||||
|
||||
pcp := plugincontext.ProvideService(localcache.ProvideService(), textCtx.PluginStore, &datasources.FakeDataSourceService{},
|
||||
pluginSettings.ProvideService(db.InitTestDB(t), fakeSecrets.NewFakeSecretsService()))
|
||||
pcp := plugincontext.ProvideService(cfg, localcache.ProvideService(), textCtx.PluginStore, &datasources.FakeDataSourceService{},
|
||||
pluginSettings.ProvideService(db.InitTestDB(t), fakeSecrets.NewFakeSecretsService()), nil, nil)
|
||||
|
||||
srv := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||
hs.Cfg = cfg
|
||||
|
@ -12,6 +12,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@ -54,11 +56,11 @@ func framesPassThroughService(t *testing.T, frames data.Frames) (data.Frames, er
|
||||
cfg: cfg,
|
||||
dataService: me,
|
||||
features: &featuremgmt.FeatureManager{},
|
||||
pCtxProvider: plugincontext.ProvideService(nil, &pluginstore.FakePluginStore{
|
||||
pCtxProvider: plugincontext.ProvideService(cfg, nil, &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "test"}},
|
||||
}},
|
||||
&datafakes.FakeDataSourceService{}, nil),
|
||||
&datafakes.FakeDataSourceService{}, nil, pluginFakes.NewFakeLicensingService(), &config.Cfg{}),
|
||||
tracer: tracing.InitializeTracerForTest(),
|
||||
metrics: newMetrics(nil),
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@ -36,11 +38,11 @@ func TestService(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
pCtxProvider := plugincontext.ProvideService(nil, &pluginstore.FakePluginStore{
|
||||
pCtxProvider := plugincontext.ProvideService(setting.NewCfg(), nil, &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "test"}},
|
||||
},
|
||||
}, &datafakes.FakeDataSourceService{}, nil)
|
||||
}, &datafakes.FakeDataSourceService{}, nil, fakes.NewFakeLicensingService(), &config.Cfg{})
|
||||
|
||||
s := Service{
|
||||
cfg: setting.NewCfg(),
|
||||
@ -122,11 +124,11 @@ func TestDSQueryError(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
pCtxProvider := plugincontext.ProvideService(nil, &pluginstore.FakePluginStore{
|
||||
pCtxProvider := plugincontext.ProvideService(setting.NewCfg(), nil, &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "test"}},
|
||||
},
|
||||
}, &datafakes.FakeDataSourceService{}, nil)
|
||||
}, &datafakes.FakeDataSourceService{}, nil, nil, &config.Cfg{})
|
||||
|
||||
s := Service{
|
||||
cfg: setting.NewCfg(),
|
||||
|
@ -10,9 +10,15 @@ import (
|
||||
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||
)
|
||||
|
||||
const (
|
||||
customConfigPrefix = "GF_PLUGIN"
|
||||
)
|
||||
|
||||
type Provider interface {
|
||||
@ -62,10 +68,97 @@ func (s *Service) Get(ctx context.Context, p *plugins.Plugin) []string {
|
||||
hostEnv = append(hostEnv, azsettings.WriteToEnvStr(s.cfg.Azure)...)
|
||||
hostEnv = append(hostEnv, s.tracingEnvVars(p)...)
|
||||
|
||||
ev := getPluginSettings(p.ID, s.cfg).asEnvVar("GF_PLUGIN", hostEnv)
|
||||
ev := getPluginSettings(p.ID, s.cfg).asEnvVar(customConfigPrefix, hostEnv...)
|
||||
return ev
|
||||
}
|
||||
|
||||
// GetConfigMap returns a map of configuration that should be passed in a plugin request.
|
||||
func (s *Service) GetConfigMap(ctx context.Context, _ string, _ *oauth.ExternalService) map[string]string {
|
||||
m := make(map[string]string)
|
||||
|
||||
// TODO add support via plugin SDK
|
||||
//if externalService != nil {
|
||||
// m[oauthtokenretriever.AppURL] = s.cfg.GrafanaAppURL
|
||||
// m[oauthtokenretriever.AppClientID] = externalService.ClientID
|
||||
// m[oauthtokenretriever.AppClientSecret] = externalService.ClientSecret
|
||||
// m[oauthtokenretriever.AppPrivateKey] = externalService.PrivateKey
|
||||
//}
|
||||
|
||||
if s.cfg.Features != nil {
|
||||
enabledFeatures := s.cfg.Features.GetEnabled(ctx)
|
||||
if len(enabledFeatures) > 0 {
|
||||
features := make([]string, 0, len(enabledFeatures))
|
||||
for feat := range enabledFeatures {
|
||||
features = append(features, feat)
|
||||
}
|
||||
m[featuretoggles.EnabledFeatures] = strings.Join(features, ",")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add support via plugin SDK
|
||||
//if s.cfg.AWSAssumeRoleEnabled {
|
||||
// m[awsds.AssumeRoleEnabledEnvVarKeyName] = "true"
|
||||
//}
|
||||
//if len(s.cfg.AWSAllowedAuthProviders) > 0 {
|
||||
// m[awsds.AllowedAuthProvidersEnvVarKeyName] = strings.Join(s.cfg.AWSAllowedAuthProviders, ",")
|
||||
//}
|
||||
//if s.cfg.AWSExternalId != "" {
|
||||
// m[awsds.GrafanaAssumeRoleExternalIdKeyName] = s.cfg.AWSExternalId
|
||||
//}
|
||||
|
||||
if s.cfg.ProxySettings.Enabled {
|
||||
m[proxy.PluginSecureSocksProxyEnabled] = "true"
|
||||
m[proxy.PluginSecureSocksProxyClientCert] = s.cfg.ProxySettings.ClientCert
|
||||
m[proxy.PluginSecureSocksProxyClientKey] = s.cfg.ProxySettings.ClientKey
|
||||
m[proxy.PluginSecureSocksProxyRootCACert] = s.cfg.ProxySettings.RootCA
|
||||
m[proxy.PluginSecureSocksProxyProxyAddress] = s.cfg.ProxySettings.ProxyAddress
|
||||
m[proxy.PluginSecureSocksProxyServerName] = s.cfg.ProxySettings.ServerName
|
||||
}
|
||||
|
||||
// TODO add support via plugin SDK
|
||||
//azureSettings := s.cfg.Azure
|
||||
//if azureSettings != nil {
|
||||
// if azureSettings.Cloud != "" {
|
||||
// m[azsettings.AzureCloud] = azureSettings.Cloud
|
||||
// }
|
||||
//
|
||||
// if azureSettings.ManagedIdentityEnabled {
|
||||
// m[azsettings.ManagedIdentityEnabled] = "true"
|
||||
//
|
||||
// if azureSettings.ManagedIdentityClientId != "" {
|
||||
// m[azsettings.ManagedIdentityClientID] = azureSettings.ManagedIdentityClientId
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if azureSettings.UserIdentityEnabled {
|
||||
// m[azsettings.UserIdentityEnabled] = "true"
|
||||
//
|
||||
// if azureSettings.UserIdentityTokenEndpoint != nil {
|
||||
// if azureSettings.UserIdentityTokenEndpoint.TokenUrl != "" {
|
||||
// m[azsettings.UserIdentityTokenURL] = azureSettings.UserIdentityTokenEndpoint.TokenUrl
|
||||
// }
|
||||
// if azureSettings.UserIdentityTokenEndpoint.ClientId != "" {
|
||||
// m[azsettings.UserIdentityClientID] = azureSettings.UserIdentityTokenEndpoint.ClientId
|
||||
// }
|
||||
// if azureSettings.UserIdentityTokenEndpoint.ClientSecret != "" {
|
||||
// m[azsettings.UserIdentityClientSecret] = azureSettings.UserIdentityTokenEndpoint.ClientSecret
|
||||
// }
|
||||
// if azureSettings.UserIdentityTokenEndpoint.UsernameAssertion {
|
||||
// m[azsettings.UserIdentityAssertion] = "username"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO add support via plugin SDK
|
||||
//ps := getPluginSettings(pluginID, s.cfg)
|
||||
//for k, v := range ps {
|
||||
// m[fmt.Sprintf("%s_%s", customConfigPrefix, strings.ToUpper(k))] = v
|
||||
//}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *Service) tracingEnvVars(plugin *plugins.Plugin) []string {
|
||||
var pluginTracingEnabled bool
|
||||
if v, exists := s.cfg.PluginSettings[plugin.ID]["tracing"]; exists {
|
||||
@ -146,7 +239,7 @@ func getPluginSettings(pluginID string, cfg *config.Cfg) pluginSettings {
|
||||
return ps
|
||||
}
|
||||
|
||||
func (ps pluginSettings) asEnvVar(prefix string, hostEnv []string) []string {
|
||||
func (ps pluginSettings) asEnvVar(prefix string, hostEnv ...string) []string {
|
||||
env := make([]string, 0, len(ps))
|
||||
for k, v := range ps {
|
||||
key := fmt.Sprintf("%s_%s", prefix, strings.ToUpper(k))
|
||||
|
@ -5,35 +5,54 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/useragent"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/envvars"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/adapters"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const (
|
||||
pluginSettingsCacheTTL = 5 * time.Second
|
||||
pluginSettingsCachePrefix = "plugin-setting-"
|
||||
)
|
||||
|
||||
var ErrPluginNotFound = errors.New("plugin not found")
|
||||
|
||||
func ProvideService(cacheService *localcache.CacheService, pluginStore pluginstore.Store,
|
||||
dataSourceService datasources.DataSourceService, pluginSettingsService pluginsettings.Service) *Provider {
|
||||
func ProvideService(cfg *setting.Cfg, cacheService *localcache.CacheService, pluginStore pluginstore.Store,
|
||||
dataSourceService datasources.DataSourceService, pluginSettingsService pluginsettings.Service,
|
||||
licensing plugins.Licensing, pCfg *config.Cfg) *Provider {
|
||||
return &Provider{
|
||||
cfg: cfg,
|
||||
cacheService: cacheService,
|
||||
pluginStore: pluginStore,
|
||||
dataSourceService: dataSourceService,
|
||||
pluginSettingsService: pluginSettingsService,
|
||||
pluginEnvVars: envvars.NewProvider(pCfg, licensing),
|
||||
logger: log.New("plugin.context"),
|
||||
}
|
||||
}
|
||||
|
||||
type Provider struct {
|
||||
cfg *setting.Cfg
|
||||
pluginEnvVars *envvars.Service
|
||||
cacheService *localcache.CacheService
|
||||
pluginStore pluginstore.Store
|
||||
dataSourceService datasources.DataSourceService
|
||||
pluginSettingsService pluginsettings.Service
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// Get allows getting plugin context by its ID. If datasourceUID is not empty string
|
||||
@ -47,7 +66,8 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
|
||||
}
|
||||
|
||||
pCtx := backend.PluginContext{
|
||||
PluginID: pluginID,
|
||||
PluginID: pluginID,
|
||||
PluginVersion: plugin.Info.Version,
|
||||
}
|
||||
if user != nil && !user.IsNil() {
|
||||
pCtx.OrgID = user.GetOrgID()
|
||||
@ -62,6 +82,12 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
|
||||
pCtx.AppInstanceSettings = appSettings
|
||||
}
|
||||
|
||||
ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH)
|
||||
if err != nil {
|
||||
p.logger.Warn("Could not create user agent", "error", err)
|
||||
}
|
||||
pCtx.UserAgent = ua
|
||||
|
||||
return pCtx, nil
|
||||
}
|
||||
|
||||
@ -69,13 +95,14 @@ func (p *Provider) Get(ctx context.Context, pluginID string, user identity.Reque
|
||||
// resolved and appended to the returned context.
|
||||
// Note: *user.SignedInUser can be nil.
|
||||
func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||
_, exists := p.pluginStore.Plugin(ctx, pluginID)
|
||||
plugin, exists := p.pluginStore.Plugin(ctx, pluginID)
|
||||
if !exists {
|
||||
return backend.PluginContext{}, ErrPluginNotFound
|
||||
}
|
||||
|
||||
pCtx := backend.PluginContext{
|
||||
PluginID: pluginID,
|
||||
PluginID: pluginID,
|
||||
PluginVersion: plugin.Info.Version,
|
||||
}
|
||||
if user != nil && !user.IsNil() {
|
||||
pCtx.OrgID = user.GetOrgID()
|
||||
@ -88,12 +115,18 @@ func (p *Provider) GetWithDataSource(ctx context.Context, pluginID string, user
|
||||
}
|
||||
pCtx.DataSourceInstanceSettings = datasourceSettings
|
||||
|
||||
settings := p.pluginEnvVars.GetConfigMap(ctx, pluginID, plugin.ExternalService)
|
||||
pCtx.GrafanaConfig = backend.NewGrafanaCfg(settings)
|
||||
|
||||
ua, err := useragent.New(p.cfg.BuildVersion, runtime.GOOS, runtime.GOARCH)
|
||||
if err != nil {
|
||||
p.logger.Warn("Could not create user agent", "error", err)
|
||||
}
|
||||
pCtx.UserAgent = ua
|
||||
|
||||
return pCtx, nil
|
||||
}
|
||||
|
||||
const pluginSettingsCacheTTL = 5 * time.Second
|
||||
const pluginSettingsCachePrefix = "plugin-setting-"
|
||||
|
||||
func (p *Provider) appInstanceSettings(ctx context.Context, pluginID string, orgID int64) (*backend.AppInstanceSettings, error) {
|
||||
jsonData := json.RawMessage{}
|
||||
decryptedSecureJSONData := map[string]string{}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/oauth"
|
||||
)
|
||||
|
||||
type Plugin struct {
|
||||
@ -32,7 +33,9 @@ type Plugin struct {
|
||||
AngularDetected bool
|
||||
|
||||
// This will be moved to plugin.json when we have general support in gcom
|
||||
Alias string `json:"alias,omitempty"`
|
||||
Alias string
|
||||
|
||||
ExternalService *oauth.ExternalService
|
||||
}
|
||||
|
||||
func (p Plugin) SupportsStreaming() bool {
|
||||
@ -74,5 +77,6 @@ func ToGrafanaDTO(p *plugins.Plugin) Plugin {
|
||||
BaseURL: p.BaseURL,
|
||||
AngularDetected: p.AngularDetected,
|
||||
Alias: p.Alias,
|
||||
ExternalService: p.ExternalService,
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
@ -119,15 +121,17 @@ func buildQueryDataService(t *testing.T, cs datasources.CacheService, fpc *fakeP
|
||||
}
|
||||
|
||||
ds := &fakeDatasources.FakeDataSourceService{}
|
||||
pCtxProvider := plugincontext.ProvideService(localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "mysql",
|
||||
pCtxProvider := plugincontext.ProvideService(setting.NewCfg(),
|
||||
localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{
|
||||
JSONData: plugins.JSONData{
|
||||
ID: "mysql",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, ds, pluginSettings.ProvideService(store, fakeSecrets.NewFakeSecretsService()))
|
||||
}, ds, pluginSettings.ProvideService(store, fakeSecrets.NewFakeSecretsService()), fakes.NewFakeLicensingService(),
|
||||
&config.Cfg{})
|
||||
|
||||
return query.ProvideService(
|
||||
setting.NewCfg(),
|
||||
|
@ -24,6 +24,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/models/roletype"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
|
||||
@ -467,7 +469,7 @@ func setup(t *testing.T) *testContext {
|
||||
SimulatePluginFailure: false,
|
||||
}
|
||||
|
||||
pCtxProvider := plugincontext.ProvideService(
|
||||
pCtxProvider := plugincontext.ProvideService(sqlStore.Cfg,
|
||||
localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "postgres"}},
|
||||
@ -475,7 +477,7 @@ func setup(t *testing.T) *testContext {
|
||||
{JSONData: plugins.JSONData{ID: "mysql"}},
|
||||
},
|
||||
}, fakeDatasourceService,
|
||||
pluginSettings.ProvideService(sqlStore, secretsService),
|
||||
pluginSettings.ProvideService(sqlStore, secretsService), pluginFakes.NewFakeLicensingService(), &config.Cfg{},
|
||||
)
|
||||
exprService := expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, pc, pCtxProvider,
|
||||
&featuremgmt.FeatureManager{}, nil, tracing.InitializeTracerForTest())
|
||||
|
@ -79,7 +79,7 @@ func getDatasourceService(settings *backend.DataSourceInstanceSettings, cfg *set
|
||||
}
|
||||
|
||||
func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider, executors map[string]azDatasourceExecutor) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
jsonDataObj := map[string]any{}
|
||||
err := json.Unmarshal(settings.JSONData, &jsonDataObj)
|
||||
if err != nil {
|
||||
|
@ -96,7 +96,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
factory := NewInstanceSettings(cfg, &httpclient.Provider{}, map[string]azDatasourceExecutor{})
|
||||
instance, err := factory(tt.settings)
|
||||
instance, err := factory(context.Background(), tt.settings)
|
||||
tt.Err(t, err)
|
||||
if !cmp.Equal(instance, tt.expectedModel) {
|
||||
t.Errorf("Unexpected instance: %v", cmp.Diff(instance, tt.expectedModel))
|
||||
|
@ -161,7 +161,7 @@ type datasourceService struct {
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
var jsonData datasourceJSONData
|
||||
err := json.Unmarshal(settings.JSONData, &jsonData)
|
||||
if err != nil {
|
||||
|
@ -24,7 +24,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
t.Run("should create a new instance with empty settings", func(t *testing.T) {
|
||||
cli := httpclient.NewProvider()
|
||||
f := newInstanceSettings(cli)
|
||||
dsInfo, err := f(backend.DataSourceInstanceSettings{
|
||||
dsInfo, err := f(context.Background(), backend.DataSourceInstanceSettings{
|
||||
JSONData: json.RawMessage(`{}`),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@ -35,7 +35,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
t.Run("should create a new instance parsing settings", func(t *testing.T) {
|
||||
cli := httpclient.NewProvider()
|
||||
f := newInstanceSettings(cli)
|
||||
dsInfo, err := f(backend.DataSourceInstanceSettings{
|
||||
dsInfo, err := f(context.Background(), backend.DataSourceInstanceSettings{
|
||||
JSONData: json.RawMessage(`{"authenticationType": "test", "defaultProject": "test", "clientEmail": "test", "tokenUri": "test"}`),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@ -1144,7 +1144,7 @@ func baseTimeSeriesQuery() *backend.QueryDataRequest {
|
||||
|
||||
func TestCheckHealth(t *testing.T) {
|
||||
t.Run("and using GCE authentation should return proper error", func(t *testing.T) {
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(_ context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return &datasourceInfo{
|
||||
authenticationType: gceAuthentication,
|
||||
}, nil
|
||||
|
@ -31,7 +31,7 @@ func TestQuery_AnnotationQuery(t *testing.T) {
|
||||
|
||||
t.Run("DescribeAlarmsForMetric is called with minimum parameters", func(t *testing.T) {
|
||||
client = fakeCWAnnotationsClient{describeAlarmsForMetricOutput: &cloudwatch.DescribeAlarmsForMetricOutput{}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -65,7 +65,7 @@ func TestQuery_AnnotationQuery(t *testing.T) {
|
||||
|
||||
t.Run("DescribeAlarms is called when prefixMatching is true", func(t *testing.T) {
|
||||
client = fakeCWAnnotationsClient{describeAlarmsOutput: &cloudwatch.DescribeAlarmsOutput{}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
|
@ -84,7 +84,7 @@ func newExecutor(im instancemgmt.InstanceManager, cfg *setting.Cfg, sessions Ses
|
||||
}
|
||||
|
||||
func NewInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
instanceSettings, err := models.LoadCloudWatchSettings(settings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading settings: %w", err)
|
||||
|
@ -46,7 +46,7 @@ func Test_CloudWatch_CallResource_Integration_Test(t *testing.T) {
|
||||
return &api
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
|
@ -70,7 +70,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f := NewInstanceSettings(httpclient.NewProvider())
|
||||
model, err := f(tt.settings)
|
||||
model, err := f(context.Background(), tt.settings)
|
||||
tt.Err(t, err)
|
||||
datasourceComparer := cmp.Comparer(func(d1 DataSource, d2 DataSource) bool {
|
||||
return d1.Settings.Profile == d2.Settings.Profile &&
|
||||
@ -110,7 +110,7 @@ func Test_CheckHealth(t *testing.T) {
|
||||
|
||||
t.Run("successfully query metrics and logs", func(t *testing.T) {
|
||||
client = fakeCheckHealthClient{}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -131,7 +131,7 @@ func Test_CheckHealth(t *testing.T) {
|
||||
describeLogGroups: func(input *cloudwatchlogs.DescribeLogGroupsInput) (*cloudwatchlogs.DescribeLogGroupsOutput, error) {
|
||||
return nil, fmt.Errorf("some logs query error")
|
||||
}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -152,7 +152,7 @@ func Test_CheckHealth(t *testing.T) {
|
||||
listMetricsPages: func(input *cloudwatch.ListMetricsInput, fn func(*cloudwatch.ListMetricsOutput, bool) bool) error {
|
||||
return fmt.Errorf("some list metrics error")
|
||||
}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -170,7 +170,7 @@ func Test_CheckHealth(t *testing.T) {
|
||||
|
||||
t.Run("fail to get clients", func(t *testing.T) {
|
||||
client = fakeCheckHealthClient{}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{getSession: func(c awsds.SessionConfig) (*session.Session, error) {
|
||||
@ -207,7 +207,7 @@ func TestQuery_ResourceRequest_DescribeLogGroups_with_CrossAccountQuerying(t *te
|
||||
return &logsApi
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
|
@ -85,7 +85,7 @@ func TestQuery_handleGetLogEvents_passes_nil_start_and_end_times_to_GetLogEvents
|
||||
t.Run(name, func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -119,7 +119,7 @@ func TestQuery_GetLogEvents_returns_response_from_GetLogEvents_to_data_frame_fie
|
||||
NewCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
|
||||
return cli
|
||||
}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -199,7 +199,7 @@ func TestQuery_StartQuery(t *testing.T) {
|
||||
To: time.Unix(1584700643, 0),
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -252,7 +252,7 @@ func TestQuery_StartQuery(t *testing.T) {
|
||||
To: time.Unix(1584873443000, 0),
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -310,7 +310,7 @@ func Test_executeStartQuery(t *testing.T) {
|
||||
|
||||
t.Run("successfully parses information from JSON to StartQueryWithContext", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -346,7 +346,7 @@ func Test_executeStartQuery(t *testing.T) {
|
||||
|
||||
t.Run("does not populate StartQueryInput.limit when no limit provided", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -372,7 +372,7 @@ func Test_executeStartQuery(t *testing.T) {
|
||||
|
||||
t.Run("attaches logGroupIdentifiers if the crossAccount feature is enabled", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures(featuremgmt.FlagCloudWatchCrossAccountQuerying))
|
||||
@ -408,7 +408,7 @@ func Test_executeStartQuery(t *testing.T) {
|
||||
|
||||
t.Run("attaches logGroupIdentifiers if the crossAccount feature is enabled and strips out trailing *", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures(featuremgmt.FlagCloudWatchCrossAccountQuerying))
|
||||
@ -474,7 +474,7 @@ func TestQuery_StopQuery(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -569,7 +569,7 @@ func TestQuery_GetQueryResults(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
|
@ -39,7 +39,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
|
||||
|
||||
t.Run("getCWLogsClient is called with region from input JSON", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{queryResults: cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
sess := fakeSessionCache{}
|
||||
@ -65,7 +65,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
|
||||
|
||||
t.Run("getCWLogsClient is called with region from instance manager when region is default", func(t *testing.T) {
|
||||
cli = fakeCWLogsClient{queryResults: cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "instance manager's region"}}}, nil
|
||||
})
|
||||
sess := fakeSessionCache{}
|
||||
@ -122,7 +122,7 @@ func Test_executeSyncLogQuery(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
syncCalled = false
|
||||
cli = fakeCWLogsClient{queryResults: cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{AWSDatasourceSettings: awsds.AWSDatasourceSettings{Region: "instance manager's region"}}}, nil
|
||||
})
|
||||
sess := fakeSessionCache{}
|
||||
@ -170,7 +170,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
|
||||
QueryId: aws.String("abcd-efgh-ijkl-mnop"),
|
||||
}, nil)
|
||||
cli.On("GetQueryResultsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}, nil)
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -199,7 +199,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
|
||||
QueryId: aws.String("abcd-efgh-ijkl-mnop"),
|
||||
}, nil)
|
||||
cli.On("GetQueryResultsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")}, nil)
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -268,7 +268,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
|
||||
}}},
|
||||
Status: aws.String("Complete")}, nil)
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -313,7 +313,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
|
||||
QueryId: aws.String("abcd-efgh-ijkl-mnop"),
|
||||
}, nil)
|
||||
cli.On("GetQueryResultsWithContext", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Running")}, nil)
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{LogsTimeout: models.Duration{Duration: time.Millisecond}}}, nil
|
||||
})
|
||||
|
||||
@ -346,7 +346,7 @@ func Test_executeSyncLogQuery_handles_RefId_from_input_queries(t *testing.T) {
|
||||
&cloudwatchlogs.GetQueryResultsOutput{Status: aws.String("Complete")},
|
||||
&fakeAWSError{code: "foo", message: "bar"},
|
||||
)
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
|
@ -42,7 +42,7 @@ func TestQuery_Regions(t *testing.T) {
|
||||
regions: []string{regionName},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -99,7 +99,7 @@ func Test_handleGetRegions_regionCache(t *testing.T) {
|
||||
newEC2Client = func(client.ConfigProvider) models.EC2APIProvider {
|
||||
return &cli
|
||||
}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -152,7 +152,7 @@ func TestQuery_InstanceAttributes(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -236,7 +236,7 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -297,7 +297,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
|
@ -50,7 +50,7 @@ func TestTimeSeriesQuery(t *testing.T) {
|
||||
StatusCode: aws.String("Complete"), Id: aws.String("b"), Label: aws.String("NetworkIn"), Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{&now},
|
||||
}}}, nil)
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -148,7 +148,7 @@ func Test_executeTimeSeriesQuery_getCWClient_is_called_once_per_region_and_GetMe
|
||||
return &mockMetricClient
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -337,7 +337,7 @@ func Test_QueryData_timeSeriesQuery_GetMetricDataWithContext(t *testing.T) {
|
||||
return &api
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
@ -429,7 +429,7 @@ func Test_QueryData_response_data_frame_name_is_always_response_label(t *testing
|
||||
Values: []*float64{aws.Float64(1.0)}, Timestamps: []*time.Time{{}}},
|
||||
}}, nil)
|
||||
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
executor := newExecutor(im, newTestConfig(), &fakeSessionCache{}, featuremgmt.WithFeatures())
|
||||
@ -584,7 +584,7 @@ func TestTimeSeriesQuery_CrossAccountQuerying(t *testing.T) {
|
||||
NewCWClient = func(sess *session.Session) cloudwatchiface.CloudWatchAPI {
|
||||
return &api
|
||||
}
|
||||
im := datasource.NewInstanceManager(func(s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
im := datasource.NewInstanceManager(func(ctx context.Context, s backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return DataSource{Settings: models.CloudWatchSettings{}}, nil
|
||||
})
|
||||
|
||||
|
@ -71,7 +71,7 @@ func queryData(ctx context.Context, queries []backend.DataQuery, dsInfo *es.Data
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
jsonData := map[string]any{}
|
||||
err := json.Unmarshal(settings.JSONData, &jsonData)
|
||||
if err != nil {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package elasticsearch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
@ -30,7 +31,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
JSONData: json.RawMessage(settingsJSON),
|
||||
}
|
||||
|
||||
_, err = newInstanceSettings(httpclient.NewProvider())(dsSettings)
|
||||
_, err = newInstanceSettings(httpclient.NewProvider())(context.Background(), dsSettings)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@ -49,7 +50,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
JSONData: json.RawMessage(settingsJSON),
|
||||
}
|
||||
|
||||
_, err = newInstanceSettings(httpclient.NewProvider())(dsSettings)
|
||||
_, err = newInstanceSettings(httpclient.NewProvider())(context.Background(), dsSettings)
|
||||
require.EqualError(t, err, "timeField cannot be cast to string")
|
||||
})
|
||||
|
||||
@ -68,7 +69,7 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
JSONData: json.RawMessage(settingsJSON),
|
||||
}
|
||||
|
||||
_, err = newInstanceSettings(httpclient.NewProvider())(dsSettings)
|
||||
_, err = newInstanceSettings(httpclient.NewProvider())(context.Background(), dsSettings)
|
||||
require.EqualError(t, err, "elasticsearch time field name is required")
|
||||
})
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ func ProvideService(httpClientProvider httpclient.Provider, ac accesscontrol.Acc
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider, ac accesscontrol.AccessControl) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return NewPyroscopeDatasource(httpClientProvider, settings, ac)
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ type datasourceInfo struct {
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -31,7 +31,7 @@ func ProvideService(httpClient httpclient.Provider) *Service {
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -12,6 +12,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
pluginFakes "github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service"
|
||||
@ -43,9 +45,9 @@ func TestHandleRequest(t *testing.T) {
|
||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, sqlStore.Cfg, featuremgmt.WithFeatures(), acmock.New(), datasourcePermissions, quotaService)
|
||||
require.NoError(t, err)
|
||||
|
||||
pCtxProvider := plugincontext.ProvideService(localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
pCtxProvider := plugincontext.ProvideService(sqlStore.Cfg, localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{{JSONData: plugins.JSONData{ID: "test"}}},
|
||||
}, dsService, pluginSettings.ProvideService(sqlStore, secretsService))
|
||||
}, dsService, pluginSettings.ProvideService(sqlStore, secretsService), pluginFakes.NewFakeLicensingService(), &config.Cfg{})
|
||||
s := ProvideService(client, nil, dsService, pCtxProvider)
|
||||
|
||||
ds := &datasources.DataSource{ID: 12, Type: "test", JsonData: simplejson.New()}
|
||||
|
@ -88,7 +88,7 @@ func parseQueryModel(raw json.RawMessage) (*QueryJSONModel, error) {
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -64,7 +64,7 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
||||
}
|
||||
|
||||
func newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
jsonData := sqleng.JsonData{
|
||||
MaxOpenConns: cfg.SqlDatasourceMaxOpenConnsDefault,
|
||||
MaxIdleConns: cfg.SqlDatasourceMaxIdleConnsDefault,
|
||||
|
@ -51,7 +51,7 @@ func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider) *S
|
||||
}
|
||||
|
||||
func newInstanceSettings(cfg *setting.Cfg, httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
jsonData := sqleng.JsonData{
|
||||
MaxOpenConns: cfg.SqlDatasourceMaxOpenConnsDefault,
|
||||
MaxIdleConns: cfg.SqlDatasourceMaxIdleConnsDefault,
|
||||
|
@ -43,7 +43,7 @@ type datasourceInfo struct {
|
||||
type DsAccess string
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -47,7 +47,7 @@ func ProvideService(httpClientProvider httpclient.Provider) *Service {
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return NewParcaDatasource(httpClientProvider, settings)
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
||||
}
|
||||
|
||||
func (s *Service) newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
logger.Debug("Creating Postgres query endpoint")
|
||||
jsonData := sqleng.JsonData{
|
||||
MaxOpenConns: cfg.SqlDatasourceMaxOpenConnsDefault,
|
||||
|
@ -46,7 +46,7 @@ func ProvideService(httpClientProvider httpclient.Provider, cfg *setting.Cfg, fe
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tracer tracing.Tracer) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
// Creates a http roundTripper.
|
||||
opts, err := client.CreateTransportOptions(settings, cfg, plog)
|
||||
if err != nil {
|
||||
|
@ -33,7 +33,7 @@ type Datasource struct {
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
Loading…
Reference in New Issue
Block a user