mirror of https://github.com/grafana/grafana
setting: configure toggles as true/false instead of array (#43326)
Signed-off-by: bergquist <carl.bergquist@gmail.com>pull/43379/head
parent
dda84dbf1a
commit
f373588810
@ -0,0 +1,74 @@ |
||||
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, |
||||
} |
||||
) |
||||
|
||||
func (cfg *Cfg) readFeatureToggles(iniFile *ini.File) error { |
||||
toggles, err := overrideDefaultWithConfiguration(iniFile, defaultFeatureToggles) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cfg.FeatureToggles = toggles |
||||
|
||||
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") |
||||
|
||||
// parse the comma separated list in `enable`.
|
||||
featuresTogglesStr := valueAsString(featureTogglesSection, "enable", "") |
||||
for _, feature := range util.SplitString(featuresTogglesStr) { |
||||
featureToggles[feature] = true |
||||
} |
||||
|
||||
// read all other settings under [feature_toggles]. If a toggle is
|
||||
// present in both the value in `enable` is overridden.
|
||||
for _, v := range featureTogglesSection.Keys() { |
||||
if v.Name() == "enable" { |
||||
continue |
||||
} |
||||
|
||||
b, err := strconv.ParseBool(v.Value()) |
||||
if err != nil { |
||||
return featureToggles, err |
||||
} |
||||
|
||||
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 |
||||
} |
||||
@ -0,0 +1,98 @@ |
||||
package setting |
||||
|
||||
import ( |
||||
"strconv" |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/require" |
||||
"gopkg.in/ini.v1" |
||||
) |
||||
|
||||
func TestFeatureToggles(t *testing.T) { |
||||
testCases := []struct { |
||||
name string |
||||
conf map[string]string |
||||
err error |
||||
expectedToggles map[string]bool |
||||
defaultToggles map[string]bool |
||||
}{ |
||||
{ |
||||
name: "can parse feature toggles passed in the `enable` array", |
||||
conf: map[string]string{ |
||||
"enable": "feature1,feature2", |
||||
}, |
||||
expectedToggles: map[string]bool{ |
||||
"feature1": true, |
||||
"feature2": true, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "can parse feature toggles listed under [feature_toggles]", |
||||
conf: map[string]string{ |
||||
"enable": "feature1,feature2", |
||||
"feature3": "true", |
||||
}, |
||||
expectedToggles: map[string]bool{ |
||||
"feature1": true, |
||||
"feature2": true, |
||||
"feature3": true, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "toggles under [feature_toggles] overrides those in the array", |
||||
conf: map[string]string{ |
||||
"enable": "feature1,feature2", |
||||
"feature2": "false", |
||||
}, |
||||
expectedToggles: map[string]bool{ |
||||
"feature1": true, |
||||
"feature2": false, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "invalid boolean value should return syntax error", |
||||
conf: map[string]string{ |
||||
"enable": "feature1,feature2", |
||||
"feature2": "invalid", |
||||
}, |
||||
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 { |
||||
f := ini.Empty() |
||||
|
||||
toggles, _ := f.NewSection("feature_toggles") |
||||
for k, v := range tc.conf { |
||||
_, err := toggles.NewKey(k, v) |
||||
require.ErrorIs(t, err, nil) |
||||
} |
||||
|
||||
dt := map[string]bool{} |
||||
if len(tc.defaultToggles) > 0 { |
||||
dt = tc.defaultToggles |
||||
} |
||||
|
||||
featureToggles, err := overrideDefaultWithConfiguration(f, dt) |
||||
require.ErrorIs(t, err, tc.err) |
||||
|
||||
if err == nil { |
||||
for k, v := range featureToggles { |
||||
require.Equal(t, tc.expectedToggles[k], v, tc.name) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue