From 7fca1bde54ff6d95b493e6d4d40d8bc2a001542c Mon Sep 17 00:00:00 2001 From: Will Browne Date: Thu, 21 Sep 2023 11:33:31 +0200 Subject: [PATCH] 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 --- go.mod | 2 +- go.sum | 2 + pkg/api/metrics_test.go | 24 ++--- pkg/api/plugin_resource_test.go | 5 +- pkg/expr/dataplane_test.go | 6 +- pkg/expr/service_test.go | 10 +- pkg/plugins/envvars/envvars.go | 97 ++++++++++++++++++- .../plugincontext/plugincontext.go | 49 ++++++++-- .../pluginsintegration/pluginstore/plugins.go | 6 +- .../publicdashboards/api/common_test.go | 18 ++-- pkg/services/query/query_test.go | 6 +- pkg/tsdb/azuremonitor/azuremonitor.go | 2 +- pkg/tsdb/azuremonitor/azuremonitor_test.go | 2 +- pkg/tsdb/cloud-monitoring/cloudmonitoring.go | 2 +- .../cloud-monitoring/cloudmonitoring_test.go | 6 +- pkg/tsdb/cloudwatch/annotation_query_test.go | 4 +- pkg/tsdb/cloudwatch/cloudwatch.go | 2 +- .../cloudwatch/cloudwatch_integration_test.go | 2 +- pkg/tsdb/cloudwatch/cloudwatch_test.go | 12 +-- pkg/tsdb/cloudwatch/log_actions_test.go | 20 ++-- pkg/tsdb/cloudwatch/log_sync_query_test.go | 16 +-- pkg/tsdb/cloudwatch/metric_find_query_test.go | 10 +- pkg/tsdb/cloudwatch/time_series_query_test.go | 10 +- pkg/tsdb/elasticsearch/elasticsearch.go | 2 +- pkg/tsdb/elasticsearch/elasticsearch_test.go | 7 +- .../grafana-pyroscope-datasource/service.go | 2 +- pkg/tsdb/graphite/graphite.go | 2 +- pkg/tsdb/influxdb/influxdb.go | 2 +- pkg/tsdb/legacydata/service/service_test.go | 6 +- pkg/tsdb/loki/loki.go | 2 +- pkg/tsdb/mssql/mssql.go | 2 +- pkg/tsdb/mysql/mysql.go | 2 +- pkg/tsdb/opentsdb/opentsdb.go | 2 +- pkg/tsdb/parca/service.go | 2 +- pkg/tsdb/postgres/postgres.go | 2 +- pkg/tsdb/prometheus/prometheus.go | 2 +- pkg/tsdb/tempo/tempo.go | 2 +- 37 files changed, 248 insertions(+), 102 deletions(-) diff --git a/go.mod b/go.mod index 1559f7675e7..82f1f2a20de 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 42529968d15..d977ffb5214 100644 --- a/go.sum +++ b/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= diff --git a/pkg/api/metrics_test.go b/pkg/api/metrics_test.go index e5076b3a463..c3c11d74200 100644 --- a/pkg/api/metrics_test.go +++ b/pkg/api/metrics_test.go @@ -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) }) diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go index 8c94ba482ef..fd07728a2d0 100644 --- a/pkg/api/plugin_resource_test.go +++ b/pkg/api/plugin_resource_test.go @@ -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 diff --git a/pkg/expr/dataplane_test.go b/pkg/expr/dataplane_test.go index fcec6bf390d..762b2069396 100644 --- a/pkg/expr/dataplane_test.go +++ b/pkg/expr/dataplane_test.go @@ -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), } diff --git a/pkg/expr/service_test.go b/pkg/expr/service_test.go index f4e1d347543..9b0c417a09e 100644 --- a/pkg/expr/service_test.go +++ b/pkg/expr/service_test.go @@ -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(), diff --git a/pkg/plugins/envvars/envvars.go b/pkg/plugins/envvars/envvars.go index b21aef63066..bf34b63e545 100644 --- a/pkg/plugins/envvars/envvars.go +++ b/pkg/plugins/envvars/envvars.go @@ -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)) diff --git a/pkg/services/pluginsintegration/plugincontext/plugincontext.go b/pkg/services/pluginsintegration/plugincontext/plugincontext.go index a04343c56e7..04dd0062c2c 100644 --- a/pkg/services/pluginsintegration/plugincontext/plugincontext.go +++ b/pkg/services/pluginsintegration/plugincontext/plugincontext.go @@ -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{} diff --git a/pkg/services/pluginsintegration/pluginstore/plugins.go b/pkg/services/pluginsintegration/pluginstore/plugins.go index 9df08ac0355..4617f48b377 100644 --- a/pkg/services/pluginsintegration/pluginstore/plugins.go +++ b/pkg/services/pluginsintegration/pluginstore/plugins.go @@ -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, } } diff --git a/pkg/services/publicdashboards/api/common_test.go b/pkg/services/publicdashboards/api/common_test.go index 2a34d991648..5a7993d9be3 100644 --- a/pkg/services/publicdashboards/api/common_test.go +++ b/pkg/services/publicdashboards/api/common_test.go @@ -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(), diff --git a/pkg/services/query/query_test.go b/pkg/services/query/query_test.go index 811241d5f94..c1cd5166b6f 100644 --- a/pkg/services/query/query_test.go +++ b/pkg/services/query/query_test.go @@ -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()) diff --git a/pkg/tsdb/azuremonitor/azuremonitor.go b/pkg/tsdb/azuremonitor/azuremonitor.go index a97553dc411..d541b8d44fe 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor.go +++ b/pkg/tsdb/azuremonitor/azuremonitor.go @@ -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 { diff --git a/pkg/tsdb/azuremonitor/azuremonitor_test.go b/pkg/tsdb/azuremonitor/azuremonitor_test.go index 943ce1efb8e..ff703df414f 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor_test.go +++ b/pkg/tsdb/azuremonitor/azuremonitor_test.go @@ -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)) diff --git a/pkg/tsdb/cloud-monitoring/cloudmonitoring.go b/pkg/tsdb/cloud-monitoring/cloudmonitoring.go index 1aab6d6c718..9c1213c03c8 100644 --- a/pkg/tsdb/cloud-monitoring/cloudmonitoring.go +++ b/pkg/tsdb/cloud-monitoring/cloudmonitoring.go @@ -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 { diff --git a/pkg/tsdb/cloud-monitoring/cloudmonitoring_test.go b/pkg/tsdb/cloud-monitoring/cloudmonitoring_test.go index f5a628f21db..8b46c7f4d32 100644 --- a/pkg/tsdb/cloud-monitoring/cloudmonitoring_test.go +++ b/pkg/tsdb/cloud-monitoring/cloudmonitoring_test.go @@ -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 diff --git a/pkg/tsdb/cloudwatch/annotation_query_test.go b/pkg/tsdb/cloudwatch/annotation_query_test.go index e76dcce8ed4..9d2ff5c0fc7 100644 --- a/pkg/tsdb/cloudwatch/annotation_query_test.go +++ b/pkg/tsdb/cloudwatch/annotation_query_test.go @@ -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 }) diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 1cfc63aa3d7..db5deb7d4c1 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -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) diff --git a/pkg/tsdb/cloudwatch/cloudwatch_integration_test.go b/pkg/tsdb/cloudwatch/cloudwatch_integration_test.go index d0d24677b39..65900e76c9e 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch_integration_test.go +++ b/pkg/tsdb/cloudwatch/cloudwatch_integration_test.go @@ -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 }) diff --git a/pkg/tsdb/cloudwatch/cloudwatch_test.go b/pkg/tsdb/cloudwatch/cloudwatch_test.go index f64d98abc19..a2bff2524fc 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch_test.go +++ b/pkg/tsdb/cloudwatch/cloudwatch_test.go @@ -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 }) diff --git a/pkg/tsdb/cloudwatch/log_actions_test.go b/pkg/tsdb/cloudwatch/log_actions_test.go index a78fea6bfcc..08c6c39fb08 100644 --- a/pkg/tsdb/cloudwatch/log_actions_test.go +++ b/pkg/tsdb/cloudwatch/log_actions_test.go @@ -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 }) diff --git a/pkg/tsdb/cloudwatch/log_sync_query_test.go b/pkg/tsdb/cloudwatch/log_sync_query_test.go index 96b27cd848f..88e20ac4ff1 100644 --- a/pkg/tsdb/cloudwatch/log_sync_query_test.go +++ b/pkg/tsdb/cloudwatch/log_sync_query_test.go @@ -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()) diff --git a/pkg/tsdb/cloudwatch/metric_find_query_test.go b/pkg/tsdb/cloudwatch/metric_find_query_test.go index ee95310d685..afc0e1d48ed 100644 --- a/pkg/tsdb/cloudwatch/metric_find_query_test.go +++ b/pkg/tsdb/cloudwatch/metric_find_query_test.go @@ -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 }) diff --git a/pkg/tsdb/cloudwatch/time_series_query_test.go b/pkg/tsdb/cloudwatch/time_series_query_test.go index 30c135f234e..73f3b65767a 100644 --- a/pkg/tsdb/cloudwatch/time_series_query_test.go +++ b/pkg/tsdb/cloudwatch/time_series_query_test.go @@ -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 }) diff --git a/pkg/tsdb/elasticsearch/elasticsearch.go b/pkg/tsdb/elasticsearch/elasticsearch.go index d9ac1fd5e74..4ea44a9f613 100644 --- a/pkg/tsdb/elasticsearch/elasticsearch.go +++ b/pkg/tsdb/elasticsearch/elasticsearch.go @@ -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 { diff --git a/pkg/tsdb/elasticsearch/elasticsearch_test.go b/pkg/tsdb/elasticsearch/elasticsearch_test.go index 8e7a8faba19..3a336e410de 100644 --- a/pkg/tsdb/elasticsearch/elasticsearch_test.go +++ b/pkg/tsdb/elasticsearch/elasticsearch_test.go @@ -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") }) }) diff --git a/pkg/tsdb/grafana-pyroscope-datasource/service.go b/pkg/tsdb/grafana-pyroscope-datasource/service.go index b8830d7e5db..e208372faac 100644 --- a/pkg/tsdb/grafana-pyroscope-datasource/service.go +++ b/pkg/tsdb/grafana-pyroscope-datasource/service.go @@ -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) } } diff --git a/pkg/tsdb/graphite/graphite.go b/pkg/tsdb/graphite/graphite.go index ef8083601ac..44904e4d896 100644 --- a/pkg/tsdb/graphite/graphite.go +++ b/pkg/tsdb/graphite/graphite.go @@ -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 diff --git a/pkg/tsdb/influxdb/influxdb.go b/pkg/tsdb/influxdb/influxdb.go index be4a030d971..bf4eb0b6325 100644 --- a/pkg/tsdb/influxdb/influxdb.go +++ b/pkg/tsdb/influxdb/influxdb.go @@ -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 diff --git a/pkg/tsdb/legacydata/service/service_test.go b/pkg/tsdb/legacydata/service/service_test.go index f80d5a5ace5..40a58fceeec 100644 --- a/pkg/tsdb/legacydata/service/service_test.go +++ b/pkg/tsdb/legacydata/service/service_test.go @@ -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()} diff --git a/pkg/tsdb/loki/loki.go b/pkg/tsdb/loki/loki.go index 1883b2ef19f..85b03120d2c 100644 --- a/pkg/tsdb/loki/loki.go +++ b/pkg/tsdb/loki/loki.go @@ -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 diff --git a/pkg/tsdb/mssql/mssql.go b/pkg/tsdb/mssql/mssql.go index 6200067b292..2b2ad38c975 100644 --- a/pkg/tsdb/mssql/mssql.go +++ b/pkg/tsdb/mssql/mssql.go @@ -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, diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 1fa984cccbd..a408b19bc0b 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -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, diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 197d26e0739..504490a3cef 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -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 diff --git a/pkg/tsdb/parca/service.go b/pkg/tsdb/parca/service.go index 4793f2a9450..08c71da0bfe 100644 --- a/pkg/tsdb/parca/service.go +++ b/pkg/tsdb/parca/service.go @@ -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) } } diff --git a/pkg/tsdb/postgres/postgres.go b/pkg/tsdb/postgres/postgres.go index d8e3eae6446..00952b28a3d 100644 --- a/pkg/tsdb/postgres/postgres.go +++ b/pkg/tsdb/postgres/postgres.go @@ -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, diff --git a/pkg/tsdb/prometheus/prometheus.go b/pkg/tsdb/prometheus/prometheus.go index 1b6a5d54b54..8987b8f0c8b 100644 --- a/pkg/tsdb/prometheus/prometheus.go +++ b/pkg/tsdb/prometheus/prometheus.go @@ -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 { diff --git a/pkg/tsdb/tempo/tempo.go b/pkg/tsdb/tempo/tempo.go index 17115860015..7a75c70b689 100644 --- a/pkg/tsdb/tempo/tempo.go +++ b/pkg/tsdb/tempo/tempo.go @@ -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