diff --git a/pkg/plugins/envvars/envvars.go b/pkg/plugins/envvars/envvars.go index 33cdcf63e0b..b21aef63066 100644 --- a/pkg/plugins/envvars/envvars.go +++ b/pkg/plugins/envvars/envvars.go @@ -31,7 +31,7 @@ func NewProvider(cfg *config.Cfg, license plugins.Licensing) *Service { } } -func (s *Service) Get(_ context.Context, p *plugins.Plugin) []string { +func (s *Service) Get(ctx context.Context, p *plugins.Plugin) []string { hostEnv := []string{ fmt.Sprintf("GF_VERSION=%s", s.cfg.BuildVersion), } @@ -56,6 +56,7 @@ func (s *Service) Get(_ context.Context, p *plugins.Plugin) []string { ) } + hostEnv = append(hostEnv, s.featureToggleEnableVar(ctx)...) hostEnv = append(hostEnv, s.awsEnvVars()...) hostEnv = append(hostEnv, s.secureSocksProxyEnvVars()...) hostEnv = append(hostEnv, azsettings.WriteToEnvStr(s.cfg.Azure)...) @@ -84,6 +85,24 @@ func (s *Service) tracingEnvVars(plugin *plugins.Plugin) []string { return vars } +func (s *Service) featureToggleEnableVar(ctx context.Context) []string { + var variables []string // an array is used for consistency and keep the logic simpler for no features case + + 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) + } + variables = append(variables, fmt.Sprintf("GF_INSTANCE_FEATURE_TOGGLES_ENABLE=%s", strings.Join(features, ","))) + } + } + + return variables +} + func (s *Service) awsEnvVars() []string { var variables []string if s.cfg.AWSAssumeRoleEnabled { diff --git a/pkg/plugins/envvars/envvars_test.go b/pkg/plugins/envvars/envvars_test.go index dd0745657ad..1482a5f7559 100644 --- a/pkg/plugins/envvars/envvars_test.go +++ b/pkg/plugins/envvars/envvars_test.go @@ -345,3 +345,37 @@ func TestInitalizer_awsEnvVars(t *testing.T) { assert.ElementsMatch(t, []string{"GF_VERSION=", "AWS_AUTH_AssumeRoleEnabled=true", "AWS_AUTH_AllowedAuthProviders=grafana_assume_role,keys", "AWS_AUTH_EXTERNAL_ID=mock_external_id"}, envVars) }) } + +func TestInitializer_featureToggleEnvVar(t *testing.T) { + t.Run("backend datasource with feature toggle", func(t *testing.T) { + expectedFeatures := []string{"feat-1", "feat-2"} + featuresLookup := map[string]bool{ + expectedFeatures[0]: true, + expectedFeatures[1]: true, + } + + p := &plugins.Plugin{} + envVarsProvider := NewProvider(&config.Cfg{ + Features: featuremgmt.WithFeatures(expectedFeatures[0], true, expectedFeatures[1], true), + }, nil) + envVars := envVarsProvider.Get(context.Background(), p) + + assert.Equal(t, 2, len(envVars)) + + toggleExpression := strings.Split(envVars[1], "=") + assert.Equal(t, 2, len(toggleExpression)) + + assert.Equal(t, "GF_INSTANCE_FEATURE_TOGGLES_ENABLE", toggleExpression[0]) + + toggleArgs := toggleExpression[1] + features := strings.Split(toggleArgs, ",") + + assert.Equal(t, len(expectedFeatures), len(features)) + + // this is necessary because the features are not returned in the order they are provided + for _, f := range features { + _, ok := featuresLookup[f] + assert.True(t, ok) + } + }) +} diff --git a/pkg/plugins/ifaces.go b/pkg/plugins/ifaces.go index 1ed75c2d2ec..a919e69303c 100644 --- a/pkg/plugins/ifaces.go +++ b/pkg/plugins/ifaces.go @@ -164,6 +164,7 @@ func (fn ClientMiddlewareFunc) CreateClientMiddleware(next Client) Client { type FeatureToggles interface { IsEnabled(flag string) bool + GetEnabled(ctx context.Context) map[string]bool } type SignatureCalculator interface { diff --git a/pkg/services/pluginsintegration/config/config.go b/pkg/services/pluginsintegration/config/config.go index fafca1e9d0a..8b76dbcb3de 100644 --- a/pkg/services/pluginsintegration/config/config.go +++ b/pkg/services/pluginsintegration/config/config.go @@ -42,7 +42,7 @@ func ProvideConfig(settingProvider setting.Provider, grafanaCfg *setting.Cfg, fe grafanaCfg.PluginsCDNURLTemplate, grafanaCfg.AppURL, tracingCfg, - featuremgmt.ProvideToggles(features), + features, grafanaCfg.AngularSupportEnabled, grafanaCfg.GrafanaComURL, ), nil