mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Hook up GMA silence APIs to new authentication handler (#86625)
This PR connects the new RBAC authentication service to existing alertmanager API silence endpoints.
This commit is contained in:
@@ -1,11 +1,37 @@
|
||||
package models
|
||||
|
||||
// Silence is the model-layer representation of an alertmanager silence.
|
||||
type Silence struct { // TODO implement using matchers
|
||||
ID *string
|
||||
RuleUID *string
|
||||
import (
|
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models"
|
||||
|
||||
alertingModels "github.com/grafana/alerting/models"
|
||||
"github.com/grafana/alerting/notify"
|
||||
)
|
||||
|
||||
// Silence is the model-layer representation of an alertmanager silence. Currently just a wrapper around the
|
||||
// alerting notify.Silence.
|
||||
type Silence notify.GettableSilence
|
||||
|
||||
// GetRuleUID returns the rule UID of the silence if the silence is associated with a rule, otherwise nil.
|
||||
// Currently, this works by looking for a matcher with the RuleUIDLabel name and returning its value.
|
||||
func (s Silence) GetRuleUID() *string {
|
||||
return getRuleUIDLabelValue(s.Silence)
|
||||
}
|
||||
|
||||
func (s *Silence) GetRuleUID() *string {
|
||||
return s.RuleUID
|
||||
// getRuleUIDLabelValue returns the value of the RuleUIDLabel matcher in the given silence, if it exists.
|
||||
func getRuleUIDLabelValue(silence notify.Silence) *string {
|
||||
for _, m := range silence.Matchers {
|
||||
if m != nil && isRuleUIDMatcher(*m) {
|
||||
return m.Value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isRuleUIDMatcher(m amv2.Matcher) bool {
|
||||
return isEqualMatcher(m) && m.Name != nil && *m.Name == alertingModels.RuleUIDLabel
|
||||
}
|
||||
|
||||
func isEqualMatcher(m amv2.Matcher) bool {
|
||||
// If IsEqual is nil, it is considered to be true.
|
||||
return (m.IsEqual == nil || *m.IsEqual) && (m.IsRegex == nil || !*m.IsRegex)
|
||||
}
|
||||
|
||||
50
pkg/services/ngalert/models/silence_test.go
Normal file
50
pkg/services/ngalert/models/silence_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/grafana/alerting/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func TestSilenceGetRuleUID(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
silence Silence
|
||||
expectedRuleUID *string
|
||||
}{
|
||||
{
|
||||
name: "silence with no rule UID",
|
||||
silence: SilenceGen()(),
|
||||
expectedRuleUID: nil,
|
||||
},
|
||||
{
|
||||
name: "silence with rule UID",
|
||||
silence: SilenceGen(SilenceMuts.WithMatcher(models.RuleUIDLabel, "someuid", labels.MatchEqual))(),
|
||||
expectedRuleUID: util.Pointer("someuid"),
|
||||
},
|
||||
{
|
||||
name: "silence with rule UID Matcher but MatchNotEqual",
|
||||
silence: SilenceGen(SilenceMuts.WithMatcher(models.RuleUIDLabel, "someuid", labels.MatchNotEqual))(),
|
||||
expectedRuleUID: nil,
|
||||
},
|
||||
{
|
||||
name: "silence with rule UID Matcher but MatchRegexp",
|
||||
silence: SilenceGen(SilenceMuts.WithMatcher(models.RuleUIDLabel, "someuid", labels.MatchRegexp))(),
|
||||
expectedRuleUID: nil,
|
||||
},
|
||||
{
|
||||
name: "silence with rule UID Matcher but MatchNotRegexp",
|
||||
silence: SilenceGen(SilenceMuts.WithMatcher(models.RuleUIDLabel, "someuid", labels.MatchNotRegexp))(),
|
||||
expectedRuleUID: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expectedRuleUID, tt.silence.GetRuleUID(), "unexpected rule UID")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -903,3 +906,117 @@ func (n NotificationSettingsMutators) WithMuteTimeIntervals(muteTimeIntervals ..
|
||||
ns.MuteTimeIntervals = muteTimeIntervals
|
||||
}
|
||||
}
|
||||
|
||||
// Silences
|
||||
|
||||
// CopySilenceWith creates a deep copy of Silence and then applies mutators to it.
|
||||
func CopySilenceWith(s Silence, mutators ...Mutator[Silence]) Silence {
|
||||
c := CopySilence(s)
|
||||
for _, mutator := range mutators {
|
||||
mutator(&c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// CopySilence creates a deep copy of Silence.
|
||||
func CopySilence(s Silence) Silence {
|
||||
c := Silence{
|
||||
Silence: amv2.Silence{},
|
||||
}
|
||||
|
||||
if s.ID != nil {
|
||||
c.ID = util.Pointer(*s.ID)
|
||||
}
|
||||
if s.Status != nil {
|
||||
c.Status = util.Pointer(*s.Status)
|
||||
}
|
||||
if s.UpdatedAt != nil {
|
||||
c.UpdatedAt = util.Pointer(*s.UpdatedAt)
|
||||
}
|
||||
if s.Silence.Comment != nil {
|
||||
c.Silence.Comment = util.Pointer(*s.Silence.Comment)
|
||||
}
|
||||
if s.Silence.CreatedBy != nil {
|
||||
c.Silence.CreatedBy = util.Pointer(*s.Silence.CreatedBy)
|
||||
}
|
||||
if s.Silence.EndsAt != nil {
|
||||
c.Silence.EndsAt = util.Pointer(*s.Silence.EndsAt)
|
||||
}
|
||||
if s.Silence.StartsAt != nil {
|
||||
c.Silence.StartsAt = util.Pointer(*s.Silence.StartsAt)
|
||||
}
|
||||
if s.Silence.Matchers != nil {
|
||||
c.Silence.Matchers = CopyMatchers(s.Silence.Matchers)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// CopyMatchers creates a deep copy of Matchers.
|
||||
func CopyMatchers(matchers []*amv2.Matcher) []*amv2.Matcher {
|
||||
copies := make([]*amv2.Matcher, len(matchers))
|
||||
for i, m := range matchers {
|
||||
c := amv2.Matcher{}
|
||||
if m.IsEqual != nil {
|
||||
c.IsEqual = util.Pointer(*m.IsEqual)
|
||||
}
|
||||
if m.IsRegex != nil {
|
||||
c.IsRegex = util.Pointer(*m.IsRegex)
|
||||
}
|
||||
if m.Name != nil {
|
||||
c.Name = util.Pointer(*m.Name)
|
||||
}
|
||||
if m.Value != nil {
|
||||
c.Value = util.Pointer(*m.Value)
|
||||
}
|
||||
copies[i] = &c
|
||||
}
|
||||
return copies
|
||||
}
|
||||
|
||||
// SilenceGen generates Silence using a base and mutators.
|
||||
func SilenceGen(mutators ...Mutator[Silence]) func() Silence {
|
||||
return func() Silence {
|
||||
now := time.Now()
|
||||
c := Silence{
|
||||
ID: util.Pointer(util.GenerateShortUID()),
|
||||
Status: util.Pointer(amv2.SilenceStatus{State: util.Pointer(amv2.SilenceStatusStateActive)}),
|
||||
UpdatedAt: util.Pointer(strfmt.DateTime(now.Add(time.Minute))),
|
||||
Silence: amv2.Silence{
|
||||
Comment: util.Pointer(util.GenerateShortUID()),
|
||||
CreatedBy: util.Pointer(util.GenerateShortUID()),
|
||||
StartsAt: util.Pointer(strfmt.DateTime(now.Add(-time.Minute))),
|
||||
EndsAt: util.Pointer(strfmt.DateTime(now.Add(time.Minute))),
|
||||
Matchers: []*amv2.Matcher{{Name: util.Pointer(util.GenerateShortUID()), Value: util.Pointer(util.GenerateShortUID()), IsRegex: util.Pointer(false), IsEqual: util.Pointer(true)}},
|
||||
},
|
||||
}
|
||||
for _, mutator := range mutators {
|
||||
mutator(&c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
SilenceMuts = SilenceMutators{}
|
||||
)
|
||||
|
||||
type SilenceMutators struct{}
|
||||
|
||||
func (n SilenceMutators) WithMatcher(name, value string, matchType labels.MatchType) Mutator[Silence] {
|
||||
return func(s *Silence) {
|
||||
m := amv2.Matcher{
|
||||
Name: &name,
|
||||
Value: &value,
|
||||
IsRegex: util.Pointer(matchType == labels.MatchRegexp || matchType == labels.MatchNotRegexp),
|
||||
IsEqual: util.Pointer(matchType == labels.MatchRegexp || matchType == labels.MatchEqual),
|
||||
}
|
||||
s.Silence.Matchers = append(s.Silence.Matchers, &m)
|
||||
}
|
||||
}
|
||||
|
||||
func (n SilenceMutators) WithEmptyId() Mutator[Silence] {
|
||||
return func(s *Silence) {
|
||||
s.ID = util.Pointer("")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user