Skip to content

Commit

Permalink
Merge pull request #402 from prometheus/master
Browse files Browse the repository at this point in the history
Merge changes into release-0.2
  • Loading branch information
fabxc authored Jun 23, 2016
2 parents 3bbb296 + 8dc2f97 commit 8da61aa
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 38 deletions.
7 changes: 4 additions & 3 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,15 @@ func (api *API) insertAlerts(w http.ResponseWriter, r *http.Request, alerts ...*
}

func (api *API) addSilence(w http.ResponseWriter, r *http.Request) {
var sil types.Silence
if err := receive(r, &sil); err != nil {
var msil model.Silence
if err := receive(r, &msil); err != nil {
respondError(w, apiError{
typ: errorBadData,
err: err,
}, nil)
return
}
sil := types.NewSilence(&msil)

if sil.CreatedAt.IsZero() {
sil.CreatedAt = time.Now()
Expand All @@ -304,7 +305,7 @@ func (api *API) addSilence(w http.ResponseWriter, r *http.Request) {
return
}

sid, err := api.silences.Set(&sil)
sid, err := api.silences.Set(sil)
if err != nil {
respondError(w, apiError{
typ: errorInternal,
Expand Down
6 changes: 6 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if c.Route == nil {
return fmt.Errorf("No routes provided")
}
if len(c.Route.Receiver) == 0 {
return fmt.Errorf("Root route must specify a default receiver")
}
if len(c.Route.Match) > 0 || len(c.Route.MatchRE) > 0 {
return fmt.Errorf("Root route must not have any matchers")
}
Expand All @@ -240,6 +243,9 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
// checkReceiver returns an error if a node in the routing tree
// references a receiver not in the given map.
func checkReceiver(r *Route, receivers map[string]struct{}) error {
if r.Receiver == "" {
return nil
}
if _, ok := receivers[r.Receiver]; !ok {
return fmt.Errorf("Undefined receiver %q used in route", r.Receiver)
}
Expand Down
39 changes: 39 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2016 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"testing"

"gopkg.in/yaml.v2"
)

func TestDefaultReceiverExists(t *testing.T) {
in := `
route:
group_wait: 30s
`

conf := &Config{}
err := yaml.Unmarshal([]byte(in), conf)

expected := "Root route must specify a default receiver"

if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%v\ngot:\n%v", expected, err.Error())
}
}
2 changes: 1 addition & 1 deletion inhibit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func TestInhibitRuleHasEqual(t *testing.T) {
}

if have := r.hasEqual(c.input); have != c.result {
t.Errorf("Unexpected result %q, expected %q", have, c.result)
t.Errorf("Unexpected result %t, expected %t", have, c.result)
}
if !reflect.DeepEqual(r.scache, c.initial) {
t.Errorf("Cache state unexpectedly changed")
Expand Down
86 changes: 52 additions & 34 deletions provider/boltmem/boltmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ func (a *Alerts) Put(alerts ...*types.Alert) error {
type Silences struct {
db *bolt.DB
mk types.Marker

mtx sync.RWMutex
cache map[uint64]*types.Silence
}

// NewSilences creates a new Silences provider.
Expand All @@ -229,7 +232,15 @@ func NewSilences(path string, mk types.Marker) (*Silences, error) {
_, err := tx.CreateBucketIfNotExists(bktSilences)
return err
})
return &Silences{db: db, mk: mk}, err
if err != nil {
return nil, err
}
s := &Silences{
db: db,
mk: mk,
cache: map[uint64]*types.Silence{},
}
return s, s.initCache()
}

// Close the silences provider.
Expand Down Expand Up @@ -261,7 +272,19 @@ func (s *Silences) Mutes(lset model.LabelSet) bool {

// All returns all existing silences.
func (s *Silences) All() ([]*types.Silence, error) {
var res []*types.Silence
s.mtx.RLock()
defer s.mtx.RUnlock()

res := make([]*types.Silence, 0, len(s.cache))
for _, s := range s.cache {
res = append(res, s)
}
return res, nil
}

func (s *Silences) initCache() error {
s.mtx.Lock()
defer s.mtx.Unlock()

err := s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(bktSilences)
Expand All @@ -272,23 +295,21 @@ func (s *Silences) All() ([]*types.Silence, error) {
if err := json.Unmarshal(v, &ms); err != nil {
return err
}
ms.ID = binary.BigEndian.Uint64(k)

if err := json.Unmarshal(v, &ms); err != nil {
return err
}

res = append(res, types.NewSilence(&ms))
// The ID is duplicated in the value and always equal
// to the stored key.
s.cache[ms.ID] = types.NewSilence(&ms)
}

return nil
})

return res, err
return err
}

// Set a new silence.
func (s *Silences) Set(sil *types.Silence) (uint64, error) {
s.mtx.Lock()
defer s.mtx.Unlock()

var (
uid uint64
err error
Expand All @@ -312,11 +333,18 @@ func (s *Silences) Set(sil *types.Silence) (uint64, error) {
}
return b.Put(k, msb)
})
return uid, err
if err != nil {
return 0, err
}
s.cache[uid] = sil
return uid, nil
}

// Del removes a silence.
func (s *Silences) Del(uid uint64) error {
s.mtx.Lock()
defer s.mtx.Unlock()

err := s.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(bktSilences)

Expand All @@ -325,33 +353,23 @@ func (s *Silences) Del(uid uint64) error {

return b.Delete(k)
})
return err
if err != nil {
return err
}
delete(s.cache, uid)
return nil
}

// Get a silence associated with a fingerprint.
func (s *Silences) Get(uid uint64) (*types.Silence, error) {
var sil *types.Silence

err := s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(bktSilences)

k := make([]byte, 8)
binary.BigEndian.PutUint64(k, uid)

v := b.Get(k)
if v == nil {
return provider.ErrNotFound
}
var ms model.Silence

if err := json.Unmarshal(v, &ms); err != nil {
return err
}
sil = types.NewSilence(&ms)
s.mtx.RLock()
defer s.mtx.RUnlock()

return nil
})
return sil, err
sil, ok := s.cache[uid]
if !ok {
return nil, provider.ErrNotFound
}
return sil, nil
}

// NotificationInfo provides information about pending and successful
Expand Down
58 changes: 58 additions & 0 deletions route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ routes:
group_by: ['foo', 'bar']
group_wait: 2m
receiver: 'notify-BC'
- match:
group_by: 'role'
group_by: ['role']
routes:
- match:
env: 'testing'
receiver: 'notify-testing'
routes:
- match:
wait: 'long'
group_wait: 2m
`

var ctree config.Route
Expand Down Expand Up @@ -167,6 +180,51 @@ routes:
},
},
},
{
input: model.LabelSet{
"group_by": "role",
},
result: []*RouteOpts{
{
Receiver: "notify-def",
GroupBy: lset("role"),
GroupWait: def.GroupWait,
GroupInterval: def.GroupInterval,
RepeatInterval: def.RepeatInterval,
},
},
},
{
input: model.LabelSet{
"env": "testing",
"group_by": "role",
},
result: []*RouteOpts{
{
Receiver: "notify-testing",
GroupBy: lset("role"),
GroupWait: def.GroupWait,
GroupInterval: def.GroupInterval,
RepeatInterval: def.RepeatInterval,
},
},
},
{
input: model.LabelSet{
"env": "testing",
"group_by": "role",
"wait": "long",
},
result: []*RouteOpts{
{
Receiver: "notify-testing",
GroupBy: lset("role"),
GroupWait: 2 * time.Minute,
GroupInterval: def.GroupInterval,
RepeatInterval: def.RepeatInterval,
},
},
},
}

for _, test := range tests {
Expand Down

0 comments on commit 8da61aa

Please sign in to comment.