[v9.4.x] Alerting: Allow alert rule pausing from API (#62675)
Alerting: Allow alert rule pausing from API (#62326)
* Add is_paused attr to the POST alert rule group endpoint
* Add is_paused to alerting API POST alert rule group
* Fixed tests
* Add is_paused to alerting gettable endpoints
* Fix integration tests
* Alerting: allow to pause existing rules (#62401)
* Display Pause Rule switch in Editing Rule form
* add isPaused property to form interface and dto
* map isPaused prop with is_paused value from DTO
Also update test snapshots
* Append '(Paused)' text on alert list state column when appropriate
* Change Switch styles according to discussion with UX
Also adding a tooltip with info what this means
* Adjust styles
* Fix alignment and isPaused type definition
Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
* Fix test
* Fix test
* Fix RuleList test
---------
Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
* wip
* Fix tests and add comments to clarify AlertRuleWithOptionals
* Fix one more test
* Fix tests
* Fix typo in comment
* Fix alert rule(s) cannot be paused via API
* Add integration tests for alerting api pausing flow
* Remove duplicated integration test
---------
Co-authored-by: Virginia Cepeda <virginia.cepeda@grafana.com>
Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
Co-authored-by: George Robinson <george.robinson@grafana.com>
(cherry picked from commit 53945afedf)
Co-authored-by: Alex Moreno <alexander.moreno@grafana.com>
This commit is contained in:
co-authored by
Alex Moreno
parent
68fb4da24a
commit
40354c6b40
@@ -764,6 +764,7 @@ func TestIntegrationDeleteFolderWithRules(t *testing.T) {
|
||||
],
|
||||
"updated": "2021-05-19T19:47:55Z",
|
||||
"intervalSeconds": 60,
|
||||
"is_paused": false,
|
||||
"version": 1,
|
||||
"uid": "",
|
||||
"namespace_uid": %q,
|
||||
@@ -1220,6 +1221,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused": false,
|
||||
"version":1,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -1256,6 +1258,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused": false,
|
||||
"version":1,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -1563,6 +1566,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused": false,
|
||||
"version":2,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -1672,6 +1676,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused":false,
|
||||
"version":3,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -1757,6 +1762,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused":false,
|
||||
"version":3,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -2063,6 +2069,7 @@ func TestIntegrationQuota(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused": false,
|
||||
"version":2,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
|
||||
@@ -113,6 +113,7 @@ func TestIntegrationAlertRulePermissions(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused":false,
|
||||
"version":1,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -163,6 +164,7 @@ func TestIntegrationAlertRulePermissions(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused":false,
|
||||
"version":1,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -236,6 +238,7 @@ func TestIntegrationAlertRulePermissions(t *testing.T) {
|
||||
],
|
||||
"updated":"2021-02-21T01:10:30Z",
|
||||
"intervalSeconds":60,
|
||||
"is_paused":false,
|
||||
"version":1,
|
||||
"uid":"uid",
|
||||
"namespace_uid":"nsuid",
|
||||
@@ -510,6 +513,7 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
|
||||
}],
|
||||
"updated": "2021-02-21T01:10:30Z",
|
||||
"intervalSeconds": 60,
|
||||
"is_paused": false,
|
||||
"version": 1,
|
||||
"uid": "uid",
|
||||
"namespace_uid": "nsuid",
|
||||
@@ -543,6 +547,7 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
|
||||
}],
|
||||
"updated": "2021-02-21T01:10:30Z",
|
||||
"intervalSeconds": 60,
|
||||
"is_paused": false,
|
||||
"version": 1,
|
||||
"uid": "uid",
|
||||
"namespace_uid": "nsuid",
|
||||
@@ -588,6 +593,7 @@ func TestIntegrationRulerRulesFilterByDashboard(t *testing.T) {
|
||||
}],
|
||||
"updated": "2021-02-21T01:10:30Z",
|
||||
"intervalSeconds": 60,
|
||||
"is_paused": false,
|
||||
"version": 1,
|
||||
"uid": "uid",
|
||||
"namespace_uid": "nsuid",
|
||||
@@ -935,3 +941,127 @@ func newTestingRuleConfig(t *testing.T) apimodels.PostableRuleGroupConfig {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationRulePause(t *testing.T) {
|
||||
testinfra.SQLiteIntegrationTest(t)
|
||||
|
||||
// Setup Grafana and its Database
|
||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||
DisableLegacyAlerting: true,
|
||||
EnableUnifiedAlerting: true,
|
||||
DisableAnonymous: true,
|
||||
AppModeProduction: true,
|
||||
})
|
||||
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
||||
|
||||
// Create a user to make authenticated requests
|
||||
createUser(t, store, user.CreateUserCommand{
|
||||
DefaultOrgRole: string(org.RoleEditor),
|
||||
Password: "password",
|
||||
Login: "grafana",
|
||||
})
|
||||
|
||||
client := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
|
||||
folder1Title := "folder1"
|
||||
client.CreateFolder(t, util.GenerateShortUID(), folder1Title)
|
||||
|
||||
t.Run("should create a paused rule if isPaused is true", func(t *testing.T) {
|
||||
group := generateAlertRuleGroup(1, alertRuleGen())
|
||||
expectedIsPaused := true
|
||||
group.Rules[0].GrafanaManagedAlert.IsPaused = &expectedIsPaused
|
||||
|
||||
status, body := client.PostRulesGroup(t, folder1Title, &group)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to post rule group. Response: %s", body)
|
||||
getGroup := client.GetRulesGroup(t, folder1Title, group.Name)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to get rule group. Response: %s", body)
|
||||
require.Equal(t, expectedIsPaused, getGroup.Rules[0].GrafanaManagedAlert.IsPaused)
|
||||
})
|
||||
|
||||
t.Run("should create a unpaused rule if isPaused is false", func(t *testing.T) {
|
||||
group := generateAlertRuleGroup(1, alertRuleGen())
|
||||
expectedIsPaused := false
|
||||
group.Rules[0].GrafanaManagedAlert.IsPaused = &expectedIsPaused
|
||||
|
||||
status, body := client.PostRulesGroup(t, folder1Title, &group)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to post rule group. Response: %s", body)
|
||||
getGroup := client.GetRulesGroup(t, folder1Title, group.Name)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to get rule group. Response: %s", body)
|
||||
require.Equal(t, expectedIsPaused, getGroup.Rules[0].GrafanaManagedAlert.IsPaused)
|
||||
})
|
||||
|
||||
t.Run("should create a unpaused rule if isPaused is not present", func(t *testing.T) {
|
||||
group := generateAlertRuleGroup(1, alertRuleGen())
|
||||
group.Rules[0].GrafanaManagedAlert.IsPaused = nil
|
||||
|
||||
status, body := client.PostRulesGroup(t, folder1Title, &group)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to post rule group. Response: %s", body)
|
||||
getGroup := client.GetRulesGroup(t, folder1Title, group.Name)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to get rule group. Response: %s", body)
|
||||
require.False(t, getGroup.Rules[0].GrafanaManagedAlert.IsPaused)
|
||||
})
|
||||
|
||||
getBooleanPointer := func(b bool) *bool { return &b }
|
||||
testCases := []struct {
|
||||
description string
|
||||
isPausedInDb bool
|
||||
isPausedInBody *bool
|
||||
expectedIsPausedInDb bool
|
||||
}{
|
||||
{
|
||||
description: "should pause rule if there is a paused rule in DB and isPaused is true",
|
||||
isPausedInDb: true,
|
||||
isPausedInBody: getBooleanPointer(true),
|
||||
expectedIsPausedInDb: true,
|
||||
},
|
||||
{
|
||||
description: "should unpause rule if there is a paused rule in DB and isPaused is false",
|
||||
isPausedInDb: true,
|
||||
isPausedInBody: getBooleanPointer(false),
|
||||
expectedIsPausedInDb: false,
|
||||
},
|
||||
{
|
||||
description: "should keep rule paused if there is a paused rule in DB and isPaused is not present",
|
||||
isPausedInDb: true,
|
||||
isPausedInBody: nil,
|
||||
expectedIsPausedInDb: true,
|
||||
},
|
||||
{
|
||||
description: "should pause rule if there is an unpaused rule in DB and isPaused is true",
|
||||
isPausedInDb: false,
|
||||
isPausedInBody: getBooleanPointer(true),
|
||||
expectedIsPausedInDb: true,
|
||||
},
|
||||
{
|
||||
description: "should unpause rule if there is an unpaused rule in DB and isPaused is false",
|
||||
isPausedInDb: false,
|
||||
isPausedInBody: getBooleanPointer(false),
|
||||
expectedIsPausedInDb: false,
|
||||
},
|
||||
{
|
||||
description: "should keep rule unpaused if there is an unpaused rule in DB and isPaused is not present",
|
||||
isPausedInDb: false,
|
||||
isPausedInBody: nil,
|
||||
expectedIsPausedInDb: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
group := generateAlertRuleGroup(1, alertRuleGen())
|
||||
group.Rules[0].GrafanaManagedAlert.IsPaused = &tc.isPausedInDb
|
||||
|
||||
status, body := client.PostRulesGroup(t, folder1Title, &group)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to post rule group. Response: %s", body)
|
||||
getGroup := client.GetRulesGroup(t, folder1Title, group.Name)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to get rule group. Response: %s", body)
|
||||
|
||||
group = convertGettableRuleGroupToPostable(getGroup.GettableRuleGroupConfig)
|
||||
group.Rules[0].GrafanaManagedAlert.IsPaused = tc.isPausedInBody
|
||||
status, body = client.PostRulesGroup(t, folder1Title, &group)
|
||||
require.Equalf(t, http.StatusAccepted, status, "failed to post rule group. Response: %s", body)
|
||||
|
||||
getGroup = client.GetRulesGroup(t, folder1Title, group.Name)
|
||||
require.Equal(t, tc.expectedIsPausedInDb, getGroup.Rules[0].GrafanaManagedAlert.IsPaused)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ func convertGettableGrafanaRuleToPostable(gettable *apimodels.GettableGrafanaRul
|
||||
UID: gettable.UID,
|
||||
NoDataState: gettable.NoDataState,
|
||||
ExecErrState: gettable.ExecErrState,
|
||||
IsPaused: &gettable.IsPaused,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user