mirror of
https://github.com/prometheus/alertmanager
synced 2025-02-16 18:47:10 +00:00
provider/boltmem: Implement Notify, add dummies
This commit creates dummy implementations of the provider interfaces for the boltmem provider. It implements the NotifyInfo provider in BoltDB.
This commit is contained in:
parent
ff182863b3
commit
0019d4f858
174
provider/boltmem/boltmem.go
Normal file
174
provider/boltmem/boltmem.go
Normal file
@ -0,0 +1,174 @@
|
||||
package boltmem
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/prometheus/alertmanager/provider"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// Alerts gives access to a set of alerts. All methods are goroutine-safe.
|
||||
type Alerts struct {
|
||||
mtx sync.RWMutex
|
||||
alerts map[model.Fingerprint]*types.Alert
|
||||
|
||||
listeners map[int]chan *types.Alert
|
||||
}
|
||||
|
||||
func NewAlerts() (*Alerts, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Subscribe returns an iterator over active alerts that have not been
|
||||
// resolved and successfully notified about.
|
||||
// They are not guaranteed to be in chronological order.
|
||||
func (a *Alerts) Subscribe() provider.AlertIterator {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPending returns an iterator over all alerts that have
|
||||
// pending notifications.
|
||||
func (a *Alerts) GetPending() provider.AlertIterator {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the alert for a given fingerprint.
|
||||
func (a *Alerts) Get(model.Fingerprint) (*types.Alert, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Put adds the given alert to the set.
|
||||
func (a *Alerts) Put(...*types.Alert) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Silences gives access to silences. All methods are goroutine-safe.
|
||||
type Silences struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
func NewSilences(path string) (*Silences, error) {
|
||||
db, err := bolt.Open(filepath.Join(path, "silences.db"), 0666, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Silences{db: db}, nil
|
||||
}
|
||||
|
||||
// The Silences provider must implement the Muter interface
|
||||
// for all its silences. The data provider may have access to an
|
||||
// optimized view of the data to perform this evaluation.
|
||||
func (s *Silences) Mutes(lset model.LabelSet) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// All returns all existing silences.
|
||||
func (s *Silences) All() ([]*types.Silence, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Set a new silence.
|
||||
func (s *Silences) Set(*types.Silence) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Del removes a silence.
|
||||
func (s *Silences) Del(uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get a silence associated with a fingerprint.
|
||||
func (s *Silences) Get(uint64) (*types.Silence, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Notifies provides information about pending and successful
|
||||
// notifications. All methods are goroutine-safe.
|
||||
type Notifies struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
func NewNotifies(path string) (*Notifies, error) {
|
||||
db, err := bolt.Open(filepath.Join(path, "notifies.db"), 0666, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(bktNotifies)
|
||||
return err
|
||||
})
|
||||
return &Notifies{db: db}, err
|
||||
}
|
||||
|
||||
var (
|
||||
bktNotifies = []byte("notifies")
|
||||
)
|
||||
|
||||
func (n *Notifies) Get(recv string, fps ...model.Fingerprint) ([]*types.NotifyInfo, error) {
|
||||
var res []*types.NotifyInfo
|
||||
|
||||
err := n.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(bktNotifies)
|
||||
|
||||
for _, fp := range fps {
|
||||
k := make([]byte, 16+len([]byte(recv)))
|
||||
binary.BigEndian.PutUint64(k, uint64(fp))
|
||||
copy(k[16:], []byte(recv))
|
||||
|
||||
v := b.Get(k)
|
||||
if v == nil {
|
||||
res = append(res, nil)
|
||||
continue
|
||||
}
|
||||
|
||||
ni := &types.NotifyInfo{
|
||||
Alert: fp,
|
||||
Receiver: recv,
|
||||
Resolved: v[0] == 1,
|
||||
}
|
||||
if err := ni.Timestamp.UnmarshalBinary(v[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
res = append(res, ni)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Set several notifies at once. All or none must succeed.
|
||||
func (n *Notifies) Set(ns ...*types.NotifyInfo) error {
|
||||
err := n.db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(bktNotifies)
|
||||
|
||||
for _, n := range ns {
|
||||
k := make([]byte, 16+len([]byte(n.Receiver)))
|
||||
binary.BigEndian.PutUint64(k, uint64(n.Alert))
|
||||
copy(k[16:], []byte(n.Receiver))
|
||||
|
||||
var v []byte
|
||||
if n.Resolved {
|
||||
v = []byte{1}
|
||||
} else {
|
||||
v = []byte{0}
|
||||
}
|
||||
tsb, err := n.Timestamp.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = append(v, tsb...)
|
||||
|
||||
if err := b.Put(k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
107
provider/boltmem/boltmem_test.go
Normal file
107
provider/boltmem/boltmem_test.go
Normal file
@ -0,0 +1,107 @@
|
||||
package boltmem
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"github.com/prometheus/alertmanager/types"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
func init() {
|
||||
pretty.CompareConfig.IncludeUnexported = false
|
||||
}
|
||||
|
||||
func TestNotifiesSet(t *testing.T) {
|
||||
var (
|
||||
t0 = time.Now()
|
||||
// t1 = t0.Add(10 * time.Minute)
|
||||
// t2 = t0.Add(20 * time.Minute)
|
||||
// t3 = t0.Add(30 * time.Minute)
|
||||
)
|
||||
type query struct {
|
||||
recv string
|
||||
fps []model.Fingerprint
|
||||
expected []*types.NotifyInfo
|
||||
}
|
||||
var steps = []struct {
|
||||
insert []*types.NotifyInfo
|
||||
queries []query
|
||||
}{
|
||||
{
|
||||
insert: []*types.NotifyInfo{
|
||||
{
|
||||
Alert: 30000,
|
||||
Receiver: "receiver",
|
||||
Resolved: false,
|
||||
Timestamp: t0,
|
||||
}, {
|
||||
Alert: 20000,
|
||||
Receiver: "receiver",
|
||||
Resolved: true,
|
||||
Timestamp: t0,
|
||||
}, {
|
||||
Alert: 10000,
|
||||
Receiver: "receiver",
|
||||
Resolved: true,
|
||||
Timestamp: t0,
|
||||
},
|
||||
},
|
||||
queries: []query{
|
||||
{
|
||||
recv: "receiver",
|
||||
fps: []model.Fingerprint{30000, 30001, 20000, 10000},
|
||||
expected: []*types.NotifyInfo{
|
||||
{
|
||||
Alert: 30000,
|
||||
Receiver: "receiver",
|
||||
Resolved: false,
|
||||
Timestamp: t0,
|
||||
},
|
||||
nil, {
|
||||
Alert: 20000,
|
||||
Receiver: "receiver",
|
||||
Resolved: true,
|
||||
Timestamp: t0,
|
||||
}, {
|
||||
Alert: 10000,
|
||||
Receiver: "receiver",
|
||||
Resolved: true,
|
||||
Timestamp: t0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "notify_set_set")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
n, err := NewNotifies(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, step := range steps {
|
||||
if err := n.Set(step.insert...); err != nil {
|
||||
t.Fatalf("Insert failed: %s", err)
|
||||
}
|
||||
|
||||
for _, q := range step.queries {
|
||||
res, err := n.Get(q.recv, q.fps...)
|
||||
if err != nil {
|
||||
t.Fatalf("Query failed: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(res, q.expected) {
|
||||
t.Errorf("Unexpected query result")
|
||||
t.Fatalf(pretty.Compare(res, q.expected))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user