FeatureFlags: Remove enabled from FeatureFlag model (#79960)

This commit is contained in:
Ryan McKinley
2024-01-10 21:34:18 -08:00
committed by GitHub
parent 48b5ac779b
commit 85d68b88cf
8 changed files with 95 additions and 98 deletions

View File

@@ -22,6 +22,8 @@ type FeatureManager struct {
enabled map[string]bool // only the "on" values
config string // path to config file
vars map[string]any
startup map[string]bool // the explicit values registered at startup
warnings map[string]string // potential warnings about the flag
log log.Logger
}
@@ -73,16 +75,16 @@ func (fm *FeatureManager) registerFlags(flags ...FeatureFlag) {
}
// meetsRequirements checks if grafana is able to run the given feature due to dev mode or licensing requirements
func (fm *FeatureManager) meetsRequirements(ff *FeatureFlag) bool {
func (fm *FeatureManager) meetsRequirements(ff *FeatureFlag) (bool, string) {
if ff.RequiresDevMode && !fm.isDevMod {
return false
return false, "requires dev mode"
}
if ff.RequiresLicense && (fm.licensing == nil || !fm.licensing.FeatureEnabled(ff.Name)) {
return false
return false, "license requirement"
}
return true
return true, ""
}
// Update
@@ -90,14 +92,16 @@ func (fm *FeatureManager) update() {
enabled := make(map[string]bool)
for _, flag := range fm.flags {
// if grafana cannot run the feature, omit metrics around it
if !fm.meetsRequirements(flag) {
ok, reason := fm.meetsRequirements(flag)
if !ok {
fm.warnings[flag.Name] = reason
continue
}
// Update the registry
track := 0.0
// TODO: CEL - expression
if flag.Expression == "true" {
if flag.Expression == "true" || (fm.startup[flag.Name]) {
track = 1
enabled[flag.Name] = true
}
@@ -196,30 +200,35 @@ func WithManager(spec ...any) *FeatureManager {
idx++
}
features[key] = &FeatureFlag{Name: key, Enabled: val}
features[key] = &FeatureFlag{Name: key}
if val {
enabled[key] = true
}
}
return &FeatureManager{enabled: enabled, flags: features}
return &FeatureManager{enabled: enabled, flags: features, startup: enabled, warnings: map[string]string{}}
}
// WithFeatureFlags is used to define feature toggles for testing.
// WithFeatureManager is used to define feature toggle manager for testing.
// It should be used when your test feature toggles require metadata beyond `Name` and `Enabled`.
// You should provide a feature toggle Name at a minimum.
func WithFeatureFlags(flags []*FeatureFlag) *FeatureManager {
func WithFeatureManager(flags []*FeatureFlag, disabled ...string) *FeatureManager {
count := len(flags)
features := make(map[string]*FeatureFlag, count)
enabled := make(map[string]bool, count)
dis := make(map[string]bool)
for _, v := range disabled {
dis[v] = true
}
for _, f := range flags {
if f.Name == "" {
continue
}
features[f.Name] = f
enabled[f.Name] = f.Enabled
enabled[f.Name] = !dis[f.Name]
}
return &FeatureManager{enabled: enabled, flags: features}
return &FeatureManager{enabled: enabled, flags: features, startup: enabled, warnings: map[string]string{}}
}

View File

@@ -26,7 +26,8 @@ func TestFeatureManager(t *testing.T) {
t.Run("check license validation", func(t *testing.T) {
ft := FeatureManager{
flags: map[string]*FeatureFlag{},
flags: map[string]*FeatureFlag{},
warnings: map[string]string{},
}
ft.registerFlags(FeatureFlag{
Name: "a",

View File

@@ -110,8 +110,8 @@ func (s *FeatureFlagStage) UnmarshalJSON(b []byte) error {
return nil
}
// These are properties about the feature, but not the current state or value for it
type FeatureFlag struct {
// Required properties
Name string `json:"name" yaml:"name"` // Unique name
Description string `json:"description"`
Stage FeatureFlagStage `json:"stage,omitempty"`
@@ -131,9 +131,6 @@ type FeatureFlag struct {
FrontendOnly bool `json:"frontend,omitempty"` // change is only seen in the frontend
HideFromDocs bool `json:"hideFromDocs,omitempty"` // don't add the values to docs
// This field is only for the feature management API. To enable your feature toggle by default, use `Expression`.
Enabled bool `json:"enabled,omitempty"`
// These are currently unused
DocsURL string `json:"docsURL,omitempty"`
RequiresRestart bool `json:"requiresRestart,omitempty"` // The server must be initialized with the value

View File

@@ -826,11 +826,11 @@ var (
{
Name: "alertingNoDataErrorExecution",
Description: "Changes how Alerting state manager handles execution of NoData/Error",
Stage: FeatureStagePrivatePreview,
Stage: FeatureStageGeneralAvailability,
FrontendOnly: false,
Owner: grafanaAlertingSquad,
RequiresRestart: true,
Enabled: true,
Expression: "true", // enabled by default
Created: time.Date(2023, time.August, 15, 12, 0, 0, 0, time.UTC),
},
{

View File

@@ -1,7 +1,6 @@
package featuremgmt
import (
"fmt"
"os"
"path/filepath"
@@ -28,6 +27,8 @@ func ProvideManagerService(cfg *setting.Cfg, licensing licensing.Licensing) (*Fe
licensing: licensing,
flags: make(map[string]*FeatureFlag, 30),
enabled: make(map[string]bool),
startup: make(map[string]bool),
warnings: make(map[string]string),
allowEditing: cfg.FeatureManagement.AllowEditing && cfg.FeatureManagement.UpdateWebhook != "",
log: log.New("featuremgmt"),
}
@@ -41,21 +42,21 @@ func ProvideManagerService(cfg *setting.Cfg, licensing licensing.Licensing) (*Fe
return mgmt, err
}
for key, val := range flags {
flag, ok := mgmt.flags[key]
_, ok := mgmt.flags[key]
if !ok {
switch key {
// renamed the flag so it supports more panels
case "autoMigrateGraphPanels":
flag = mgmt.flags[FlagAutoMigrateOldPanels]
key = FlagAutoMigrateOldPanels
default:
flag = &FeatureFlag{
mgmt.flags[key] = &FeatureFlag{
Name: key,
Stage: FeatureStageUnknown,
}
mgmt.flags[key] = flag
mgmt.warnings[key] = "unknown flag in config"
}
}
flag.Expression = fmt.Sprintf("%t", val) // true | false
mgmt.startup[key] = val
}
// Load config settings

View File

@@ -95,7 +95,7 @@ permissionsFilterRemoveSubquery,experimental,@grafana/backend-platform,2023-08-0
prometheusConfigOverhaulAuth,GA,@grafana/observability-metrics,2023-07-21,false,false,false,false
configurableSchedulerTick,experimental,@grafana/alerting-squad,2023-07-26,false,false,true,false
influxdbSqlSupport,GA,@grafana/observability-metrics,2023-08-02,false,false,true,false
alertingNoDataErrorExecution,privatePreview,@grafana/alerting-squad,2023-08-15,false,false,true,false
alertingNoDataErrorExecution,GA,@grafana/alerting-squad,2023-08-15,false,false,true,false
angularDeprecationUI,experimental,@grafana/plugins-platform-backend,2023-08-29,false,false,false,true
dashgpt,preview,@grafana/dashboards-squad,2023-11-17,false,false,false,true
reportingRetries,preview,@grafana/sharing-squad,2023-08-31,false,false,true,false
1 Name Stage Owner Created requiresDevMode RequiresLicense RequiresRestart FrontendOnly
95 prometheusConfigOverhaulAuth GA @grafana/observability-metrics 2023-07-21 false false false false
96 configurableSchedulerTick experimental @grafana/alerting-squad 2023-07-26 false false true false
97 influxdbSqlSupport GA @grafana/observability-metrics 2023-08-02 false false true false
98 alertingNoDataErrorExecution privatePreview GA @grafana/alerting-squad 2023-08-15 false false true false
99 angularDeprecationUI experimental @grafana/plugins-platform-backend 2023-08-29 false false false true
100 dashgpt preview @grafana/dashboards-squad 2023-11-17 false false false true
101 reportingRetries preview @grafana/sharing-squad 2023-08-31 false false true false