diff --git a/provider/mesh/peer.go b/provider/mesh/peer.go index 7b46d164..15444369 100644 --- a/provider/mesh/peer.go +++ b/provider/mesh/peer.go @@ -2,7 +2,6 @@ package mesh import ( "fmt" - "time" "github.com/prometheus/alertmanager/provider" "github.com/prometheus/alertmanager/types" @@ -161,31 +160,16 @@ func (s *Silences) Set(sil *types.Silence) (uuid.UUID, error) { } func (s *Silences) Del(id uuid.UUID) error { - s.st.mtx.RLock() - sil, ok := s.st.m[id] - s.st.mtx.RUnlock() - if !ok { - return provider.ErrNotFound + sil, err := s.st.del(id) + if err != nil { + return err } - now := time.Now() - if sil.EndsAt.Before(now) { - return fmt.Errorf("silence already ended") - } - // Silences are immutable by contract so we create a completely - // new object instead. - newSil := *sil - newSil.UpdatedAt = now - newSil.EndsAt = now - if err := newSil.Init(); err != nil { - return fmt.Errorf("silence init: %s", err) - } update := &silenceState{ m: map[uuid.UUID]*types.Silence{ - newSil.ID: &newSil, + sil.ID: sil, }, } - s.st.Merge(update) s.send.GossipBroadcast(update) return nil diff --git a/provider/mesh/state.go b/provider/mesh/state.go index bab085ca..f9683b38 100644 --- a/provider/mesh/state.go +++ b/provider/mesh/state.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/prometheus/alertmanager/provider" "github.com/prometheus/alertmanager/types" "github.com/satori/go.uuid" "github.com/weaveworks/mesh" @@ -133,11 +134,10 @@ func (st *silenceState) Encode() [][]byte { // silenceModAllowed checks whether silence a may be changed to silence b. // Returns an error stating the reason if not. -func (st *silenceState) silenceModAllowed(a, b *types.Silence) error { +func silenceModAllowed(a, b *types.Silence, now time.Time) error { if !b.StartsAt.Equal(a.StartsAt) { return fmt.Errorf("silence start time must not be modified") } - now := st.now() if a.EndsAt.Before(now) { return fmt.Errorf("end time must not be modified for elapsed silence") } @@ -154,7 +154,8 @@ func (st *silenceState) set(s *types.Silence) error { st.mtx.Lock() defer st.mtx.Unlock() - s.UpdatedAt = st.now() + now := st.now() + s.UpdatedAt = now if err := s.Validate(); err != nil { return err @@ -165,13 +166,39 @@ func (st *silenceState) set(s *types.Silence) error { st.m[s.ID] = s return nil } - if err := st.silenceModAllowed(prev, s); err != nil { + if err := silenceModAllowed(prev, s, now); err != nil { return err } st.m[s.ID] = s return nil } +func (st *silenceState) del(id uuid.UUID) (*types.Silence, error) { + st.mtx.Lock() + defer st.mtx.Unlock() + + prev, ok := st.m[id] + if !ok { + return nil, provider.ErrNotFound + } + // Silences are immutable by contract so we create a + // shallow copy. + sil := *prev + now := st.now() + sil.UpdatedAt = now + sil.EndsAt = now + + if err := sil.Validate(); err != nil { + return nil, err + } + + if err := silenceModAllowed(prev, &sil, now); err != nil { + return nil, err + } + st.m[sil.ID] = &sil + return &sil, nil +} + func (st *silenceState) Merge(other mesh.GossipData) mesh.GossipData { o := other.(*silenceState) o.mtx.RLock() diff --git a/types/types.go b/types/types.go index 513363f4..0cdf04e5 100644 --- a/types/types.go +++ b/types/types.go @@ -16,6 +16,7 @@ package types import ( "fmt" "hash/fnv" + "sort" "strings" "sync" "time" @@ -276,6 +277,7 @@ func (s *Silence) Init() error { return err } } + sort.Sort(s.Matchers) return nil }