mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
FeatureFlags: manage feature flags outside of settings.Cfg (#43692)
This commit is contained in:
@@ -132,7 +132,7 @@ func (o *OSSImpl) Section(section string) Section {
|
||||
func (OSSImpl) RegisterReloadHandler(string, ReloadHandler) {}
|
||||
|
||||
func (o OSSImpl) IsFeatureToggleEnabled(name string) bool {
|
||||
return o.Cfg.FeatureToggles[name]
|
||||
return o.Cfg.IsFeatureToggleEnabled(name)
|
||||
}
|
||||
|
||||
type keyValImpl struct {
|
||||
|
||||
@@ -342,8 +342,10 @@ type Cfg struct {
|
||||
|
||||
ApiKeyMaxSecondsToLive int64
|
||||
|
||||
// Use to enable new features which may still be in alpha/beta stage.
|
||||
FeatureToggles map[string]bool
|
||||
// Check if a feature toggle is enabled
|
||||
// @deprecated
|
||||
IsFeatureToggleEnabled func(key string) bool // filled in dynamically
|
||||
|
||||
AnonymousEnabled bool
|
||||
AnonymousOrgName string
|
||||
AnonymousOrgRole string
|
||||
@@ -429,41 +431,6 @@ type Cfg struct {
|
||||
UnifiedAlerting UnifiedAlertingSettings
|
||||
}
|
||||
|
||||
// IsLiveConfigEnabled returns true if live should be able to save configs to SQL tables
|
||||
func (cfg Cfg) IsLiveConfigEnabled() bool {
|
||||
return cfg.FeatureToggles["live-config"]
|
||||
}
|
||||
|
||||
// IsLiveConfigEnabled returns true if live should be able to save configs to SQL tables
|
||||
func (cfg Cfg) IsDashboardPreviesEnabled() bool {
|
||||
return cfg.FeatureToggles["dashboardPreviews"]
|
||||
}
|
||||
|
||||
// IsTrimDefaultsEnabled returns whether the standalone trim dashboard default feature is enabled.
|
||||
func (cfg Cfg) IsTrimDefaultsEnabled() bool {
|
||||
return cfg.FeatureToggles["trimDefaults"]
|
||||
}
|
||||
|
||||
// IsDatabaseMetricsEnabled returns whether the database instrumentation feature is enabled.
|
||||
func (cfg Cfg) IsDatabaseMetricsEnabled() bool {
|
||||
return cfg.FeatureToggles["database_metrics"]
|
||||
}
|
||||
|
||||
// IsHTTPRequestHistogramDisabled returns whether the request historgrams is disabled.
|
||||
// This feature toggle will be removed in Grafana 8.x but gives the operator
|
||||
// some graceperiod to update all the monitoring tools.
|
||||
func (cfg Cfg) IsHTTPRequestHistogramDisabled() bool {
|
||||
return cfg.FeatureToggles["disable_http_request_histogram"]
|
||||
}
|
||||
|
||||
func (cfg Cfg) IsNewNavigationEnabled() bool {
|
||||
return cfg.FeatureToggles["newNavigation"]
|
||||
}
|
||||
|
||||
func (cfg Cfg) IsServiceAccountEnabled() bool {
|
||||
return cfg.FeatureToggles["service-accounts"]
|
||||
}
|
||||
|
||||
type CommandLineArgs struct {
|
||||
Config string
|
||||
HomePath string
|
||||
|
||||
@@ -3,42 +3,23 @@ package setting
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
featureToggleInfo = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "feature_toggles_info",
|
||||
Help: "info metric that exposes what feature toggles are enabled or not",
|
||||
Namespace: "grafana",
|
||||
}, []string{"name"})
|
||||
|
||||
defaultFeatureToggles = map[string]bool{
|
||||
"recordedQueries": false,
|
||||
"accesscontrol": false,
|
||||
"service-accounts": false,
|
||||
"httpclientprovider_azure_auth": false,
|
||||
}
|
||||
)
|
||||
|
||||
// @deprecated -- should use `featuremgmt.FeatureToggles`
|
||||
func (cfg *Cfg) readFeatureToggles(iniFile *ini.File) error {
|
||||
toggles, err := overrideDefaultWithConfiguration(iniFile, defaultFeatureToggles)
|
||||
section := iniFile.Section("feature_toggles")
|
||||
toggles, err := ReadFeatureTogglesFromInitFile(section)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg.FeatureToggles = toggles
|
||||
|
||||
cfg.IsFeatureToggleEnabled = func(key string) bool { return toggles[key] }
|
||||
return nil
|
||||
}
|
||||
|
||||
func overrideDefaultWithConfiguration(iniFile *ini.File, featureToggles map[string]bool) (map[string]bool, error) {
|
||||
// Read and populate feature toggles list
|
||||
featureTogglesSection := iniFile.Section("feature_toggles")
|
||||
func ReadFeatureTogglesFromInitFile(featureTogglesSection *ini.Section) (map[string]bool, error) {
|
||||
featureToggles := make(map[string]bool, 10)
|
||||
|
||||
// parse the comma separated list in `enable`.
|
||||
featuresTogglesStr := valueAsString(featureTogglesSection, "enable", "")
|
||||
@@ -60,15 +41,5 @@ func overrideDefaultWithConfiguration(iniFile *ini.File, featureToggles map[stri
|
||||
|
||||
featureToggles[v.Name()] = b
|
||||
}
|
||||
|
||||
// track if feature toggles are enabled or not using an info metric
|
||||
for k, v := range featureToggles {
|
||||
if v {
|
||||
featureToggleInfo.WithLabelValues(k).Set(1)
|
||||
} else {
|
||||
featureToggleInfo.WithLabelValues(k).Set(0)
|
||||
}
|
||||
}
|
||||
|
||||
return featureToggles, nil
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ func TestFeatureToggles(t *testing.T) {
|
||||
conf map[string]string
|
||||
err error
|
||||
expectedToggles map[string]bool
|
||||
defaultToggles map[string]bool
|
||||
}{
|
||||
{
|
||||
name: "can parse feature toggles passed in the `enable` array",
|
||||
@@ -58,18 +57,6 @@ func TestFeatureToggles(t *testing.T) {
|
||||
expectedToggles: map[string]bool{},
|
||||
err: strconv.ErrSyntax,
|
||||
},
|
||||
{
|
||||
name: "should override default feature toggles",
|
||||
defaultToggles: map[string]bool{
|
||||
"feature1": true,
|
||||
},
|
||||
conf: map[string]string{
|
||||
"feature1": "false",
|
||||
},
|
||||
expectedToggles: map[string]bool{
|
||||
"feature1": false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -81,12 +68,7 @@ func TestFeatureToggles(t *testing.T) {
|
||||
require.ErrorIs(t, err, nil)
|
||||
}
|
||||
|
||||
dt := map[string]bool{}
|
||||
if len(tc.defaultToggles) > 0 {
|
||||
dt = tc.defaultToggles
|
||||
}
|
||||
|
||||
featureToggles, err := overrideDefaultWithConfiguration(f, dt)
|
||||
featureToggles, err := ReadFeatureTogglesFromInitFile(toggles)
|
||||
require.ErrorIs(t, err, tc.err)
|
||||
|
||||
if err == nil {
|
||||
|
||||
@@ -79,7 +79,7 @@ func (cfg *Cfg) readUnifiedAlertingEnabledSetting(section *ini.Section) (*bool,
|
||||
// the unified alerting is not enabled by default. First, check the feature flag
|
||||
if err != nil {
|
||||
// TODO: Remove in Grafana v9
|
||||
if cfg.FeatureToggles["ngalert"] {
|
||||
if cfg.IsFeatureToggleEnabled("ngalert") {
|
||||
cfg.Logger.Warn("ngalert feature flag is deprecated: use unified alerting enabled setting instead")
|
||||
enabled = true
|
||||
// feature flag overrides the legacy alerting setting.
|
||||
|
||||
@@ -143,6 +143,7 @@ func TestUnifiedAlertingSettings(t *testing.T) {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
f := ini.Empty()
|
||||
cfg := NewCfg()
|
||||
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
||||
unifiedAlertingSec, err := f.NewSection("unified_alerting")
|
||||
require.NoError(t, err)
|
||||
for k, v := range tc.unifiedAlertingOptions {
|
||||
|
||||
Reference in New Issue
Block a user