Alerting: Make Unified Alerting enabled by default for those who do not use legacy alerting (#42200)
* update AlertingEnabled and UnifiedAlertingSettings.Enabled to be pointers * add a pseudo migration to fix the AlertingEnabled and UnifiedAlertingSettings.Enabled if the latter is not defined * update the default configuration file to make default value for both 'enabled' flags be undefined Misc * update Migrator to expose DB engine. This is needed for a ualert migration to access the database while the list of migrations is created. * add more verbose failure when migrations do not match Co-authored-by: gotjosh <josue@grafana.com> Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
This commit is contained in:
co-authored by
gotjosh
Yuriy Tseretyan
gillesdemey
parent
1c261aea8e
commit
6523486122
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
|
||||
@@ -153,7 +154,7 @@ var (
|
||||
Quota QuotaSettings
|
||||
|
||||
// Alerting
|
||||
AlertingEnabled bool
|
||||
AlertingEnabled *bool
|
||||
ExecuteAlerts bool
|
||||
AlertingRenderLimit int
|
||||
AlertingErrorOrTimeout string
|
||||
@@ -914,9 +915,6 @@ func (cfg *Cfg) Load(args CommandLineArgs) error {
|
||||
if err := readAlertingSettings(iniFile); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.ReadUnifiedAlertingSettings(iniFile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
explore := iniFile.Section("explore")
|
||||
ExploreEnabled = explore.Key("enabled").MustBool(true)
|
||||
@@ -1377,7 +1375,11 @@ func (cfg *Cfg) readFeatureToggles(iniFile *ini.File) error {
|
||||
|
||||
func readAlertingSettings(iniFile *ini.File) error {
|
||||
alerting := iniFile.Section("alerting")
|
||||
AlertingEnabled = alerting.Key("enabled").MustBool(true)
|
||||
enabled, err := alerting.Key("enabled").Bool()
|
||||
AlertingEnabled = nil
|
||||
if err == nil {
|
||||
AlertingEnabled = &enabled
|
||||
}
|
||||
ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
|
||||
AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ func (cfg *Cfg) readQuotaSettings() {
|
||||
|
||||
var alertOrgQuota int64
|
||||
var alertGlobalQuota int64
|
||||
if cfg.UnifiedAlerting.Enabled {
|
||||
if cfg.UnifiedAlerting.IsEnabled() {
|
||||
alertOrgQuota = quota.Key("org_alert_rule").MustInt64(100)
|
||||
alertGlobalQuota = quota.Key("global_alert_rule").MustInt64(-1)
|
||||
}
|
||||
|
||||
+41
-112
@@ -446,8 +446,10 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.Equal(t, AlertingEnabled, true)
|
||||
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -461,12 +463,14 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when both alerting are enabled, it should error",
|
||||
desc: "when both alerting are enabled",
|
||||
legacyAlertingEnabled: "true",
|
||||
unifiedAlertingEnabled: "true",
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
@@ -479,8 +483,8 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is invalid and unified is disabled",
|
||||
legacyAlertingEnabled: "invalid",
|
||||
desc: "when legacy alerting is invalid (or not defined) and unified is disabled",
|
||||
legacyAlertingEnabled: "",
|
||||
unifiedAlertingEnabled: "false",
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
@@ -489,13 +493,15 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.Equal(t, AlertingEnabled, true)
|
||||
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is invalid and unified is enabled",
|
||||
legacyAlertingEnabled: "invalid",
|
||||
desc: "when legacy alerting is invalid (or not defined) and unified is enabled",
|
||||
legacyAlertingEnabled: "",
|
||||
unifiedAlertingEnabled: "true",
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
@@ -503,13 +509,17 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
err = cfg.readFeatureToggles(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.Error(t, err)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is enabled and unified is invalid",
|
||||
desc: "when legacy alerting is enabled and unified is invalid (or not defined)",
|
||||
legacyAlertingEnabled: "true",
|
||||
unifiedAlertingEnabled: "invalid",
|
||||
unifiedAlertingEnabled: "",
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
@@ -517,12 +527,13 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.Equal(t, AlertingEnabled, true)
|
||||
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is disabled and unified is invalid",
|
||||
desc: "when legacy alerting is disabled and unified is invalid (or not defined)",
|
||||
legacyAlertingEnabled: "false",
|
||||
unifiedAlertingEnabled: "invalid",
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
@@ -532,12 +543,14 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when both are invalid",
|
||||
desc: "when both are invalid (or not defined)",
|
||||
legacyAlertingEnabled: "invalid",
|
||||
unifiedAlertingEnabled: "invalid",
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
@@ -547,31 +560,14 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.Equal(t, AlertingEnabled, true)
|
||||
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Nil(t, AlertingEnabled)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is enabled and unified is disabled and feature toggle is set",
|
||||
legacyAlertingEnabled: "true",
|
||||
unifiedAlertingEnabled: "false",
|
||||
featureToggleSet: true,
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.readFeatureToggles(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is disabled and unified is disabled and feature toggle is set",
|
||||
desc: "when both are false",
|
||||
legacyAlertingEnabled: "false",
|
||||
unifiedAlertingEnabled: "false",
|
||||
featureToggleSet: true,
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
@@ -579,70 +575,10 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is disabled and unified is invalid and feature toggle is set",
|
||||
legacyAlertingEnabled: "false",
|
||||
unifiedAlertingEnabled: "invalid",
|
||||
featureToggleSet: true,
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.readFeatureToggles(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is invalid and unified is disabled and feature toggle is set",
|
||||
legacyAlertingEnabled: "invalid",
|
||||
unifiedAlertingEnabled: "false",
|
||||
featureToggleSet: true,
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.readFeatureToggles(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when legacy alerting is invalid and unified is enabled and feature toggle is set",
|
||||
legacyAlertingEnabled: "invalid",
|
||||
unifiedAlertingEnabled: "true",
|
||||
featureToggleSet: true,
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.readFeatureToggles(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.Error(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "when both are invalid and feature toggle is set",
|
||||
legacyAlertingEnabled: "invalid",
|
||||
unifiedAlertingEnabled: "invalid",
|
||||
featureToggleSet: true,
|
||||
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
|
||||
err := readAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.readFeatureToggles(f)
|
||||
require.NoError(t, err)
|
||||
err = cfg.ReadUnifiedAlertingSettings(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, cfg.UnifiedAlerting.Enabled, true)
|
||||
assert.Equal(t, AlertingEnabled, false)
|
||||
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
|
||||
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false)
|
||||
assert.NotNil(t, AlertingEnabled)
|
||||
assert.Equal(t, *AlertingEnabled, false)
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -650,7 +586,7 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
t.Cleanup(func() {
|
||||
AlertingEnabled = false
|
||||
AlertingEnabled = nil
|
||||
})
|
||||
|
||||
f := ini.Empty()
|
||||
@@ -665,13 +601,6 @@ func TestAlertingEnabled(t *testing.T) {
|
||||
_, err = alertingSec.NewKey("enabled", tc.legacyAlertingEnabled)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.featureToggleSet {
|
||||
alertingSec, err := f.NewSection("feature_toggles")
|
||||
require.NoError(t, err)
|
||||
_, err = alertingSec.NewKey("enable", "ngalert")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
tc.verifyCfg(t, *cfg, f)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
|
||||
"github.com/prometheus/alertmanager/cluster"
|
||||
@@ -63,26 +64,60 @@ type UnifiedAlertingSettings struct {
|
||||
EvaluationTimeout time.Duration
|
||||
ExecuteAlerts bool
|
||||
DefaultConfiguration string
|
||||
Enabled bool
|
||||
Enabled *bool // determines whether unified alerting is enabled. If it is nil then user did not define it and therefore its value will be determined during migration. Services should not use it directly.
|
||||
DisabledOrgs map[int64]struct{}
|
||||
}
|
||||
|
||||
// IsEnabled returns true if UnifiedAlertingSettings.Enabled is either nil or true.
|
||||
// It hides the implementation details of the Enabled and simplifies its usage.
|
||||
func (u *UnifiedAlertingSettings) IsEnabled() bool {
|
||||
return u.Enabled == nil || *u.Enabled
|
||||
}
|
||||
|
||||
func (cfg *Cfg) readUnifiedAlertingEnabledSetting(section *ini.Section) (*bool, error) {
|
||||
enabled, err := section.Key("enabled").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"] {
|
||||
cfg.Logger.Warn("ngalert feature flag is deprecated: use unified alerting enabled setting instead")
|
||||
enabled = true
|
||||
// feature flag overrides the legacy alerting setting.
|
||||
legacyAlerting := false
|
||||
AlertingEnabled = &legacyAlerting
|
||||
return &enabled, nil
|
||||
}
|
||||
// next, check whether legacy flag is set
|
||||
if AlertingEnabled != nil && !*AlertingEnabled {
|
||||
enabled = true
|
||||
return &enabled, nil // if legacy alerting is explicitly disabled, enable the unified alerting by default.
|
||||
}
|
||||
// NOTE: If the enabled flag is still not defined, the final decision is made during migration (see sqlstore.migrations.ualert.CheckUnifiedAlertingEnabledByDefault).
|
||||
cfg.Logger.Info("The state of unified alerting is still not defined. The decision will be made during as we run the database migrations")
|
||||
return nil, nil // the flag is not defined
|
||||
}
|
||||
|
||||
// If unified alerting is defined explicitly as well as legacy alerting and both are enabled, return error.
|
||||
if enabled && AlertingEnabled != nil && *AlertingEnabled {
|
||||
return nil, errors.New("both legacy and Grafana 8 Alerts are enabled. Disable one of them and restart")
|
||||
}
|
||||
// if legacy alerting is not defined but unified is determined then update the legacy with inverted value
|
||||
if AlertingEnabled == nil {
|
||||
legacyEnabled := !enabled
|
||||
AlertingEnabled = &legacyEnabled
|
||||
}
|
||||
return &enabled, nil
|
||||
}
|
||||
|
||||
// ReadUnifiedAlertingSettings reads both the `unified_alerting` and `alerting` sections of the configuration while preferring configuration the `alerting` section.
|
||||
// It first reads the `unified_alerting` section, then looks for non-defaults on the `alerting` section and prefers those.
|
||||
func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error {
|
||||
var err error
|
||||
uaCfg := UnifiedAlertingSettings{}
|
||||
ua := iniFile.Section("unified_alerting")
|
||||
uaCfg.Enabled = ua.Key("enabled").MustBool(false)
|
||||
|
||||
// TODO: Deprecate this in v8.4, if the old feature toggle ngalert is set, enable Grafana 8 Unified Alerting anyway.
|
||||
if !uaCfg.Enabled && cfg.FeatureToggles["ngalert"] {
|
||||
cfg.Logger.Warn("ngalert feature flag is deprecated: use unified alerting enabled setting instead")
|
||||
uaCfg.Enabled = true
|
||||
AlertingEnabled = false
|
||||
}
|
||||
|
||||
if uaCfg.Enabled && AlertingEnabled {
|
||||
return errors.New("both legacy and Grafana 8 Alerts are enabled")
|
||||
uaCfg.Enabled, err = cfg.readUnifiedAlertingEnabledSetting(ua)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uaCfg.DisabledOrgs = make(map[int64]struct{})
|
||||
@@ -95,7 +130,6 @@ func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error {
|
||||
uaCfg.DisabledOrgs[orgID] = struct{}{}
|
||||
}
|
||||
|
||||
var err error
|
||||
uaCfg.AdminConfigPollInterval, err = gtime.ParseDuration(valueAsString(ua, "admin_config_poll_interval", (schedulerDefaultAdminConfigPollInterval).String()))
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user