mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 09:33:34 -06:00
157 lines
5.0 KiB
Go
157 lines
5.0 KiB
Go
|
package alerting
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||
|
"github.com/prometheus/common/model"
|
||
|
|
||
|
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
|
||
|
|
||
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||
|
|
||
|
"github.com/grafana/grafana/pkg/models"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/grafana/grafana/pkg/bus"
|
||
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||
|
)
|
||
|
|
||
|
func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) {
|
||
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||
|
EnableFeatureToggles: []string{"ngalert"},
|
||
|
DisableAnonymous: true,
|
||
|
NGAlertAdminConfigIntervalSeconds: 2,
|
||
|
})
|
||
|
|
||
|
s := testinfra.SetUpDatabase(t, dir)
|
||
|
// override bus to get the GetSignedInUserQuery handler
|
||
|
s.Bus = bus.GetBus()
|
||
|
grafanaListedAddr := testinfra.StartGrafana(t, dir, path, s)
|
||
|
|
||
|
// Create a user to make authenticated requests
|
||
|
createUser(t, s, models.CreateUserCommand{
|
||
|
DefaultOrgRole: string(models.ROLE_ADMIN),
|
||
|
Login: "grafana",
|
||
|
Password: "password",
|
||
|
})
|
||
|
|
||
|
// Create a couple of "fake" Alertmanagers
|
||
|
fakeAM1 := schedule.NewFakeExternalAlertmanager(t)
|
||
|
fakeAM2 := schedule.NewFakeExternalAlertmanager(t)
|
||
|
|
||
|
// Now, let's test the configuration API.
|
||
|
{
|
||
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
||
|
resp := getRequest(t, alertsURL, http.StatusNotFound) // nolint
|
||
|
b, err := ioutil.ReadAll(resp.Body)
|
||
|
require.NoError(t, err)
|
||
|
require.JSONEq(t, string(b), "{\"message\": \"no admin configuration available\"}")
|
||
|
}
|
||
|
|
||
|
// Now, lets re-set external Alertmanagers.
|
||
|
{
|
||
|
ac := apimodels.PostableNGalertConfig{
|
||
|
Alertmanagers: []string{fakeAM1.URL(), fakeAM2.URL()},
|
||
|
}
|
||
|
buf := bytes.Buffer{}
|
||
|
enc := json.NewEncoder(&buf)
|
||
|
err := enc.Encode(&ac)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
||
|
resp := postRequest(t, alertsURL, buf.String(), http.StatusCreated) // nolint
|
||
|
b, err := ioutil.ReadAll(resp.Body)
|
||
|
require.NoError(t, err)
|
||
|
require.JSONEq(t, string(b), "{\"message\": \"admin configuration updated\"}")
|
||
|
}
|
||
|
|
||
|
// If we get the configuration again, it shows us what we've set.
|
||
|
{
|
||
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
||
|
resp := getRequest(t, alertsURL, http.StatusOK) // nolint
|
||
|
b, err := ioutil.ReadAll(resp.Body)
|
||
|
require.NoError(t, err)
|
||
|
require.JSONEq(t, string(b), fmt.Sprintf("{\"alertmanagers\":[\"%s\",\"%s\"]}\n", fakeAM1.URL(), fakeAM2.URL()))
|
||
|
}
|
||
|
|
||
|
// With the configuration set, we should eventually discover those Alertmanagers set.
|
||
|
{
|
||
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/alertmanagers", grafanaListedAddr)
|
||
|
require.Eventually(t, func() bool {
|
||
|
resp := getRequest(t, alertsURL, http.StatusOK) // nolint
|
||
|
b, err := ioutil.ReadAll(resp.Body)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
var alertmanagers apimodels.GettableAlertmanagers
|
||
|
require.NoError(t, json.Unmarshal(b, &alertmanagers))
|
||
|
|
||
|
return len(alertmanagers.Data.Active) == 2
|
||
|
}, 80*time.Second, 4*time.Second)
|
||
|
}
|
||
|
|
||
|
// Now, let's set an alert that should fire as quickly as possible.
|
||
|
{
|
||
|
// create the namespace we'll save our alerts to
|
||
|
_, err := createFolder(t, s, 0, "default")
|
||
|
require.NoError(t, err)
|
||
|
interval, err := model.ParseDuration("10s")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
rules := apimodels.PostableRuleGroupConfig{
|
||
|
Name: "arulegroup",
|
||
|
Interval: interval,
|
||
|
Rules: []apimodels.PostableExtendedRuleNode{
|
||
|
{
|
||
|
ApiRuleNode: &apimodels.ApiRuleNode{
|
||
|
For: interval,
|
||
|
Labels: map[string]string{"label1": "val1"},
|
||
|
Annotations: map[string]string{"annotation1": "val1"},
|
||
|
},
|
||
|
// this rule does not explicitly set no data and error states
|
||
|
// therefore it should get the default values
|
||
|
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
|
||
|
Title: "AlwaysFiring",
|
||
|
Condition: "A",
|
||
|
Data: []ngmodels.AlertQuery{
|
||
|
{
|
||
|
RefID: "A",
|
||
|
RelativeTimeRange: ngmodels.RelativeTimeRange{
|
||
|
From: ngmodels.Duration(time.Duration(5) * time.Hour),
|
||
|
To: ngmodels.Duration(time.Duration(3) * time.Hour),
|
||
|
},
|
||
|
DatasourceUID: "-100",
|
||
|
Model: json.RawMessage(`{
|
||
|
"type": "math",
|
||
|
"expression": "2 + 3 > 1"
|
||
|
}`),
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
buf := bytes.Buffer{}
|
||
|
enc := json.NewEncoder(&buf)
|
||
|
err = enc.Encode(&rules)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
ruleURL := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
|
||
|
// nolint
|
||
|
_ = postRequest(t, ruleURL, buf.String(), http.StatusAccepted)
|
||
|
}
|
||
|
|
||
|
//Eventually, our Alertmanagers should receiver the alert.
|
||
|
{
|
||
|
require.Eventually(t, func() bool {
|
||
|
return fakeAM1.AlertsCount() == 1 && fakeAM2.AlertsCount() == 1
|
||
|
}, 60*time.Second, 5*time.Second)
|
||
|
}
|
||
|
}
|