2021-03-24 09:20:44 -05:00
|
|
|
package notifier
|
|
|
|
|
|
|
|
import (
|
2021-04-23 09:19:03 -05:00
|
|
|
"context"
|
2021-04-22 10:12:18 -05:00
|
|
|
"errors"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2021-04-27 06:33:22 -05:00
|
|
|
"sort"
|
2021-03-24 09:20:44 -05:00
|
|
|
"testing"
|
2021-04-22 10:12:18 -05:00
|
|
|
"time"
|
2021-03-24 09:20:44 -05:00
|
|
|
|
2021-04-23 09:19:03 -05:00
|
|
|
gokit_log "github.com/go-kit/kit/log"
|
2021-04-22 10:12:18 -05:00
|
|
|
"github.com/go-openapi/strfmt"
|
|
|
|
"github.com/prometheus/alertmanager/api/v2/models"
|
2021-04-23 09:19:03 -05:00
|
|
|
"github.com/prometheus/alertmanager/provider/mem"
|
2021-04-22 10:12:18 -05:00
|
|
|
"github.com/prometheus/alertmanager/types"
|
2021-04-23 09:19:03 -05:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2021-04-22 10:12:18 -05:00
|
|
|
"github.com/prometheus/common/model"
|
2021-03-24 09:20:44 -05:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-04-13 07:02:44 -05:00
|
|
|
|
2021-04-22 10:12:18 -05:00
|
|
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
2021-04-13 07:02:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
2021-03-24 09:20:44 -05:00
|
|
|
)
|
|
|
|
|
2021-04-13 07:02:44 -05:00
|
|
|
func TestAlertmanager_ShouldUseDefaultConfigurationWhenNoConfiguration(t *testing.T) {
|
2021-04-23 09:19:03 -05:00
|
|
|
am := &Alertmanager{}
|
|
|
|
am.Settings = &setting.Cfg{}
|
|
|
|
am.SQLStore = sqlstore.InitTestDB(t)
|
2021-03-24 09:20:44 -05:00
|
|
|
require.NoError(t, am.Init())
|
2021-04-13 07:02:44 -05:00
|
|
|
require.NoError(t, am.SyncAndApplyConfigFromDatabase())
|
|
|
|
require.NotNil(t, am.config)
|
2021-03-24 09:20:44 -05:00
|
|
|
}
|
2021-04-22 10:12:18 -05:00
|
|
|
|
|
|
|
func TestPutAlert(t *testing.T) {
|
2021-04-23 09:19:03 -05:00
|
|
|
am := &Alertmanager{}
|
2021-04-22 10:12:18 -05:00
|
|
|
dir, err := ioutil.TempDir("", "")
|
|
|
|
require.NoError(t, err)
|
|
|
|
t.Cleanup(func() {
|
|
|
|
require.NoError(t, os.RemoveAll(dir))
|
|
|
|
})
|
|
|
|
|
2021-04-23 09:19:03 -05:00
|
|
|
am.Settings = &setting.Cfg{
|
|
|
|
DataPath: dir,
|
2021-04-22 10:12:18 -05:00
|
|
|
}
|
2021-04-23 09:19:03 -05:00
|
|
|
|
2021-04-22 10:12:18 -05:00
|
|
|
require.NoError(t, am.Init())
|
|
|
|
|
|
|
|
startTime := time.Now()
|
|
|
|
endTime := startTime.Add(2 * time.Hour)
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
title string
|
|
|
|
postableAlerts apimodels.PostableAlerts
|
|
|
|
expAlerts func(now time.Time) []*types.Alert
|
|
|
|
expError *AlertValidationError
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
title: "Valid alerts with different start/end set",
|
|
|
|
postableAlerts: apimodels.PostableAlerts{
|
|
|
|
PostableAlerts: []models.PostableAlert{
|
|
|
|
{ // Start and end set.
|
|
|
|
Annotations: models.LabelSet{"msg": "Alert1 annotation"},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert1"},
|
|
|
|
GeneratorURL: "http://localhost/url1",
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime(startTime),
|
|
|
|
EndsAt: strfmt.DateTime(endTime),
|
|
|
|
}, { // Only end is set.
|
|
|
|
Annotations: models.LabelSet{"msg": "Alert2 annotation"},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert2"},
|
|
|
|
GeneratorURL: "http://localhost/url2",
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime{},
|
|
|
|
EndsAt: strfmt.DateTime(endTime),
|
|
|
|
}, { // Only start is set.
|
|
|
|
Annotations: models.LabelSet{"msg": "Alert3 annotation"},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert3"},
|
|
|
|
GeneratorURL: "http://localhost/url3",
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime(startTime),
|
|
|
|
EndsAt: strfmt.DateTime{},
|
|
|
|
}, { // Both start and end are not set.
|
|
|
|
Annotations: models.LabelSet{"msg": "Alert4 annotation"},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert4"},
|
|
|
|
GeneratorURL: "http://localhost/url4",
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime{},
|
|
|
|
EndsAt: strfmt.DateTime{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expAlerts: func(now time.Time) []*types.Alert {
|
|
|
|
return []*types.Alert{
|
|
|
|
{
|
|
|
|
Alert: model.Alert{
|
|
|
|
Annotations: model.LabelSet{"msg": "Alert1 annotation"},
|
|
|
|
Labels: model.LabelSet{"alertname": "Alert1"},
|
|
|
|
StartsAt: startTime,
|
|
|
|
EndsAt: endTime,
|
|
|
|
GeneratorURL: "http://localhost/url1",
|
|
|
|
},
|
|
|
|
UpdatedAt: now,
|
|
|
|
}, {
|
|
|
|
Alert: model.Alert{
|
|
|
|
Annotations: model.LabelSet{"msg": "Alert2 annotation"},
|
|
|
|
Labels: model.LabelSet{"alertname": "Alert2"},
|
|
|
|
StartsAt: endTime,
|
|
|
|
EndsAt: endTime,
|
|
|
|
GeneratorURL: "http://localhost/url2",
|
|
|
|
},
|
|
|
|
UpdatedAt: now,
|
|
|
|
}, {
|
|
|
|
Alert: model.Alert{
|
|
|
|
Annotations: model.LabelSet{"msg": "Alert3 annotation"},
|
|
|
|
Labels: model.LabelSet{"alertname": "Alert3"},
|
|
|
|
StartsAt: startTime,
|
|
|
|
EndsAt: now.Add(defaultResolveTimeout),
|
|
|
|
GeneratorURL: "http://localhost/url3",
|
|
|
|
},
|
|
|
|
UpdatedAt: now,
|
|
|
|
Timeout: true,
|
|
|
|
}, {
|
|
|
|
Alert: model.Alert{
|
|
|
|
Annotations: model.LabelSet{"msg": "Alert4 annotation"},
|
|
|
|
Labels: model.LabelSet{"alertname": "Alert4"},
|
|
|
|
StartsAt: now,
|
|
|
|
EndsAt: now.Add(defaultResolveTimeout),
|
|
|
|
GeneratorURL: "http://localhost/url4",
|
|
|
|
},
|
|
|
|
UpdatedAt: now,
|
|
|
|
Timeout: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
title: "Removing empty labels and annotations",
|
|
|
|
postableAlerts: apimodels.PostableAlerts{
|
|
|
|
PostableAlerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Annotations: models.LabelSet{"msg": "Alert4 annotation", "empty": ""},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert4", "emptylabel": ""},
|
|
|
|
GeneratorURL: "http://localhost/url1",
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime{},
|
|
|
|
EndsAt: strfmt.DateTime{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expAlerts: func(now time.Time) []*types.Alert {
|
|
|
|
return []*types.Alert{
|
|
|
|
{
|
|
|
|
Alert: model.Alert{
|
|
|
|
Annotations: model.LabelSet{"msg": "Alert4 annotation"},
|
|
|
|
Labels: model.LabelSet{"alertname": "Alert4"},
|
|
|
|
StartsAt: now,
|
|
|
|
EndsAt: now.Add(defaultResolveTimeout),
|
|
|
|
GeneratorURL: "http://localhost/url1",
|
|
|
|
},
|
|
|
|
UpdatedAt: now,
|
|
|
|
Timeout: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
title: "Invalid labels",
|
|
|
|
postableAlerts: apimodels.PostableAlerts{
|
|
|
|
PostableAlerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname$": "Alert1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expError: &AlertValidationError{
|
|
|
|
Alerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname$": "Alert1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Errors: []error{errors.New("invalid label set: invalid name \"alertname$\"")},
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
title: "Invalid annotation",
|
|
|
|
postableAlerts: apimodels.PostableAlerts{
|
|
|
|
PostableAlerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Annotations: models.LabelSet{"msg$": "Alert4 annotation"},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expError: &AlertValidationError{
|
|
|
|
Alerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Annotations: models.LabelSet{"msg$": "Alert4 annotation"},
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": "Alert1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Errors: []error{errors.New("invalid annotations: invalid name \"msg$\"")},
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
title: "No labels after removing empty",
|
|
|
|
postableAlerts: apimodels.PostableAlerts{
|
|
|
|
PostableAlerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": ""},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expError: &AlertValidationError{
|
|
|
|
Alerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": ""},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Errors: []error{errors.New("at least one label pair required")},
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
title: "Start should be before end",
|
|
|
|
postableAlerts: apimodels.PostableAlerts{
|
|
|
|
PostableAlerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": ""},
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime(endTime),
|
|
|
|
EndsAt: strfmt.DateTime(startTime),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expError: &AlertValidationError{
|
|
|
|
Alerts: []models.PostableAlert{
|
|
|
|
{
|
|
|
|
Alert: models.Alert{
|
|
|
|
Labels: models.LabelSet{"alertname": ""},
|
|
|
|
},
|
|
|
|
StartsAt: strfmt.DateTime(endTime),
|
|
|
|
EndsAt: strfmt.DateTime(startTime),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Errors: []error{errors.New("start time must be before end time")},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
t.Run(c.title, func(t *testing.T) {
|
2021-04-23 09:19:03 -05:00
|
|
|
r := prometheus.NewRegistry()
|
|
|
|
am.marker = types.NewMarker(r)
|
|
|
|
am.alerts, err = mem.NewAlerts(context.Background(), am.marker, 15*time.Minute, gokit_log.NewNopLogger())
|
|
|
|
require.NoError(t, err)
|
2021-04-22 10:12:18 -05:00
|
|
|
|
2021-04-23 09:19:03 -05:00
|
|
|
alerts := []*types.Alert{}
|
2021-04-22 10:12:18 -05:00
|
|
|
err := am.PutAlerts(c.postableAlerts)
|
|
|
|
if c.expError != nil {
|
|
|
|
require.Error(t, err)
|
|
|
|
require.Equal(t, c.expError, err)
|
2021-04-23 09:19:03 -05:00
|
|
|
require.Equal(t, 0, len(alerts))
|
2021-04-22 10:12:18 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-04-23 09:19:03 -05:00
|
|
|
iter := am.alerts.GetPending()
|
|
|
|
defer iter.Close()
|
|
|
|
for a := range iter.Next() {
|
|
|
|
alerts = append(alerts, a)
|
|
|
|
}
|
|
|
|
|
2021-04-22 10:12:18 -05:00
|
|
|
// We take the "now" time from one of the UpdatedAt.
|
2021-04-23 09:19:03 -05:00
|
|
|
now := alerts[0].UpdatedAt
|
2021-04-27 06:33:22 -05:00
|
|
|
expAlerts := c.expAlerts(now)
|
|
|
|
|
|
|
|
sort.Sort(types.AlertSlice(expAlerts))
|
|
|
|
sort.Sort(types.AlertSlice(alerts))
|
|
|
|
|
|
|
|
require.Equal(t, expAlerts, alerts)
|
2021-04-22 10:12:18 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|