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 {
2023-11-14 14:50:27 -06:00
// Check if a feature is enabled for a given context.
// The settings may be per user, tenant, or globally set in the cloud
IsEnabled ( ctx context . Context , flag string ) bool
// Check if a flag is configured globally. For now, this is the same
// 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
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
}
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" `
2022-01-26 11:44:20 -06:00
DocsURL string ` json:"docsURL,omitempty" `
2023-03-07 10:04:20 -06:00
// Owner person or team that owns this feature flag
Owner codeowner ` json:"-" `
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" `
// Special behavior flags
RequiresDevMode bool ` json:"requiresDevMode,omitempty" ` // can not be enabled in production
2023-10-20 09:00:37 -05:00
// This flag is currently unused.
2023-11-03 10:59:07 -05:00
RequiresRestart bool ` json:"requiresRestart,omitempty" ` // The server must be initialized with the value
RequiresLicense bool ` json:"requiresLicense,omitempty" ` // Must be enabled in the license
FrontendOnly bool ` json:"frontend,omitempty" ` // change is only seen in the frontend
HideFromDocs bool ` json:"hideFromDocs,omitempty" ` // don't add the values to docs
HideFromAdminPage bool ` json:"hideFromAdminPage,omitempty" ` // don't display the feature in the admin page - add a comment with the reasoning
AllowSelfServe * bool ` json:"allowSelfServe,omitempty" ` // allow admin users to toggle the feature state from the admin page; this is required for GA toggles only
2023-07-24 15:12:59 -05:00
2023-10-20 09:00:37 -05:00
// This field is only for the feature management API. To enable your feature toggle by default, use `Expression`.
2023-08-09 10:32:28 -05:00
Enabled bool ` json:"enabled,omitempty" `
}
type UpdateFeatureTogglesCommand struct {
FeatureToggles [ ] FeatureToggleDTO ` json:"featureToggles" `
}
type FeatureToggleDTO struct {
Name string ` json:"name" binding:"Required" `
Description string ` json:"description" `
Enabled bool ` json:"enabled" `
ReadOnly bool ` json:"readOnly,omitempty" `
2022-01-26 11:44:20 -06:00
}
2023-10-13 05:54:34 -05:00
type FeatureManagerState struct {
RestartRequired bool ` json:"restartRequired" `
2023-10-26 04:42:00 -05:00
AllowEditing bool ` json:"allowEditing" `
2023-10-13 05:54:34 -05:00
}