2022-01-26 11:44:20 -06:00
package featuremgmt
import (
"bytes"
2023-11-14 14:50:27 -06:00
"context"
2022-01-26 11:44:20 -06:00
"encoding/json"
)
type FeatureToggles interface {
2024-01-10 05:25:54 -06:00
// IsEnabled checks if a feature is enabled for a given context.
2023-11-14 14:50:27 -06:00
// The settings may be per user, tenant, or globally set in the cloud
IsEnabled ( ctx context . Context , flag string ) bool
2024-01-10 05:25:54 -06:00
// IsEnabledGlobally checks if a flag is configured globally. For now, this is the same
2023-11-14 14:50:27 -06:00
// as the function above, however it will move to only checking flags that
// are configured by the operator and shared across all tenants.
// Use of global feature flags should be limited and careful as they require
// a full server restart for a change to take place.
IsEnabledGlobally ( flag string ) bool
2024-01-09 12:38:06 -06:00
// Get the enabled flags -- this *may* also include disabled flags (with value false)
// but it is guaranteed to have the enabled ones listed
GetEnabled ( ctx context . Context ) map [ string ] bool
2022-01-26 11:44:20 -06:00
}
2023-06-08 11:16:55 -05:00
// FeatureFlagStage indicates the quality level
type FeatureFlagStage int
2022-01-26 11:44:20 -06:00
const (
2023-06-08 11:16:55 -05:00
// FeatureStageUnknown indicates that no state is specified
FeatureStageUnknown FeatureFlagStage = iota
2022-01-26 11:44:20 -06:00
2023-06-08 11:16:55 -05:00
// FeatureStageExperimental -- Does this work for Grafana Labs?
FeatureStageExperimental
2022-01-26 11:44:20 -06:00
2023-06-08 11:16:55 -05:00
// FeatureStagePrivatePreview -- Does this work for a limited number of customers?
FeatureStagePrivatePreview
2022-01-26 11:44:20 -06:00
2023-06-08 11:16:55 -05:00
// FeatureStagePublicPreview -- Does this work for most customers?
FeatureStagePublicPreview
2022-01-26 11:44:20 -06:00
2023-06-08 11:16:55 -05:00
// FeatureStageGeneralAvailability -- Feature is available to all applicable customers
FeatureStageGeneralAvailability
// FeatureStageDeprecated the feature will be removed in the future
FeatureStageDeprecated
2022-01-26 11:44:20 -06:00
)
2023-06-08 11:16:55 -05:00
func ( s FeatureFlagStage ) String ( ) string {
2022-01-26 11:44:20 -06:00
switch s {
2023-06-08 11:16:55 -05:00
case FeatureStageExperimental :
return "experimental"
case FeatureStagePrivatePreview :
return "privatePreview"
case FeatureStagePublicPreview :
return "preview"
case FeatureStageGeneralAvailability :
return "GA"
case FeatureStageDeprecated :
2022-01-26 11:44:20 -06:00
return "deprecated"
2023-06-08 11:16:55 -05:00
case FeatureStageUnknown :
2022-01-26 11:44:20 -06:00
}
return "unknown"
}
// MarshalJSON marshals the enum as a quoted json string
2023-06-08 11:16:55 -05:00
func ( s FeatureFlagStage ) MarshalJSON ( ) ( [ ] byte , error ) {
2022-01-26 11:44:20 -06:00
buffer := bytes . NewBufferString ( ` " ` )
buffer . WriteString ( s . String ( ) )
buffer . WriteString ( ` " ` )
return buffer . Bytes ( ) , nil
}
// UnmarshalJSON unmarshals a quoted json string to the enum value
2023-06-08 11:16:55 -05:00
func ( s * FeatureFlagStage ) UnmarshalJSON ( b [ ] byte ) error {
2022-01-26 11:44:20 -06:00
var j string
err := json . Unmarshal ( b , & j )
if err != nil {
return err
}
switch j {
case "alpha" :
2023-06-08 11:16:55 -05:00
fallthrough
case "experimental" :
* s = FeatureStageExperimental
case "privatePreview" :
* s = FeatureStagePrivatePreview
2022-01-26 11:44:20 -06:00
case "beta" :
2023-06-08 11:16:55 -05:00
fallthrough
case "preview" :
* s = FeatureStagePublicPreview
2022-01-26 11:44:20 -06:00
case "stable" :
2023-06-08 11:16:55 -05:00
fallthrough
case "ga" :
fallthrough
case "GA" :
* s = FeatureStageGeneralAvailability
2022-01-26 11:44:20 -06:00
case "deprecated" :
2023-06-08 11:16:55 -05:00
* s = FeatureStageDeprecated
2022-01-26 11:44:20 -06:00
default :
2023-06-08 11:16:55 -05:00
* s = FeatureStageUnknown
2022-01-26 11:44:20 -06:00
}
return nil
}
2024-01-10 23:34:18 -06:00
// These are properties about the feature, but not the current state or value for it
2022-01-26 11:44:20 -06:00
type FeatureFlag struct {
Name string ` json:"name" yaml:"name" ` // Unique name
Description string ` json:"description" `
2023-06-08 11:16:55 -05:00
Stage FeatureFlagStage ` json:"stage,omitempty" `
2024-02-09 17:34:12 -06:00
Owner codeowner ` json:"-" ` // Owner person or team that owns this feature flag
2022-01-26 11:44:20 -06:00
2023-12-18 12:55:21 -06:00
// Recommended properties - control behavior of the feature toggle management page in the UI
2024-02-09 10:48:56 -06:00
AllowSelfServe bool ` json:"allowSelfServe,omitempty" ` // allow users with the right privileges to toggle this from the UI (GeneralAvailability, PublicPreview, and Deprecated toggles only)
2023-12-18 12:55:21 -06:00
HideFromAdminPage bool ` json:"hideFromAdminPage,omitempty" ` // GA, Deprecated, and PublicPreview toggles only: don't display this feature in the UI; if this is a GA toggle, add a comment with the reasoning
2023-03-07 10:04:20 -06:00
2022-01-26 11:44:20 -06:00
// CEL-GO expression. Using the value "true" will mean this is on by default
Expression string ` json:"expression,omitempty" `
2023-12-18 12:55:21 -06:00
// Special behavior properties
2022-01-26 11:44:20 -06:00
RequiresDevMode bool ` json:"requiresDevMode,omitempty" ` // can not be enabled in production
2023-12-18 12:55:21 -06:00
FrontendOnly bool ` json:"frontend,omitempty" ` // change is only seen in the frontend
HideFromDocs bool ` json:"hideFromDocs,omitempty" ` // don't add the values to docs
2023-07-24 15:12:59 -05:00
2024-01-31 00:25:16 -06:00
// The server must be initialized with the value
RequiresRestart bool ` json:"requiresRestart,omitempty" `
2023-08-09 10:32:28 -05:00
}
2024-02-01 22:52:02 -06:00
type FeatureToggleWebhookPayload struct {
FeatureToggles map [ string ] string ` json:"feature_toggles" `
User string ` json:"user" `
2023-10-13 05:54:34 -05:00
}