diff --git a/provider/boltmem/boltmem.go b/provider/boltmem/boltmem.go index efa18f7e..120251c8 100644 --- a/provider/boltmem/boltmem.go +++ b/provider/boltmem/boltmem.go @@ -302,6 +302,7 @@ func (s *Silences) Set(sil *types.Silence) (uuid.UUID, error) { b := tx.Bucket(bktSilences) // Silences are immutable and we always create a new one. sil.ID = uuid.NewV4() + sil.UpdatedAt = time.Now() msb, err := json.Marshal(sil) if err != nil { diff --git a/provider/mesh/state.go b/provider/mesh/state.go index 927d1db3..c67e3b36 100644 --- a/provider/mesh/state.go +++ b/provider/mesh/state.go @@ -6,6 +6,8 @@ import ( "sync" "time" + "github.com/prometheus/alertmanager/types" + "github.com/satori/go.uuid" "github.com/weaveworks/mesh" ) @@ -85,3 +87,69 @@ func (st *notificationState) mergeDelta(set map[string]notificationEntry) *notif } return ¬ificationState{set: d} } + +type silenceState struct { + mtx sync.RWMutex + set map[uuid.UUID]*types.Silence +} + +func (st *silenceState) Encode() [][]byte { + st.mtx.RLock() + defer st.mtx.RUnlock() + + var buf bytes.Buffer + if err := gob.NewEncoder(&buf).Encode(&st.set); err != nil { + panic(err) + } + return [][]byte{buf.Bytes()} + +} + +func (st *silenceState) Merge(other mesh.GossipData) mesh.GossipData { + o := other.(*silenceState) + o.mtx.RLock() + defer o.mtx.RUnlock() + + return st.mergeComplete(o.set) +} + +func (st *silenceState) mergeComplete(set map[uuid.UUID]*types.Silence) *silenceState { + st.mtx.Lock() + defer st.mtx.Unlock() + + for k, v := range set { + if prev, ok := st.set[k]; !ok || prev.UpdatedAt.Before(v.UpdatedAt) { + st.set[k] = v + } + } + return st +} + +func (st *silenceState) mergeDelta(set map[uuid.UUID]*types.Silence) *silenceState { + st.mtx.Lock() + defer st.mtx.Unlock() + + d := map[uuid.UUID]*types.Silence{} + + for k, v := range set { + if prev, ok := st.set[k]; !ok || prev.UpdatedAt.Before(v.UpdatedAt) { + st.set[k] = v + d[k] = v + } + + } + return &silenceState{set: d} +} + +func (s *silenceState) copy() *silenceState { + s.mtx.RLock() + defer s.mtx.RUnlock() + + res := &silenceState{ + set: make(map[uuid.UUID]*types.Silence, len(s.set)), + } + for k, v := range s.set { + res.set[k] = v + } + return res +} diff --git a/types/types.go b/types/types.go index e1be0b22..369a2106 100644 --- a/types/types.go +++ b/types/types.go @@ -223,6 +223,9 @@ type Silence struct { StartsAt time.Time `json:"startsAt"` EndsAt time.Time `json:"endsAt"` + // The last time the silence was updated. + UpdatedAt time.Time `json:"updatedAt"` + // Information about who created the silence for which reason. CreatedBy string `json:"createdBy"` Comment string `json:"comment,omitempty"`