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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 50 additions and 555 deletions

View File

@ -1200,17 +1200,17 @@ ha_gossip_interval = 200ms
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_push_pull_interval = 60s
# Enable or disable alerting rule execution. The alerting UI remains visible. This option has a legacy version in the `[alerting]` section that takes precedence.
# Enable or disable alerting rule execution. The alerting UI remains visible.
execute_alerts = true
# Alert evaluation timeout when fetching data from the datasource. This option has a legacy version in the `[alerting]` section that takes precedence.
# Alert evaluation timeout when fetching data from the datasource.
# The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
evaluation_timeout = 30s
# Number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. The default value is 1.
max_attempts = 1
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has a legacy version in the `[alerting]` section that takes precedence.
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
min_interval = 10s
@ -1347,45 +1347,6 @@ password =
sync_interval = 5m
#################################### Alerting ############################
[alerting]
# Enable the legacy alerting sub-system and interface. If Unified Alerting is already enabled and you try to go back to legacy alerting, all data that is part of Unified Alerting will be deleted. When this configuration section and flag are not defined, the state is defined at runtime. See the documentation for more details.
enabled =
# Makes it possible to turn off alert execution but alerting UI is visible
execute_alerts = true
# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
error_or_timeout = alerting
# Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok)
nodata_or_nullvalues = no_data
# Alert notifications can include images, but rendering many images at the same time can overload the server
# This limit will protect the server from render overloading and make sure notifications are sent out quickly
concurrent_render_limit = 5
# Default setting for alert calculation timeout. Default value is 30
evaluation_timeout_seconds = 30
# Default setting for alert notification timeout. Default value is 30
notification_timeout_seconds = 30
# Default setting for max attempts to sending alert notifications. Default value is 3
max_attempts = 3
# Makes it possible to enforce a minimal interval between evaluations, to reduce load on the backend
min_interval_seconds = 1
# Configures for how long alert annotations are stored. Default is 0, which keeps them forever.
# This setting should be expressed as an duration. Ex 6h (hours), 10d (days), 2w (weeks), 1M (month).
# Deprecated, use [annotations.alerting].max_age instead
max_annotation_age =
# Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
# Deprecated, use [annotations.alerting].max_annotations_to_keep instead
max_annotations_to_keep =
#################################### Annotations #########################
[annotations]
# Configures the batch size for the annotation clean-up job. This setting is used for dashboard, API, and alert annotations.

View File

@ -1116,17 +1116,17 @@
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_push_pull_interval = "60s"
# Enable or disable alerting rule execution. The alerting UI remains visible. This option has a legacy version in the `[alerting]` section that takes precedence.
# Enable or disable alerting rule execution. The alerting UI remains visible.
;execute_alerts = true
# Alert evaluation timeout when fetching data from the datasource. This option has a legacy version in the `[alerting]` section that takes precedence.
# Alert evaluation timeout when fetching data from the datasource.
# The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;evaluation_timeout = 30s
# Number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. The default value is 1.
;max_attempts = 1
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has a legacy version in the `[alerting]` section that takes precedence.
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;min_interval = 10s
@ -1216,45 +1216,6 @@ max_annotations_to_keep =
# Unified Alerting. Should be kept false when not needed as it may cause unintended data-loss if left enabled.
;clean_upgrade = false
#################################### Alerting ############################
[alerting]
# Disable legacy alerting engine & UI features
;enabled = false
# Makes it possible to turn off alert execution but alerting UI is visible
;execute_alerts = true
# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
;error_or_timeout = alerting
# Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok)
;nodata_or_nullvalues = no_data
# Alert notifications can include images, but rendering many images at the same time can overload the server
# This limit will protect the server from render overloading and make sure notifications are sent out quickly
;concurrent_render_limit = 5
# Default setting for alert calculation timeout. Default value is 30
;evaluation_timeout_seconds = 30
# Default setting for alert notification timeout. Default value is 30
;notification_timeout_seconds = 30
# Default setting for max attempts to sending alert notifications. Default value is 3
;max_attempts = 3
# Makes it possible to enforce a minimal interval between evaluations, to reduce load on the backend
;min_interval_seconds = 1
# Configures for how long alert annotations are stored. Default is 0, which keeps them forever.
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
# Deprecated, use [annotations.alerting].max_age instead
;max_annotation_age =
# Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
# Deprecated, use [annotations.alerting].max_annotations_to_keep instead
;max_annotations_to_keep =
#################################### Annotations #########################
[annotations]
# Configures the batch size for the annotation clean-up job. This setting is used for dashboard, API, and alert annotations.

View File

@ -1608,11 +1608,11 @@ The interval string is a possibly signed sequence of decimal numbers, followed b
### execute_alerts
Enable or disable alerting rule execution. The default value is `true`. The alerting UI remains visible. This option has a [legacy version in the alerting section]({{< relref "#execute_alerts-1" >}}) that takes precedence.
Enable or disable alerting rule execution. The default value is `true`. The alerting UI remains visible.
### evaluation_timeout
Sets the alert evaluation timeout when fetching data from the data source. The default value is `30s`. This option has a [legacy version in the alerting section]({{< relref "#evaluation_timeout_seconds" >}}) that takes precedence.
Sets the alert evaluation timeout when fetching data from the data source. The default value is `30s`.
The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
@ -1622,7 +1622,7 @@ Sets a maximum number of times we'll attempt to evaluate an alert rule before gi
### min_interval
Sets the minimum interval to enforce between rule evaluations. The default value is `10s` which equals the scheduler interval. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has [a legacy version in the alerting section]({{< relref "#min_interval_seconds" >}}) that takes precedence.
Sets the minimum interval to enforce between rule evaluations. The default value is `10s` which equals the scheduler interval. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
@ -1690,68 +1690,6 @@ It should be kept false when not needed, as it may cause unintended data loss if
<hr>
## [alerting]
For more information about the legacy dashboard alerting feature in Grafana, refer to [the legacy Grafana alerts](/docs/grafana/v8.5/alerting/old-alerting/).
### enabled
Set to `true` to [enable legacy dashboard alerting]({{< relref "#unified_alerting" >}}). The default value is `false`.
### execute_alerts
Turns off alert rule execution, but alerting is still visible in the Grafana UI.
### error_or_timeout
Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
### nodata_or_nullvalues
Defines how Grafana handles nodata or null values in alerting. Options are `alerting`, `no_data`, `keep_state`, and `ok`. Default is `no_data`.
### concurrent_render_limit
Alert notifications can include images, but rendering many images at the same time can overload the server.
This limit protects the server from render overloading and ensures notifications are sent out quickly. Default value is `5`.
### evaluation_timeout_seconds
Sets the alert calculation timeout. Default value is `30`.
### notification_timeout_seconds
Sets the alert notification timeout. Default value is `30`.
### max_attempts
Sets a maximum limit on attempts to sending alert notifications. Default value is `3`.
### min_interval_seconds
Sets the minimum interval between rule evaluations. Default value is `1`.
> **Note.** This setting has precedence over each individual rule frequency. If a rule frequency is lower than this value, then this value is enforced.
### max_annotation_age
{{% admonition type="note" %}}
This option is deprecated - See `max_age` option in [unified_alerting.state_history.annotations]({{< relref "#unified_alertingstate_historyannotations" >}}) instead.
{{% /admonition %}}
Configures for how long alert annotations are stored. Default is 0, which keeps them forever.
This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
### max_annotations_to_keep
{{% admonition type="note" %}}
This option is deprecated - See `max_annotations_to_keep` option in [unified_alerting.state_history.annotations]({{< relref "#unified_alertingstate_historyannotations" >}}) instead.
{{% /admonition %}}
Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
<hr>
## [annotations]
### cleanupjob_batchsize

View File

@ -30,7 +30,7 @@ You can also render a PNG by hovering over the panel to display the actions menu
## Alerting and render limits
Alert notifications can include images, but rendering many images at the same time can overload the server where the renderer is running. For instructions of how to configure this, see [concurrent_render_limit]({{< relref "../configure-grafana#concurrent_render_limit" >}}).
Alert notifications can include images, but rendering many images at the same time can overload the server where the renderer is running. For instructions of how to configure this, see [max_concurrent_screenshots]({{< relref "../configure-grafana#max_concurrent_screenshots" >}}).
## Install Grafana Image Renderer plugin

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)