mirror of
https://github.com/grafana/grafana.git
synced 2025-02-16 18:34:52 -06:00
* Remove `ngalert` feature toggle * Update frontend Remove all references of ngalert feature toggle * Update docs * Disable unified alerting for specific orgs * Add backend tests * Apply suggestions from code review Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Disabled unified alerting by default * Ensure backward compatibility with old ngalert feature toggle * Apply suggestions from code review Co-authored-by: gotjosh <josue@grafana.com>
290 lines
7.9 KiB
Go
290 lines
7.9 KiB
Go
package alerting
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAlertmanagerConfigurationIsTransactional(t *testing.T) {
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
|
DisableLegacyAlerting: true,
|
|
EnableUnifiedAlerting: true,
|
|
NGAlertAlertmanagerConfigPollInterval: 2 * time.Second,
|
|
DisableAnonymous: true,
|
|
})
|
|
|
|
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
|
|
|
// editor from main organisation requests configuration
|
|
alertConfigURL := fmt.Sprintf("http://editor:editor@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr)
|
|
|
|
// override bus to get the GetSignedInUserQuery handler
|
|
store.Bus = bus.GetBus()
|
|
|
|
// create user under main organisation
|
|
userID := createUser(t, store, models.CreateUserCommand{
|
|
DefaultOrgRole: string(models.ROLE_EDITOR),
|
|
Password: "editor",
|
|
Login: "editor",
|
|
})
|
|
|
|
// create another organisation
|
|
orgID := createOrg(t, store, "another org", userID)
|
|
|
|
// create user under different organisation
|
|
createUser(t, store, models.CreateUserCommand{
|
|
DefaultOrgRole: string(models.ROLE_EDITOR),
|
|
Password: "editor-42",
|
|
Login: "editor-42",
|
|
OrgId: orgID,
|
|
})
|
|
|
|
// On a blank start with no configuration, it saves and delivers the default configuration.
|
|
{
|
|
resp := getRequest(t, alertConfigURL, http.StatusOK) // nolint
|
|
require.JSONEq(t, defaultAlertmanagerConfigJSON, getBody(t, resp.Body))
|
|
}
|
|
|
|
// When creating new configuration, if it fails to apply - it does not save it.
|
|
{
|
|
payload := `
|
|
{
|
|
"template_files": {},
|
|
"alertmanager_config": {
|
|
"route": {
|
|
"receiver": "slack.receiver"
|
|
},
|
|
"templates": null,
|
|
"receivers": [{
|
|
"name": "slack.receiver",
|
|
"grafana_managed_receiver_configs": [{
|
|
"settings": {
|
|
"iconEmoji": "",
|
|
"iconUrl": "",
|
|
"mentionGroups": "",
|
|
"mentionUsers": "",
|
|
"recipient": "#unified-alerting-test",
|
|
"username": ""
|
|
},
|
|
"secureSettings": {},
|
|
"type": "slack",
|
|
"name": "slack.receiver",
|
|
"disableResolveMessage": false,
|
|
"uid": ""
|
|
}]
|
|
}]
|
|
}
|
|
}
|
|
`
|
|
resp := postRequest(t, alertConfigURL, payload, http.StatusBadRequest) // nolint
|
|
require.JSONEq(t, `{"message":"failed to save and apply Alertmanager configuration: failed to build integration map: the receiver is invalid: failed to validate receiver \"slack.receiver\" of type \"slack\": token must be specified when using the Slack chat API"}`, getBody(t, resp.Body))
|
|
|
|
resp = getRequest(t, alertConfigURL, http.StatusOK) // nolint
|
|
require.JSONEq(t, defaultAlertmanagerConfigJSON, getBody(t, resp.Body))
|
|
}
|
|
|
|
// editor42 from organisation 42 posts configuration
|
|
alertConfigURL = fmt.Sprintf("http://editor-42:editor-42@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr)
|
|
|
|
// Before we start operating, make sure we've synced this org.
|
|
require.Eventually(t, func() bool {
|
|
resp, err := http.Get(alertConfigURL) // nolint
|
|
require.NoError(t, err)
|
|
return resp.StatusCode == http.StatusOK
|
|
}, 10*time.Second, 2*time.Second)
|
|
|
|
// Post the alertmanager config.
|
|
{
|
|
mockChannel := newMockNotificationChannel(t, grafanaListedAddr)
|
|
amConfig := getAlertmanagerConfig(mockChannel.server.Addr)
|
|
postRequest(t, alertConfigURL, amConfig, http.StatusAccepted) // nolint
|
|
|
|
// Verifying that the new configuration is returned
|
|
resp := getRequest(t, alertConfigURL, http.StatusOK) // nolint
|
|
b := getBody(t, resp.Body)
|
|
re := regexp.MustCompile(`"uid":"([\w|-]*)"`)
|
|
e := getExpAlertmanagerConfigFromAPI(mockChannel.server.Addr)
|
|
require.JSONEq(t, e, string(re.ReplaceAll([]byte(b), []byte(`"uid":""`))))
|
|
}
|
|
|
|
// verify that main organisation still gets the default configuration
|
|
alertConfigURL = fmt.Sprintf("http://editor:editor@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr)
|
|
{
|
|
resp := getRequest(t, alertConfigURL, http.StatusOK) // nolint
|
|
require.JSONEq(t, defaultAlertmanagerConfigJSON, getBody(t, resp.Body))
|
|
}
|
|
}
|
|
|
|
func TestAlertmanagerConfigurationPersistSecrets(t *testing.T) {
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
|
DisableLegacyAlerting: true,
|
|
EnableUnifiedAlerting: true,
|
|
DisableAnonymous: true,
|
|
})
|
|
|
|
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
|
alertConfigURL := fmt.Sprintf("http://editor:editor@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr)
|
|
|
|
// override bus to get the GetSignedInUserQuery handler
|
|
store.Bus = bus.GetBus()
|
|
|
|
createUser(t, store, models.CreateUserCommand{
|
|
DefaultOrgRole: string(models.ROLE_EDITOR),
|
|
Password: "editor",
|
|
Login: "editor",
|
|
})
|
|
generatedUID := ""
|
|
|
|
// create a new configuration that has a secret
|
|
{
|
|
payload := `
|
|
{
|
|
"template_files": {},
|
|
"alertmanager_config": {
|
|
"route": {
|
|
"receiver": "slack.receiver"
|
|
},
|
|
"templates": null,
|
|
"receivers": [{
|
|
"name": "slack.receiver",
|
|
"grafana_managed_receiver_configs": [{
|
|
"settings": {
|
|
"recipient": "#unified-alerting-test"
|
|
},
|
|
"secureSettings": {
|
|
"url": "http://averysecureurl.com/webhook"
|
|
},
|
|
"type": "slack",
|
|
"name": "slack.receiver",
|
|
"disableResolveMessage": false
|
|
}]
|
|
}]
|
|
}
|
|
}
|
|
`
|
|
resp := postRequest(t, alertConfigURL, payload, http.StatusAccepted) // nolint
|
|
require.JSONEq(t, `{"message":"configuration created"}`, getBody(t, resp.Body))
|
|
}
|
|
|
|
// Try to update a receiver with unknown UID
|
|
{
|
|
// Then, update the recipient
|
|
payload := `
|
|
{
|
|
"template_files": {},
|
|
"alertmanager_config": {
|
|
"route": {
|
|
"receiver": "slack.receiver"
|
|
},
|
|
"templates": null,
|
|
"receivers": [{
|
|
"name": "slack.receiver",
|
|
"grafana_managed_receiver_configs": [{
|
|
"settings": {
|
|
"recipient": "#unified-alerting-test-but-updated"
|
|
},
|
|
"secureFields": {
|
|
"url": true
|
|
},
|
|
"type": "slack",
|
|
"name": "slack.receiver",
|
|
"disableResolveMessage": false,
|
|
"uid": "invalid"
|
|
}]
|
|
}]
|
|
}
|
|
}
|
|
`
|
|
|
|
resp := postRequest(t, alertConfigURL, payload, http.StatusBadRequest) // nolint
|
|
require.JSONEq(t, `{"message": "unknown receiver: invalid"}`, getBody(t, resp.Body))
|
|
}
|
|
|
|
// The secure settings must be present
|
|
{
|
|
resp := getRequest(t, alertConfigURL, http.StatusOK) // nolint
|
|
var c definitions.GettableUserConfig
|
|
bb := getBody(t, resp.Body)
|
|
err := json.Unmarshal([]byte(bb), &c)
|
|
require.NoError(t, err)
|
|
m := c.GetGrafanaReceiverMap()
|
|
assert.Len(t, m, 1)
|
|
for k := range m {
|
|
generatedUID = m[k].UID
|
|
}
|
|
|
|
// Then, update the recipient
|
|
payload := fmt.Sprintf(`
|
|
{
|
|
"template_files": {},
|
|
"alertmanager_config": {
|
|
"route": {
|
|
"receiver": "slack.receiver"
|
|
},
|
|
"templates": null,
|
|
"receivers": [{
|
|
"name": "slack.receiver",
|
|
"grafana_managed_receiver_configs": [{
|
|
"settings": {
|
|
"recipient": "#unified-alerting-test-but-updated"
|
|
},
|
|
"secureFields": {
|
|
"url": true
|
|
},
|
|
"type": "slack",
|
|
"name": "slack.receiver",
|
|
"disableResolveMessage": false,
|
|
"uid": %q
|
|
}]
|
|
}]
|
|
}
|
|
}
|
|
`, generatedUID)
|
|
|
|
resp = postRequest(t, alertConfigURL, payload, http.StatusAccepted) // nolint
|
|
require.JSONEq(t, `{"message": "configuration created"}`, getBody(t, resp.Body))
|
|
}
|
|
|
|
// The secure settings must be present
|
|
{
|
|
resp := getRequest(t, alertConfigURL, http.StatusOK) // nolint
|
|
require.JSONEq(t, fmt.Sprintf(`
|
|
{
|
|
"template_files": {},
|
|
"alertmanager_config": {
|
|
"route": {
|
|
"receiver": "slack.receiver"
|
|
},
|
|
"templates": null,
|
|
"receivers": [{
|
|
"name": "slack.receiver",
|
|
"grafana_managed_receiver_configs": [{
|
|
"uid": %q,
|
|
"name": "slack.receiver",
|
|
"type": "slack",
|
|
"disableResolveMessage": false,
|
|
"settings": {
|
|
"recipient": "#unified-alerting-test-but-updated"
|
|
},
|
|
"secureFields": {
|
|
"url": true
|
|
}
|
|
}]
|
|
}]
|
|
}
|
|
}
|
|
`, generatedUID), getBody(t, resp.Body))
|
|
}
|
|
}
|