Alerting: Disable legacy alerting for ever (#83651)

* hard disable for legacy alerting
* remove alerting section from configuration file 
* update documentation to not refer to deleted section
* remove AlertingEnabled from usage in UA setting parsing
This commit is contained in:
Yuri Tseretyan
2024-03-07 16:01:11 -05:00
committed by GitHub
parent 8c7090bc11
commit 7147af6b8e
8 changed files with 50 additions and 555 deletions

View File

@@ -715,6 +715,8 @@ func (cfg *Cfg) readAnnotationSettings() error {
alertingAnnotations := cfg.Raw.Section("unified_alerting.state_history.annotations")
if alertingAnnotations.Key("max_age").Value() == "" && section.Key("max_annotations_to_keep").Value() == "" {
// Although this section is not documented anymore, we decided to keep it to avoid potential data-loss when user upgrades Grafana and does not change the setting.
// TODO delete some time after Grafana 11.
alertingSection := cfg.Raw.Section("alerting")
cleanup := newAnnotationCleanupSettings(alertingSection, "max_annotation_age")
if cleanup.MaxCount > 0 || cleanup.MaxAge > 0 {
@@ -1743,25 +1745,13 @@ func (cfg *Cfg) readRenderingSettings(iniFile *ini.File) error {
}
func (cfg *Cfg) readAlertingSettings(iniFile *ini.File) error {
// This check is kept to prevent users that upgrade to Grafana 11 with the legacy alerting enabled. This should prevent them from accidentally upgrading without migration to Unified Alerting.
alerting := iniFile.Section("alerting")
enabled, err := alerting.Key("enabled").Bool()
cfg.AlertingEnabled = nil
if err == nil {
cfg.AlertingEnabled = &enabled
if err == nil && enabled {
cfg.Logger.Error("Option '[alerting].enabled' cannot be true. Legacy Alerting is removed. It is no longer deployed, enhanced, or supported. Delete '[alerting].enabled' and use '[unified_alerting].enabled' to enable Grafana Alerting. For more information, refer to the documentation on upgrading to Grafana Alerting (https://grafana.com/docs/grafana/v10.4/alerting/set-up/migrating-alerts)")
return fmt.Errorf("invalid setting [alerting].enabled")
}
cfg.ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
cfg.AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
cfg.AlertingErrorOrTimeout = valueAsString(alerting, "error_or_timeout", "alerting")
cfg.AlertingNoDataOrNullValues = valueAsString(alerting, "nodata_or_nullvalues", "no_data")
evaluationTimeoutSeconds := alerting.Key("evaluation_timeout_seconds").MustInt64(30)
cfg.AlertingEvaluationTimeout = time.Second * time.Duration(evaluationTimeoutSeconds)
notificationTimeoutSeconds := alerting.Key("notification_timeout_seconds").MustInt64(30)
cfg.AlertingNotificationTimeout = time.Second * time.Duration(notificationTimeoutSeconds)
cfg.AlertingMaxAttempts = alerting.Key("max_attempts").MustInt(3)
cfg.AlertingMinInterval = alerting.Key("min_interval_seconds").MustInt64(1)
return nil
}

View File

@@ -2,7 +2,6 @@ package setting
import (
"bufio"
"math/rand"
"net/url"
"os"
"path"
@@ -463,356 +462,39 @@ func TestGetCDNPathWithAlphaVersion(t *testing.T) {
}
func TestAlertingEnabled(t *testing.T) {
anyBoolean := func() bool {
return rand.Int63()%2 == 0
}
t.Run("fail if legacy alerting enabled", func(t *testing.T) {
f := ini.Empty()
cfg := NewCfg()
testCases := []struct {
desc string
unifiedAlertingEnabled string
legacyAlertingEnabled string
featureToggleSet bool
isEnterprise bool
verifyCfg func(*testing.T, Cfg, *ini.File)
}{
{
desc: "when legacy alerting is enabled and unified is disabled",
legacyAlertingEnabled: "true",
unifiedAlertingEnabled: "false",
isEnterprise: anyBoolean(),
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), true)
},
},
{
desc: "when legacy alerting is disabled and unified is enabled",
legacyAlertingEnabled: "false",
unifiedAlertingEnabled: "true",
isEnterprise: anyBoolean(),
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), false)
},
},
{
desc: "when both alerting are enabled",
legacyAlertingEnabled: "true",
unifiedAlertingEnabled: "true",
isEnterprise: anyBoolean(),
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.Error(t, err)
},
},
{
desc: "when legacy alerting is invalid (or not defined) and unified is disabled",
legacyAlertingEnabled: "",
unifiedAlertingEnabled: "false",
isEnterprise: anyBoolean(),
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), true)
},
},
{
desc: "when legacy alerting is invalid (or not defined) and unified is enabled",
legacyAlertingEnabled: "",
unifiedAlertingEnabled: "true",
isEnterprise: anyBoolean(),
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), false)
},
},
{
desc: "when legacy alerting is enabled and unified is not defined [OSS]",
legacyAlertingEnabled: "true",
unifiedAlertingEnabled: "",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, true, *cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when legacy alerting is enabled and unified is invalid [OSS]",
legacyAlertingEnabled: "true",
unifiedAlertingEnabled: "invalid",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false")
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when legacy alerting is enabled and unified is not defined [Enterprise]",
legacyAlertingEnabled: "true",
unifiedAlertingEnabled: "",
isEnterprise: true,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, true, *cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when legacy alerting is enabled and unified is invalid [Enterprise]",
legacyAlertingEnabled: "true",
unifiedAlertingEnabled: "invalid",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false")
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when legacy alerting is disabled and unified is not defined [OSS]",
legacyAlertingEnabled: "false",
unifiedAlertingEnabled: "",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), false)
},
},
{
desc: "when legacy alerting is disabled and unified is invalid [OSS]",
legacyAlertingEnabled: "false",
unifiedAlertingEnabled: "invalid",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false")
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when legacy alerting is disabled and unified is not defined [Enterprise]",
legacyAlertingEnabled: "false",
unifiedAlertingEnabled: "",
isEnterprise: true,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, true)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), false)
},
},
{
desc: "when legacy alerting is disabled and unified is invalid [Enterprise]",
legacyAlertingEnabled: "false",
unifiedAlertingEnabled: "invalid",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false")
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when both are not defined [OSS]",
legacyAlertingEnabled: "",
unifiedAlertingEnabled: "",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.True(t, *cfg.UnifiedAlerting.Enabled)
assert.Nil(t, cfg.AlertingEnabled)
},
},
{
desc: "when both are not invalid [OSS]",
legacyAlertingEnabled: "invalid",
unifiedAlertingEnabled: "invalid",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false")
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when both are not defined [Enterprise]",
legacyAlertingEnabled: "",
unifiedAlertingEnabled: "",
isEnterprise: true,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.True(t, *cfg.UnifiedAlerting.Enabled)
assert.Nil(t, cfg.AlertingEnabled)
},
},
{
desc: "when both are not invalid [Enterprise]",
legacyAlertingEnabled: "invalid",
unifiedAlertingEnabled: "invalid",
isEnterprise: false,
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
assert.EqualError(t, err, "failed to read unified alerting enabled setting: invalid value invalid, should be either true or false")
assert.Nil(t, cfg.UnifiedAlerting.Enabled)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, false, *(cfg.AlertingEnabled))
},
},
{
desc: "when both are false",
legacyAlertingEnabled: "false",
unifiedAlertingEnabled: "false",
isEnterprise: anyBoolean(),
verifyCfg: func(t *testing.T, cfg Cfg, f *ini.File) {
err := cfg.readAlertingSettings(f)
require.NoError(t, err)
err = cfg.readFeatureToggles(f)
require.NoError(t, err)
err = cfg.ReadUnifiedAlertingSettings(f)
require.NoError(t, err)
assert.NotNil(t, cfg.UnifiedAlerting.Enabled)
assert.Equal(t, *cfg.UnifiedAlerting.Enabled, false)
assert.NotNil(t, cfg.AlertingEnabled)
assert.Equal(t, *(cfg.AlertingEnabled), false)
},
},
}
alertingSec, err := f.NewSection("alerting")
require.NoError(t, err)
_, err = alertingSec.NewKey("enabled", "true")
require.NoError(t, err)
var isEnterpriseOld = IsEnterprise
t.Cleanup(func() {
IsEnterprise = isEnterpriseOld
require.Error(t, cfg.readAlertingSettings(f))
})
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
IsEnterprise = tc.isEnterprise
t.Run("do nothing if it is disabled", func(t *testing.T) {
f := ini.Empty()
cfg := NewCfg()
f := ini.Empty()
cfg := NewCfg()
unifiedAlertingSec, err := f.NewSection("unified_alerting")
require.NoError(t, err)
_, err = unifiedAlertingSec.NewKey("enabled", tc.unifiedAlertingEnabled)
require.NoError(t, err)
alertingSec, err := f.NewSection("alerting")
require.NoError(t, err)
_, err = alertingSec.NewKey("enabled", "false")
require.NoError(t, err)
require.NoError(t, cfg.readAlertingSettings(f))
})
alertingSec, err := f.NewSection("alerting")
require.NoError(t, err)
_, err = alertingSec.NewKey("enabled", tc.legacyAlertingEnabled)
require.NoError(t, err)
t.Run("do nothing if it invalid", func(t *testing.T) {
f := ini.Empty()
cfg := NewCfg()
tc.verifyCfg(t, *cfg, f)
})
}
alertingSec, err := f.NewSection("alerting")
require.NoError(t, err)
_, err = alertingSec.NewKey("enabled", "test")
require.NoError(t, err)
require.NoError(t, cfg.readAlertingSettings(f))
})
}
func TestRedactedValue(t *testing.T) {

View File

@@ -1,7 +1,6 @@
package setting
import (
"errors"
"fmt"
"strconv"
"strings"
@@ -46,7 +45,7 @@ const (
`
evaluatorDefaultEvaluationTimeout = 30 * time.Second
schedulerDefaultAdminConfigPollInterval = time.Minute
schedulereDefaultExecuteAlerts = true
schedulerDefaultExecuteAlerts = true
schedulerDefaultMaxAttempts = 1
schedulerDefaultLegacyMinInterval = 1
screenshotsDefaultCapture = false
@@ -166,49 +165,13 @@ func (cfg *Cfg) readUnifiedAlertingEnabledSetting(section *ini.Section) (*bool,
// At present an invalid value is considered the same as no value. This means that a
// spelling mistake in the string "false" could enable unified alerting rather
// than disable it. This issue can be found here
hasEnabled := section.Key("enabled").Value() != ""
if !hasEnabled {
// TODO: Remove in Grafana v10
if cfg.IsFeatureToggleEnabled("ngalert") {
cfg.Logger.Warn("ngalert feature flag is deprecated: use unified alerting enabled setting instead")
// feature flag overrides the legacy alerting setting
legacyAlerting := false
cfg.AlertingEnabled = &legacyAlerting
unifiedAlerting := true
return &unifiedAlerting, nil
}
// if legacy alerting has not been configured then enable unified alerting
if cfg.AlertingEnabled == nil {
unifiedAlerting := true
return &unifiedAlerting, nil
}
// enable unified alerting and disable legacy alerting
legacyAlerting := false
cfg.AlertingEnabled = &legacyAlerting
unifiedAlerting := true
return &unifiedAlerting, nil
if section.Key("enabled").Value() == "" {
return util.Pointer(true), nil
}
unifiedAlerting, err := section.Key("enabled").Bool()
if err != nil {
// the value for unified alerting is invalid so disable all alerting
legacyAlerting := false
cfg.AlertingEnabled = &legacyAlerting
return nil, fmt.Errorf("invalid value %s, should be either true or false", section.Key("enabled"))
}
// If both legacy and unified alerting are enabled then return an error
if cfg.AlertingEnabled != nil && *(cfg.AlertingEnabled) && unifiedAlerting {
return nil, errors.New("legacy and unified alerting cannot both be enabled at the same time, please disable one of them and restart Grafana")
}
if cfg.AlertingEnabled == nil {
legacyAlerting := !unifiedAlerting
cfg.AlertingEnabled = &legacyAlerting
}
return &unifiedAlerting, nil
}
@@ -277,9 +240,9 @@ func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error {
alerting := iniFile.Section("alerting")
uaExecuteAlerts := ua.Key("execute_alerts").MustBool(schedulereDefaultExecuteAlerts)
uaExecuteAlerts := ua.Key("execute_alerts").MustBool(schedulerDefaultExecuteAlerts)
if uaExecuteAlerts { // unified option equals the default (true)
legacyExecuteAlerts := alerting.Key("execute_alerts").MustBool(schedulereDefaultExecuteAlerts)
legacyExecuteAlerts := alerting.Key("execute_alerts").MustBool(schedulerDefaultExecuteAlerts)
if !legacyExecuteAlerts {
cfg.Logger.Warn("falling back to legacy setting of 'execute_alerts'; please use the configuration option in the `unified_alerting` section if Grafana 8 alerts are enabled.")
}

View File

@@ -93,7 +93,7 @@ func TestUnifiedAlertingSettings(t *testing.T) {
alertingOptions: map[string]string{
"max_attempts": strconv.FormatInt(schedulerDefaultMaxAttempts, 10),
"min_interval_seconds": strconv.FormatInt(schedulerDefaultLegacyMinInterval, 10),
"execute_alerts": strconv.FormatBool(schedulereDefaultExecuteAlerts),
"execute_alerts": strconv.FormatBool(schedulerDefaultExecuteAlerts),
"evaluation_timeout_seconds": strconv.FormatInt(int64(evaluatorDefaultEvaluationTimeout.Seconds()), 10),
},
verifyCfg: func(t *testing.T, cfg Cfg) {
@@ -111,7 +111,7 @@ func TestUnifiedAlertingSettings(t *testing.T) {
unifiedAlertingOptions: map[string]string{
"admin_config_poll_interval": "120s",
"min_interval": SchedulerBaseInterval.String(),
"execute_alerts": strconv.FormatBool(schedulereDefaultExecuteAlerts),
"execute_alerts": strconv.FormatBool(schedulerDefaultExecuteAlerts),
"evaluation_timeout": evaluatorDefaultEvaluationTimeout.String(),
},
alertingOptions: map[string]string{
@@ -148,7 +148,7 @@ func TestUnifiedAlertingSettings(t *testing.T) {
require.Equal(t, alertmanagerDefaultConfigPollInterval, cfg.UnifiedAlerting.AdminConfigPollInterval)
require.Equal(t, int64(schedulerDefaultMaxAttempts), cfg.UnifiedAlerting.MaxAttempts)
require.Equal(t, SchedulerBaseInterval, cfg.UnifiedAlerting.MinInterval)
require.Equal(t, schedulereDefaultExecuteAlerts, cfg.UnifiedAlerting.ExecuteAlerts)
require.Equal(t, schedulerDefaultExecuteAlerts, cfg.UnifiedAlerting.ExecuteAlerts)
require.Equal(t, evaluatorDefaultEvaluationTimeout, cfg.UnifiedAlerting.EvaluationTimeout)
require.Equal(t, SchedulerBaseInterval, cfg.UnifiedAlerting.BaseInterval)
require.Equal(t, DefaultRuleEvaluationInterval, cfg.UnifiedAlerting.DefaultRuleEvaluationInterval)