mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Remove unused code after importing from grafana/alerting (#61869)
* Alerting: Remove unused code after importing from grafana/alerting
This commit is contained in:
parent
cd99bfec68
commit
0be920e61c
@ -1,4 +1,3 @@
|
||||
//nolint:golint,unused
|
||||
package notifier
|
||||
|
||||
import (
|
||||
@ -8,29 +7,12 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/alertmanager/dispatch"
|
||||
"github.com/prometheus/alertmanager/inhibit"
|
||||
"github.com/prometheus/alertmanager/nflog"
|
||||
"github.com/prometheus/alertmanager/nflog/nflogpb"
|
||||
"github.com/prometheus/alertmanager/notify"
|
||||
"github.com/prometheus/alertmanager/provider/mem"
|
||||
"github.com/prometheus/alertmanager/silence"
|
||||
"github.com/prometheus/alertmanager/timeinterval"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/grafana/alerting/alerting"
|
||||
"github.com/grafana/alerting/alerting/notifier/channels"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
@ -40,6 +22,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/notifications"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -47,13 +31,8 @@ const (
|
||||
silencesFilename = "silences"
|
||||
|
||||
workingDir = "alerting"
|
||||
// maintenanceNotificationAndSilences how often should we flush and gargabe collect notifications
|
||||
// maintenanceNotificationAndSilences how often should we flush and garbage collect notifications
|
||||
notificationLogMaintenanceInterval = 15 * time.Minute
|
||||
// defaultResolveTimeout is the default timeout used for resolving an alert
|
||||
// if the end time is not specified.
|
||||
defaultResolveTimeout = 5 * time.Minute
|
||||
// memoryAlertsGCInterval is the interval at which we'll remove resolved alerts from memory.
|
||||
memoryAlertsGCInterval = 30 * time.Minute
|
||||
)
|
||||
|
||||
// How long should we keep silences and notification entries on-disk after they've served their purpose.
|
||||
@ -72,42 +51,10 @@ type Alertmanager struct {
|
||||
Settings *setting.Cfg
|
||||
Store AlertingStore
|
||||
fileStore *FileStore
|
||||
Metrics *metrics.Alertmanager
|
||||
NotificationService notifications.Service
|
||||
|
||||
notificationLog *nflog.Log
|
||||
marker types.Marker
|
||||
alerts *mem.Alerts
|
||||
route *dispatch.Route
|
||||
peer alerting.ClusterPeer
|
||||
peerTimeout time.Duration
|
||||
|
||||
dispatcher *dispatch.Dispatcher
|
||||
inhibitor *inhibit.Inhibitor
|
||||
// wg is for dispatcher, inhibitor, silences and notifications
|
||||
// Across configuration changes dispatcher and inhibitor are completely replaced, however, silences, notification log and alerts remain the same.
|
||||
// stopc is used to let silences and notifications know we are done.
|
||||
stopc chan struct{}
|
||||
wg sync.WaitGroup
|
||||
|
||||
silencer *silence.Silencer
|
||||
silences *silence.Silences
|
||||
|
||||
receivers []*alerting.Receiver
|
||||
|
||||
// muteTimes is a map where the key is the name of the mute_time_interval
|
||||
// and the value represents all configured time_interval(s)
|
||||
muteTimes map[string][]timeinterval.TimeInterval
|
||||
|
||||
stageMetrics *notify.Metrics
|
||||
dispatcherMetrics *dispatch.DispatcherMetrics
|
||||
|
||||
reloadConfigMtx sync.RWMutex
|
||||
config *apimodels.PostableUserConfig
|
||||
configHash [16]byte
|
||||
orgID int64
|
||||
|
||||
decryptFn channels.GetDecryptedValueFn
|
||||
orgID int64
|
||||
}
|
||||
|
||||
// maintenanceOptions represent the options for components that need maintenance on a frequency within the Alertmanager.
|
||||
@ -203,16 +150,12 @@ func (am *Alertmanager) Ready() bool {
|
||||
return am.Base.Ready()
|
||||
}
|
||||
|
||||
func (am *Alertmanager) ready() bool {
|
||||
return am.config != nil
|
||||
}
|
||||
|
||||
func (am *Alertmanager) StopAndWait() {
|
||||
am.Base.StopAndWait()
|
||||
}
|
||||
|
||||
// SaveAndApplyDefaultConfig saves the default configuration the database and applies the configuration to the Alertmanager.
|
||||
// It rollbacks the save if we fail to apply the configuration.
|
||||
// It rolls back the save if we fail to apply the configuration.
|
||||
func (am *Alertmanager) SaveAndApplyDefaultConfig(ctx context.Context) error {
|
||||
var outerErr error
|
||||
am.Base.WithLock(func() {
|
||||
@ -294,40 +237,6 @@ func (am *Alertmanager) ApplyConfig(dbCfg *ngmodels.AlertConfiguration) error {
|
||||
return outerErr
|
||||
}
|
||||
|
||||
func (am *Alertmanager) getTemplate() (*alerting.Template, error) {
|
||||
am.reloadConfigMtx.RLock()
|
||||
defer am.reloadConfigMtx.RUnlock()
|
||||
if !am.ready() {
|
||||
return nil, errors.New("alertmanager is not initialized")
|
||||
}
|
||||
paths := make([]string, 0, len(am.config.TemplateFiles))
|
||||
for name := range am.config.TemplateFiles {
|
||||
paths = append(paths, filepath.Join(am.WorkingDirPath(), name))
|
||||
}
|
||||
return am.templateFromPaths(paths...)
|
||||
}
|
||||
|
||||
func (am *Alertmanager) templateFromPaths(paths ...string) (*alerting.Template, error) {
|
||||
tmpl, err := alerting.FromGlobs(paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
externalURL, err := url.Parse(am.Settings.AppURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpl.ExternalURL = externalURL
|
||||
return tmpl, nil
|
||||
}
|
||||
|
||||
func (am *Alertmanager) buildMuteTimesMap(muteTimeIntervals []config.MuteTimeInterval) map[string][]timeinterval.TimeInterval {
|
||||
muteTimes := make(map[string][]timeinterval.TimeInterval, len(muteTimeIntervals))
|
||||
for _, ti := range muteTimeIntervals {
|
||||
muteTimes[ti.Name] = ti.TimeIntervals
|
||||
}
|
||||
return muteTimes
|
||||
}
|
||||
|
||||
// applyConfig applies a new configuration by re-initializing all components using the configuration provided.
|
||||
// It is not safe to call concurrently.
|
||||
func (am *Alertmanager) applyConfig(cfg *apimodels.PostableUserConfig, rawConfig []byte) (err error) {
|
||||
@ -479,51 +388,6 @@ func (am *Alertmanager) PutAlerts(postableAlerts apimodels.PostableAlerts) error
|
||||
return am.Base.PutAlerts(alerts)
|
||||
}
|
||||
|
||||
// validateAlert is a.Validate() while additionally allowing
|
||||
// space for label and annotation names.
|
||||
func validateAlert(a *types.Alert) error {
|
||||
if a.StartsAt.IsZero() {
|
||||
return fmt.Errorf("start time missing")
|
||||
}
|
||||
if !a.EndsAt.IsZero() && a.EndsAt.Before(a.StartsAt) {
|
||||
return fmt.Errorf("start time must be before end time")
|
||||
}
|
||||
if err := validateLabelSet(a.Labels); err != nil {
|
||||
return fmt.Errorf("invalid label set: %s", err)
|
||||
}
|
||||
if len(a.Labels) == 0 {
|
||||
return fmt.Errorf("at least one label pair required")
|
||||
}
|
||||
if err := validateLabelSet(a.Annotations); err != nil {
|
||||
return fmt.Errorf("invalid annotations: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateLabelSet is ls.Validate() while additionally allowing
|
||||
// space for label names.
|
||||
func validateLabelSet(ls model.LabelSet) error {
|
||||
for ln, lv := range ls {
|
||||
if !isValidLabelName(ln) {
|
||||
return fmt.Errorf("invalid name %q", ln)
|
||||
}
|
||||
if !lv.IsValid() {
|
||||
return fmt.Errorf("invalid value %q", lv)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isValidLabelName is ln.IsValid() without restrictions other than it can not be empty.
|
||||
// The regex for Prometheus data model is ^[a-zA-Z_][a-zA-Z0-9_]*$.
|
||||
func isValidLabelName(ln model.LabelName) bool {
|
||||
if len(ln) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return utf8.ValidString(string(ln))
|
||||
}
|
||||
|
||||
// AlertValidationError is the error capturing the validation errors
|
||||
// faced on the alerts.
|
||||
type AlertValidationError struct {
|
||||
@ -542,50 +406,6 @@ func (e AlertValidationError) Error() string {
|
||||
return errMsg
|
||||
}
|
||||
|
||||
// createReceiverStage creates a pipeline of stages for a receiver.
|
||||
func (am *Alertmanager) createReceiverStage(name string, integrations []*notify.Integration, wait func() time.Duration, notificationLog notify.NotificationLog) notify.Stage {
|
||||
var fs notify.FanoutStage
|
||||
for _, integration := range integrations {
|
||||
recv := &nflogpb.Receiver{
|
||||
GroupName: name,
|
||||
Integration: integration.Name(),
|
||||
Idx: uint32(integration.Index()),
|
||||
}
|
||||
var s notify.MultiStage
|
||||
s = append(s, notify.NewWaitStage(wait))
|
||||
s = append(s, notify.NewDedupStage(integration, notificationLog, recv))
|
||||
s = append(s, notify.NewRetryStage(integration, name, am.stageMetrics))
|
||||
s = append(s, notify.NewSetNotifiesStage(notificationLog, recv))
|
||||
|
||||
fs = append(fs, s)
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// getActiveReceiversMap returns all receivers that are in use by a route.
|
||||
func (am *Alertmanager) getActiveReceiversMap(r *dispatch.Route) map[string]struct{} {
|
||||
receiversMap := make(map[string]struct{})
|
||||
visitFunc := func(r *dispatch.Route) {
|
||||
receiversMap[r.RouteOpts.Receiver] = struct{}{}
|
||||
}
|
||||
r.Walk(visitFunc)
|
||||
|
||||
return receiversMap
|
||||
}
|
||||
|
||||
func (am *Alertmanager) waitFunc() time.Duration {
|
||||
return time.Duration(am.peer.Position()) * am.peerTimeout
|
||||
}
|
||||
|
||||
func (am *Alertmanager) timeoutFunc(d time.Duration) time.Duration {
|
||||
// time.Duration d relates to the receiver's group_interval. Even with a group interval of 1s,
|
||||
// we need to make sure (non-position-0) peers in the cluster wait before flushing the notifications.
|
||||
if d < notify.MinTimeout {
|
||||
d = notify.MinTimeout
|
||||
}
|
||||
return d + am.waitFunc()
|
||||
}
|
||||
|
||||
type nilLimits struct{}
|
||||
|
||||
func (n nilLimits) MaxNumberOfAggregationGroups() int { return 0 }
|
||||
|
@ -2,25 +2,17 @@ package notifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/provider/mem"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
@ -53,367 +45,7 @@ func setupAMTest(t *testing.T) *Alertmanager {
|
||||
return am
|
||||
}
|
||||
|
||||
func TestPutAlert(t *testing.T) {
|
||||
t.SkipNow()
|
||||
func TestAlertmanager_newAlertmanager(t *testing.T) {
|
||||
am := setupAMTest(t)
|
||||
|
||||
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: "Allow spaces in label and annotation name",
|
||||
postableAlerts: apimodels.PostableAlerts{
|
||||
PostableAlerts: []models.PostableAlert{
|
||||
{
|
||||
Annotations: models.LabelSet{"Dashboard URL": "http://localhost:3000"},
|
||||
Alert: models.Alert{
|
||||
Labels: models.LabelSet{"alertname": "Alert4", "Spaced Label": "works"},
|
||||
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{"Dashboard URL": "http://localhost:3000"},
|
||||
Labels: model.LabelSet{"alertname": "Alert4", "Spaced Label": "works"},
|
||||
StartsAt: now,
|
||||
EndsAt: now.Add(defaultResolveTimeout),
|
||||
GeneratorURL: "http://localhost/url1",
|
||||
},
|
||||
UpdatedAt: now,
|
||||
Timeout: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
}, {
|
||||
title: "Special characters in labels",
|
||||
postableAlerts: apimodels.PostableAlerts{
|
||||
PostableAlerts: []models.PostableAlert{
|
||||
{
|
||||
Alert: models.Alert{
|
||||
Labels: models.LabelSet{"alertname$": "Alert1", "az3-- __...++!!!£@@312312": "1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expAlerts: func(now time.Time) []*types.Alert {
|
||||
return []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname$": "Alert1", "az3-- __...++!!!£@@312312": "1"},
|
||||
Annotations: model.LabelSet{},
|
||||
StartsAt: now,
|
||||
EndsAt: now.Add(defaultResolveTimeout),
|
||||
GeneratorURL: "",
|
||||
},
|
||||
UpdatedAt: now,
|
||||
Timeout: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
}, {
|
||||
title: "Special characters in annotations",
|
||||
postableAlerts: apimodels.PostableAlerts{
|
||||
PostableAlerts: []models.PostableAlert{
|
||||
{
|
||||
Annotations: models.LabelSet{"az3-- __...++!!!£@@312312": "Alert4 annotation"},
|
||||
Alert: models.Alert{
|
||||
Labels: models.LabelSet{"alertname": "Alert4"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expAlerts: func(now time.Time) []*types.Alert {
|
||||
return []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "Alert4"},
|
||||
Annotations: model.LabelSet{"az3-- __...++!!!£@@312312": "Alert4 annotation"},
|
||||
StartsAt: now,
|
||||
EndsAt: now.Add(defaultResolveTimeout),
|
||||
GeneratorURL: "",
|
||||
},
|
||||
UpdatedAt: now,
|
||||
Timeout: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
}, {
|
||||
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 {
|
||||
var err error
|
||||
t.Run(c.title, func(t *testing.T) {
|
||||
r := prometheus.NewRegistry()
|
||||
am.marker = types.NewMarker(r)
|
||||
am.alerts, err = mem.NewAlerts(context.Background(), am.marker, 15*time.Minute, nil, am.logger, r)
|
||||
require.NoError(t, err)
|
||||
|
||||
alerts := []*types.Alert{}
|
||||
err := am.PutAlerts(c.postableAlerts)
|
||||
if c.expError != nil {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, c.expError, err)
|
||||
require.Equal(t, 0, len(alerts))
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
iter := am.alerts.GetPending()
|
||||
defer iter.Close()
|
||||
for a := range iter.Next() {
|
||||
alerts = append(alerts, a)
|
||||
}
|
||||
|
||||
// We take the "now" time from one of the UpdatedAt.
|
||||
now := alerts[0].UpdatedAt
|
||||
expAlerts := c.expAlerts(now)
|
||||
|
||||
sort.Sort(types.AlertSlice(expAlerts))
|
||||
sort.Sort(types.AlertSlice(alerts))
|
||||
|
||||
require.Equal(t, expAlerts, alerts)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Tests cleanup of expired Silences. We rely on prometheus/alertmanager for
|
||||
// our alert silencing functionality, so we rely on its tests. However, we
|
||||
// implement a custom maintenance function for silences, because we snapshot
|
||||
// our data differently, so we test that functionality.
|
||||
func TestSilenceCleanup(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
oldRetention := retentionNotificationsAndSilences
|
||||
retentionNotificationsAndSilences = 30 * time.Millisecond
|
||||
oldMaintenance := silenceMaintenanceInterval
|
||||
silenceMaintenanceInterval = 15 * time.Millisecond
|
||||
t.Cleanup(
|
||||
func() {
|
||||
retentionNotificationsAndSilences = oldRetention
|
||||
silenceMaintenanceInterval = oldMaintenance
|
||||
})
|
||||
|
||||
am := setupAMTest(t)
|
||||
now := time.Now()
|
||||
dt := func(t time.Time) strfmt.DateTime { return strfmt.DateTime(t) }
|
||||
|
||||
makeSilence := func(comment string, createdBy string,
|
||||
startsAt, endsAt strfmt.DateTime, matchers models.Matchers) *apimodels.PostableSilence {
|
||||
return &apimodels.PostableSilence{
|
||||
ID: "",
|
||||
Silence: models.Silence{
|
||||
Comment: &comment,
|
||||
CreatedBy: &createdBy,
|
||||
StartsAt: &startsAt,
|
||||
EndsAt: &endsAt,
|
||||
Matchers: matchers,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
tru := true
|
||||
testString := "testName"
|
||||
matchers := models.Matchers{&models.Matcher{Name: &testString, IsEqual: &tru, IsRegex: &tru, Value: &testString}}
|
||||
// Create silences - one in the future, one currently active, one expired but
|
||||
// retained, one expired and not retained.
|
||||
silences := []*apimodels.PostableSilence{
|
||||
// Active in future
|
||||
makeSilence("", "tests", dt(now.Add(5*time.Hour)), dt(now.Add(6*time.Hour)), matchers),
|
||||
// Active now
|
||||
makeSilence("", "tests", dt(now.Add(-5*time.Hour)), dt(now.Add(6*time.Hour)), matchers),
|
||||
// Expiring soon.
|
||||
makeSilence("", "tests", dt(now.Add(-5*time.Hour)), dt(now.Add(2*time.Second)), matchers),
|
||||
// Expiring *very* soon
|
||||
makeSilence("", "tests", dt(now.Add(-5*time.Hour)), dt(now.Add(1*time.Second)), matchers),
|
||||
}
|
||||
|
||||
for _, s := range silences {
|
||||
_, err := am.CreateSilence(s)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
// Let enough time pass for the maintenance window to run.
|
||||
require.Eventually(func() bool {
|
||||
// So, what silences do we have now?
|
||||
found, err := am.ListSilences(nil)
|
||||
require.NoError(err)
|
||||
return len(found) == 3
|
||||
}, 3*time.Second, 100*time.Millisecond)
|
||||
|
||||
// Wait again for another silence to expire.
|
||||
require.Eventually(func() bool {
|
||||
found, err := am.ListSilences(nil)
|
||||
require.NoError(err)
|
||||
return len(found) == 2
|
||||
}, 6*time.Second, 100*time.Millisecond)
|
||||
require.False(t, am.Ready())
|
||||
}
|
||||
|
@ -126,10 +126,7 @@ func (am *Alertmanager) TestReceivers(ctx context.Context, c apimodels.TestRecei
|
||||
}, err
|
||||
}
|
||||
|
||||
func (am *Alertmanager) GetReceivers(ctx context.Context) []apimodels.Receiver {
|
||||
am.reloadConfigMtx.RLock()
|
||||
defer am.reloadConfigMtx.RUnlock()
|
||||
|
||||
func (am *Alertmanager) GetReceivers(_ context.Context) []apimodels.Receiver {
|
||||
apiReceivers := make([]apimodels.Receiver, 0, len(am.Base.GetReceivers()))
|
||||
for _, rcv := range am.Base.GetReceivers() {
|
||||
// Build integrations slice for each receiver.
|
||||
|
Loading…
Reference in New Issue
Block a user