mirror of
https://github.com/prometheus/alertmanager
synced 2025-03-31 15:48:47 +00:00
api: support zero StartsAt for alerts (#1238)
When the API receives alerts where StartsAt is zero, it updates the value to EndsAt (if not zero itself) or "now". This ensures that the alert validation will not fail since StartsAt has to be less than or equal to EndsAt.
This commit is contained in:
parent
32f90a02ca
commit
382a0d8089
10
api/api.go
10
api/api.go
@ -103,6 +103,10 @@ func New(
|
||||
peer *cluster.Peer,
|
||||
l log.Logger,
|
||||
) *API {
|
||||
if l == nil {
|
||||
l = log.NewNopLogger()
|
||||
}
|
||||
|
||||
return &API{
|
||||
alerts: alerts,
|
||||
silences: silences,
|
||||
@ -466,7 +470,11 @@ func (api *API) insertAlerts(w http.ResponseWriter, r *http.Request, alerts ...*
|
||||
|
||||
// Ensure StartsAt is set.
|
||||
if alert.StartsAt.IsZero() {
|
||||
alert.StartsAt = now
|
||||
if alert.EndsAt.IsZero() {
|
||||
alert.StartsAt = now
|
||||
} else {
|
||||
alert.StartsAt = alert.EndsAt
|
||||
}
|
||||
}
|
||||
// If no end time is defined, set a timeout after which an alert
|
||||
// is marked resolved if it is not updated.
|
||||
|
@ -1,16 +1,93 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/alertmanager/dispatch"
|
||||
"github.com/prometheus/alertmanager/provider"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type fakeAlerts struct {
|
||||
putWithErr bool
|
||||
}
|
||||
|
||||
func newEmptyIterator() provider.AlertIterator {
|
||||
return provider.NewAlertIterator(make(chan *types.Alert), make(chan struct{}), nil)
|
||||
}
|
||||
|
||||
func (f *fakeAlerts) Subscribe() provider.AlertIterator { return newEmptyIterator() }
|
||||
func (f *fakeAlerts) GetPending() provider.AlertIterator { return newEmptyIterator() }
|
||||
func (f *fakeAlerts) Get(model.Fingerprint) (*types.Alert, error) { return nil, nil }
|
||||
func (f *fakeAlerts) Put(alerts ...*types.Alert) error {
|
||||
if f.putWithErr {
|
||||
return errors.New("Error occured")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func groupAlerts([]*labels.Matcher) dispatch.AlertOverview { return dispatch.AlertOverview{} }
|
||||
func getAlertStatus(model.Fingerprint) types.AlertStatus { return types.AlertStatus{} }
|
||||
|
||||
func TestAddAlerts(t *testing.T) {
|
||||
now := func(offset int) time.Time {
|
||||
return time.Now().Add(time.Duration(offset) * time.Second)
|
||||
}
|
||||
|
||||
for i, tc := range []struct {
|
||||
start, end time.Time
|
||||
err bool
|
||||
code int
|
||||
}{
|
||||
{time.Time{}, time.Time{}, false, 200},
|
||||
{now(0), time.Time{}, false, 200},
|
||||
{time.Time{}, now(-1), false, 200},
|
||||
{time.Time{}, now(0), false, 200},
|
||||
{time.Time{}, now(1), false, 200},
|
||||
{now(-2), now(-1), false, 200},
|
||||
{now(1), now(2), false, 200},
|
||||
{now(1), now(0), false, 400},
|
||||
{now(0), time.Time{}, true, 500},
|
||||
} {
|
||||
alerts := []model.Alert{{
|
||||
StartsAt: tc.start,
|
||||
EndsAt: tc.end,
|
||||
Labels: model.LabelSet{"label1": "test1"},
|
||||
Annotations: model.LabelSet{"annotation1": "some text"},
|
||||
}}
|
||||
b, err := json.Marshal(&alerts)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
api := New(&fakeAlerts{putWithErr: tc.err}, nil, groupAlerts, getAlertStatus, nil, nil)
|
||||
|
||||
r, err := http.NewRequest("POST", "/api/v1/alerts", bytes.NewReader(b))
|
||||
w := httptest.NewRecorder()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
api.addAlerts(w, r)
|
||||
res := w.Result()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
|
||||
require.Equal(t, tc.code, w.Code, fmt.Sprintf("test case: %d, StartsAt %v, EndsAt %v, Response: %s", i, tc.start, tc.end, string(body)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertFiltering(t *testing.T) {
|
||||
type test struct {
|
||||
alert *model.Alert
|
||||
@ -21,7 +98,7 @@ func TestAlertFiltering(t *testing.T) {
|
||||
// Equal
|
||||
equal, err := labels.NewMatcher(labels.MatchEqual, "label1", "test1")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests := []test{
|
||||
@ -39,7 +116,7 @@ func TestAlertFiltering(t *testing.T) {
|
||||
// Not Equal
|
||||
notEqual, err := labels.NewMatcher(labels.MatchNotEqual, "label1", "test1")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
@ -57,7 +134,7 @@ func TestAlertFiltering(t *testing.T) {
|
||||
// Regexp Equal
|
||||
regexpEqual, err := labels.NewMatcher(labels.MatchRegexp, "label1", "tes.*")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
@ -75,7 +152,7 @@ func TestAlertFiltering(t *testing.T) {
|
||||
// Regexp Not Equal
|
||||
regexpNotEqual, err := labels.NewMatcher(labels.MatchNotRegexp, "label1", "tes.*")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
@ -101,7 +178,7 @@ func TestSilenceFiltering(t *testing.T) {
|
||||
// Equal
|
||||
equal, err := labels.NewMatcher(labels.MatchEqual, "label1", "test1")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests := []test{
|
||||
@ -131,7 +208,7 @@ func TestSilenceFiltering(t *testing.T) {
|
||||
// Not Equal
|
||||
notEqual, err := labels.NewMatcher(labels.MatchNotEqual, "label1", "test1")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
@ -161,7 +238,7 @@ func TestSilenceFiltering(t *testing.T) {
|
||||
// Regexp Equal
|
||||
regexpEqual, err := labels.NewMatcher(labels.MatchRegexp, "label1", "tes.*")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
@ -191,7 +268,7 @@ func TestSilenceFiltering(t *testing.T) {
|
||||
// Regexp Not Equal
|
||||
regexpNotEqual, err := labels.NewMatcher(labels.MatchNotRegexp, "label1", "tes.*")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
@ -224,13 +301,13 @@ func TestReceiversMatchFilter(t *testing.T) {
|
||||
|
||||
filter, err := regexp.Compile(fmt.Sprintf("^(?:%s)$", "hip.*"))
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
require.True(t, receiversMatchFilter(receivers, filter))
|
||||
|
||||
filter, err = regexp.Compile(fmt.Sprintf("^(?:%s)$", "hip"))
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
t.Errorf("Unexpected error %v", err)
|
||||
}
|
||||
require.False(t, receiversMatchFilter(receivers, filter))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user