Fix silences negative filtering (#1095)
* Fix silence negative filtering * Refactor extract filtering labels func
This commit is contained in:
parent
e303646b80
commit
10ed60361d
41
api/api.go
41
api/api.go
|
@ -400,21 +400,11 @@ func receiversMatchFilter(receivers []string, filter *regexp.Regexp) bool {
|
|||
}
|
||||
|
||||
func alertMatchesFilterLabels(a *model.Alert, matchers []*labels.Matcher) bool {
|
||||
for _, m := range matchers {
|
||||
v, prs := a.Labels[model.LabelName(m.Name)]
|
||||
switch m.Type {
|
||||
case labels.MatchNotEqual, labels.MatchNotRegexp:
|
||||
if !m.Matches(string(v)) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !prs || !m.Matches(string(v)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
sms := make(map[string]string)
|
||||
for name, value := range a.Labels {
|
||||
sms[string(name)] = string(value)
|
||||
}
|
||||
|
||||
return true
|
||||
return matchFilterLabels(matchers, sms)
|
||||
}
|
||||
|
||||
func (api *API) legacyAddAlerts(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -618,7 +608,7 @@ func (api *API) listSilences(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if !matchesFilterLabels(s, matchers) {
|
||||
if !silenceMatchesFilterLabels(s, matchers) {
|
||||
continue
|
||||
}
|
||||
sils = append(sils, s)
|
||||
|
@ -657,14 +647,27 @@ func (api *API) listSilences(w http.ResponseWriter, r *http.Request) {
|
|||
api.respond(w, silences)
|
||||
}
|
||||
|
||||
func matchesFilterLabels(s *types.Silence, matchers []*labels.Matcher) bool {
|
||||
sms := map[string]string{}
|
||||
func silenceMatchesFilterLabels(s *types.Silence, matchers []*labels.Matcher) bool {
|
||||
sms := make(map[string]string)
|
||||
for _, m := range s.Matchers {
|
||||
sms[m.Name] = m.Value
|
||||
}
|
||||
|
||||
return matchFilterLabels(matchers, sms)
|
||||
}
|
||||
|
||||
func matchFilterLabels(matchers []*labels.Matcher, sms map[string]string) bool {
|
||||
for _, m := range matchers {
|
||||
if v, prs := sms[m.Name]; !prs || !m.Matches(v) {
|
||||
return false
|
||||
v, prs := sms[m.Name]
|
||||
switch m.Type {
|
||||
case labels.MatchNotEqual, labels.MatchNotRegexp:
|
||||
if !m.Matches(string(v)) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !prs || !m.Matches(string(v)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
137
api/api_test.go
137
api/api_test.go
|
@ -5,6 +5,7 @@ import (
|
|||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/prometheus/pkg/labels"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -90,6 +91,134 @@ func TestAlertFiltering(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSilenceFiltering(t *testing.T) {
|
||||
type test struct {
|
||||
silence *types.Silence
|
||||
msg string
|
||||
expected bool
|
||||
}
|
||||
|
||||
// Equal
|
||||
equal, err := labels.NewMatcher(labels.MatchEqual, "label1", "test1")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests := []test{
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})},
|
||||
"label1=test1",
|
||||
true,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})},
|
||||
"label1=test2",
|
||||
false,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})},
|
||||
"label2=test2",
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{equal})
|
||||
msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg)
|
||||
require.Equal(t, test.expected, actual, msg)
|
||||
}
|
||||
|
||||
// Not Equal
|
||||
notEqual, err := labels.NewMatcher(labels.MatchNotEqual, "label1", "test1")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})},
|
||||
"label1!=test1",
|
||||
false,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})},
|
||||
"label1!=test2",
|
||||
true,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})},
|
||||
"label2!=test2",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{notEqual})
|
||||
msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg)
|
||||
require.Equal(t, test.expected, actual, msg)
|
||||
}
|
||||
|
||||
// Regexp Equal
|
||||
regexpEqual, err := labels.NewMatcher(labels.MatchRegexp, "label1", "tes.*")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})},
|
||||
"label1=~test1",
|
||||
true,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})},
|
||||
"label1=~test2",
|
||||
true,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})},
|
||||
"label2=~test2",
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{regexpEqual})
|
||||
msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg)
|
||||
require.Equal(t, test.expected, actual, msg)
|
||||
}
|
||||
|
||||
// Regexp Not Equal
|
||||
regexpNotEqual, err := labels.NewMatcher(labels.MatchNotRegexp, "label1", "tes.*")
|
||||
if err != nil {
|
||||
t.Error("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
tests = []test{
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test1"})},
|
||||
"label1!~test1",
|
||||
false,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label1": "test2"})},
|
||||
"label1!~test2",
|
||||
false,
|
||||
},
|
||||
{
|
||||
&types.Silence{Matchers: newMatcher(model.LabelSet{"label2": "test2"})},
|
||||
"label2!~test2",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
actual := silenceMatchesFilterLabels(test.silence, []*labels.Matcher{regexpNotEqual})
|
||||
msg := fmt.Sprintf("Expected %t for %s", test.expected, test.msg)
|
||||
require.Equal(t, test.expected, actual, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReceiversMatchFilter(t *testing.T) {
|
||||
receivers := []string{"pagerduty", "slack", "hipchat"}
|
||||
|
||||
|
@ -105,3 +234,11 @@ func TestReceiversMatchFilter(t *testing.T) {
|
|||
}
|
||||
require.False(t, receiversMatchFilter(receivers, filter))
|
||||
}
|
||||
|
||||
func newMatcher(labelSet model.LabelSet) types.Matchers {
|
||||
matchers := make([]*types.Matcher, 0, len(labelSet))
|
||||
for key, val := range labelSet {
|
||||
matchers = append(matchers, types.NewMatcher(key, string(val)))
|
||||
}
|
||||
return matchers
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue