Sync ui-rewrite with master (#779)

This commit is contained in:
Max Inden 2017-05-10 11:49:02 +02:00 committed by GitHub
parent 6784e300cf
commit d463f1c298
12 changed files with 109 additions and 178 deletions

View File

@ -1,25 +1,36 @@
## v0.6.2 / 2017-05-09
* [BUGFIX] Correctly link to silences from alert again
* [BUGFIX] Correctly hide silenced/show active alerts in UI again
* [BUGFIX] Fix regression of alerts not being displayed until first processing
* [BUGFIX] Fix internal usage of wrong lock for silence markers
* [BUGFIX] Adapt amtool's API parsing to recent API changes
* [BUGFIX] Correctly marshal regexes in config JSON response
* [ENHANCEMENT] Anchor silence regex matchers to be consistent with Prometheus
* [ENHANCEMENT] Error if root route is using `continue` keyword
## v0.6.1 / 2017-04-28
- [BUGFIX] Fix incorrectly serialized hash for notification providers.
- [ENHANCEMENT] Add config hash metric.
- [ENHANCEMENT] Add processing status field to alerts.
* [BUGFIX] Fix incorrectly serialized hash for notification providers.
* [ENHANCEMENT] Add config hash metric.
* [ENHANCEMENT] Add processing status field to alerts.
## v0.6.0 / 2017-04-25
- [BUGFIX] Add `groupKey` to `alerts/groups` endpoint https://github.com/prometheus/alertmanager/pull/576
- [BUGFIX] Only notify on firing alerts https://github.com/prometheus/alertmanager/pull/595
- [BUGFIX] Correctly marshal regex's in config for routing tree https://github.com/prometheus/alertmanager/pull/602
- [BUGFIX] Prevent panic when failing to load config https://github.com/prometheus/alertmanager/pull/607
- [BUGFIX] Prevent panic when alertmanager is started with an empty `-mesh.peer` https://github.com/prometheus/alertmanager/pull/726
- [CHANGE] Add `DELETE` as accepted CORS method https://github.com/prometheus/alertmanager/pull/641
- [CHANGE] Rename VictorOps config variables https://github.com/prometheus/alertmanager/pull/667
- [CHANGE] Switch to using `gogoproto` for protobuf https://github.com/prometheus/alertmanager/pull/715
- [CHANGE] No longer generate releases for openbsd/arm https://github.com/prometheus/alertmanager/pull/732
- [ENHANCEMENT] Add `reReplaceAll` template function https://github.com/prometheus/alertmanager/pull/639
- [ENHANCEMENT] Expose mesh peers on status page https://github.com/prometheus/alertmanager/pull/644
- [ENHANCEMENT] Allow label-based filtering alerts/silences through API https://github.com/prometheus/alertmanager/pull/633
- [ENHANCEMENT] Include notifier type in logs and errors https://github.com/prometheus/alertmanager/pull/702
- [ENHANCEMENT] Add commandline tool for interacting with alertmanager https://github.com/prometheus/alertmanager/pull/636
* [BUGFIX] Add `groupKey` to `alerts/groups` endpoint https://github.com/prometheus/alertmanager/pull/576
* [BUGFIX] Only notify on firing alerts https://github.com/prometheus/alertmanager/pull/595
* [BUGFIX] Correctly marshal regex's in config for routing tree https://github.com/prometheus/alertmanager/pull/602
* [BUGFIX] Prevent panic when failing to load config https://github.com/prometheus/alertmanager/pull/607
* [BUGFIX] Prevent panic when alertmanager is started with an empty `-mesh.peer` https://github.com/prometheus/alertmanager/pull/726
* [CHANGE] Add `DELETE` as accepted CORS method https://github.com/prometheus/alertmanager/pull/641
* [CHANGE] Rename VictorOps config variables https://github.com/prometheus/alertmanager/pull/667
* [CHANGE] Switch to using `gogoproto` for protobuf https://github.com/prometheus/alertmanager/pull/715
* [CHANGE] No longer generate releases for openbsd/arm https://github.com/prometheus/alertmanager/pull/732
* [ENHANCEMENT] Add `reReplaceAll` template function https://github.com/prometheus/alertmanager/pull/639
* [ENHANCEMENT] Expose mesh peers on status page https://github.com/prometheus/alertmanager/pull/644
* [ENHANCEMENT] Allow label-based filtering alerts/silences through API https://github.com/prometheus/alertmanager/pull/633
* [ENHANCEMENT] Include notifier type in logs and errors https://github.com/prometheus/alertmanager/pull/702
* [ENHANCEMENT] Add commandline tool for interacting with alertmanager https://github.com/prometheus/alertmanager/pull/636
## v0.5.1 / 2016-11-24

View File

@ -1 +1 @@
0.6.1
0.6.2

View File

@ -248,9 +248,7 @@ func (api *API) alertGroups(w http.ResponseWriter, req *http.Request) {
type APIAlert struct {
*model.Alert
Status types.AlertState `json:"status"`
InhibitedBy []string `json:"inhibitedBy"`
SilencedBy []string `json:"silencedBy"`
Status types.AlertStatus `json:"status"`
}
func (api *API) listAlerts(w http.ResponseWriter, r *http.Request) {
@ -289,10 +287,8 @@ func (api *API) listAlerts(w http.ResponseWriter, r *http.Request) {
status := api.getAlertStatus(a.Fingerprint())
apiAlert := &APIAlert{
Alert: &a.Alert,
Status: status.Status,
SilencedBy: status.SilencedBy,
InhibitedBy: status.InhibitedBy,
Alert: &a.Alert,
Status: status,
}
res = append(res, apiAlert)

View File

@ -28,7 +28,7 @@ type alertmanagerAlertResponse struct {
type alertGroup struct {
Labels model.LabelSet `json:"labels"`
GroupKey uint64 `json:"groupKey"`
GroupKey string `json:"groupKey"`
Blocks []*alertBlock `json:"blocks"`
}
@ -103,7 +103,7 @@ func fetchAlerts(filter string) ([]*dispatch.APIAlert, error) {
err = json.NewDecoder(res.Body).Decode(&alertResponse)
if err != nil {
return []*dispatch.APIAlert{}, errors.New("Unable to decode json response")
return []*dispatch.APIAlert{}, fmt.Errorf("Unable to decode json response: %s", err)
}
if alertResponse.Status != "success" {
@ -158,7 +158,7 @@ func queryAlerts(cmd *cobra.Command, args []string) error {
if !showSilenced {
// If any silence mutes this alert don't show it
if alert.Status == types.AlertStateSuppressed && len(alert.SilencedBy) > 0 {
if alert.Status.State == types.AlertStateSuppressed && len(alert.Status.SilencedBy) > 0 {
continue
}
}

View File

@ -74,12 +74,10 @@ func fetchConfig() (Config, error) {
}
defer res.Body.Close()
decoder := json.NewDecoder(res.Body)
err = decoder.Decode(&configResponse)
err = json.NewDecoder(res.Body).Decode(&configResponse)
if err != nil {
panic(err)
return Config{}, err
return configResponse.Data, err
}
if configResponse.Status != "success" {

View File

@ -23,6 +23,7 @@ import (
"time"
"encoding/json"
"github.com/prometheus/common/model"
"gopkg.in/yaml.v2"
)
@ -51,6 +52,11 @@ func Load(s string) (*Config, error) {
return nil, errors.New("no route provided in config")
}
// Check if continue in root route.
if cfg.Route.Continue {
return nil, errors.New("cannot have continue in root route")
}
cfg.original = s
return cfg, nil
}
@ -498,7 +504,7 @@ func (re *Regexp) UnmarshalJSON(data []byte) error {
}
// MarshalJSON implements the json.Marshaler interface.
func (re *Regexp) MarshalJSON() ([]byte, error) {
func (re Regexp) MarshalJSON() ([]byte, error) {
if re.Regexp != nil {
return json.Marshal(re.String())
}

View File

@ -37,3 +37,26 @@ route:
t.Errorf("\nexpected:\n%v\ngot:\n%v", expected, err.Error())
}
}
func TestContinueErrorInRouteRoot(t *testing.T) {
in := `
route:
receiver: team-X-mails
continue: true
receivers:
- name: 'team-X-mails'
`
_, err := Load(in)
expected := "cannot have continue in root route"
if err == nil {
t.Fatalf("no error returned, expeceted:\n%q", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%q\ngot:\n%q", expected, err.Error())
}
}

View File

@ -80,10 +80,7 @@ type AlertBlock struct {
// annotated with silencing and inhibition info.
type APIAlert struct {
*model.Alert
Status types.AlertState
InhibitedBy []string `json:"inhibitedBy"`
SilencedBy []string `json:"silencedBy"`
Status types.AlertStatus `json:"status"`
}
// AlertGroup is a list of alert blocks grouped by the same label set.
@ -138,10 +135,8 @@ func (d *Dispatcher) Groups(matchers []*labels.Matcher) AlertOverview {
}
status := d.marker.Status(a.Fingerprint())
aa := &APIAlert{
Alert: a,
Status: status.Status,
SilencedBy: status.SilencedBy,
InhibitedBy: status.InhibitedBy,
Alert: a,
Status: status,
}
if !matchesFilterLabels(aa, matchers) {

View File

@ -169,8 +169,8 @@ func TestAlertsGC(t *testing.T) {
}
s := marker.Status(a.Fingerprint())
if s.Status != types.AlertStateUnprocessed {
t.Errorf("marker %d didn't get GC'd", i)
if s.State != types.AlertStateUnprocessed {
t.Errorf("marker %d didn't get GC'd: %v", i, s)
}
}
}

View File

@ -37,7 +37,7 @@ func (m *Matcher) Init() error {
if !m.IsRegex {
return nil
}
re, err := regexp.Compile(m.Value)
re, err := regexp.Compile("^(?:" + m.Value + ")$")
if err == nil {
m.regex = re
}

View File

@ -14,7 +14,6 @@
package types
import (
"encoding/json"
"fmt"
"sort"
"strings"
@ -24,58 +23,19 @@ import (
"github.com/prometheus/common/model"
)
type AlertState uint8
type AlertState string
const (
AlertStateUnprocessed AlertState = iota
AlertStateActive
AlertStateSuppressed
AlertStateUnprocessed AlertState = "unprocessed"
AlertStateActive = "active"
AlertStateSuppressed = "suppressed"
)
// AlertStatus stores the state and values associated with an Alert.
type AlertStatus struct {
Status AlertState
SilencedBy []string
InhibitedBy []string
}
// Save an allocation when serializing an empty string slice.
var emptyVals = []string{}
// MarshalJSON implements the json.Marshaler interface.
func (a *AlertStatus) MarshalJSON() ([]byte, error) {
silencedBy := a.SilencedBy
if silencedBy == nil {
silencedBy = emptyVals
}
inhibitedBy := a.InhibitedBy
if inhibitedBy == nil {
inhibitedBy = emptyVals
}
return json.Marshal(map[string]interface{}{
"status": a.Status,
"silencedBy": silencedBy,
"inhibitedBy": inhibitedBy,
})
}
// Save an allocation when serializing the unknown response.
const unknown = "unknown"
// MarshalJSON implements the json.Marshaler interface.
func (s AlertState) MarshalJSON() ([]byte, error) {
status, found := statusMap[s]
if !found {
status = unknown
}
return json.Marshal(status)
}
var statusMap = map[AlertState]string{
AlertStateUnprocessed: "unprocessed",
AlertStateActive: "active",
AlertStateSuppressed: "suppressed",
State AlertState `json:"state"`
SilencedBy []string `json:"silencedBy"`
InhibitedBy []string `json:"inhibitedBy"`
}
// Marker helps to mark alerts as silenced and/or inhibited.
@ -109,8 +69,7 @@ type memMarker struct {
// SetSilenced sets the AlertStatus to suppressed and stores the associated silence IDs.
func (m *memMarker) SetSilenced(alert model.Fingerprint, ids ...string) {
m.mtx.RLock()
defer m.mtx.RUnlock()
m.mtx.Lock()
s, found := m.m[alert]
if !found {
@ -122,18 +81,20 @@ func (m *memMarker) SetSilenced(alert model.Fingerprint, ids ...string) {
// fingerprint, it is suppressed. Otherwise, set it to
// AlertStateUnprocessed.
if len(ids) == 0 && len(s.InhibitedBy) == 0 {
m.mtx.Unlock()
m.SetActive(alert)
return
}
s.Status = AlertStateSuppressed
s.State = AlertStateSuppressed
s.SilencedBy = ids
m.mtx.Unlock()
}
// SetInhibited sets the AlertStatus to suppressed and stores the associated alert IDs.
func (m *memMarker) SetInhibited(alert model.Fingerprint, ids ...string) {
m.mtx.RLock()
defer m.mtx.RUnlock()
m.mtx.Lock()
s, found := m.m[alert]
if !found {
@ -145,24 +106,31 @@ func (m *memMarker) SetInhibited(alert model.Fingerprint, ids ...string) {
// fingerprint, it is suppressed. Otherwise, set it to
// AlertStateUnprocessed.
if len(ids) == 0 && len(s.SilencedBy) == 0 {
m.mtx.Unlock()
m.SetActive(alert)
return
}
s.Status = AlertStateSuppressed
s.State = AlertStateSuppressed
s.InhibitedBy = ids
m.mtx.Unlock()
}
func (m *memMarker) SetActive(alert model.Fingerprint) {
m.mtx.RLock()
defer m.mtx.RUnlock()
m.mtx.Lock()
defer m.mtx.Unlock()
s, found := m.m[alert]
if !found {
s = &AlertStatus{}
s = &AlertStatus{
SilencedBy: []string{},
InhibitedBy: []string{},
}
m.m[alert] = s
}
s.Status = AlertStateActive
s.State = AlertStateActive
s.SilencedBy = []string{}
s.InhibitedBy = []string{}
}
@ -174,17 +142,19 @@ func (m *memMarker) Status(alert model.Fingerprint) AlertStatus {
s, found := m.m[alert]
if !found {
s = &AlertStatus{}
m.m[alert] = s
s = &AlertStatus{
State: AlertStateUnprocessed,
SilencedBy: []string{},
InhibitedBy: []string{},
}
}
return *s
}
// Delete deletes the given Fingerprint from the internal cache.
func (m *memMarker) Delete(alert model.Fingerprint) {
m.mtx.RLock()
defer m.mtx.RUnlock()
m.mtx.Lock()
defer m.mtx.Unlock()
delete(m.m, alert)
}
@ -192,13 +162,13 @@ func (m *memMarker) Delete(alert model.Fingerprint) {
// Unprocessed returns whether the alert for the given Fingerprint is in the
// Unprocessed state.
func (m *memMarker) Unprocessed(alert model.Fingerprint) bool {
return m.Status(alert).Status == AlertStateUnprocessed
return m.Status(alert).State == AlertStateUnprocessed
}
// Active returns whether the alert for the given Fingerprint is in the Active
// state.
func (m *memMarker) Active(alert model.Fingerprint) bool {
return m.Status(alert).Status == AlertStateActive
return m.Status(alert).State == AlertStateActive
}
// Inhibited returns whether the alert for the given Fingerprint is in the
@ -206,7 +176,7 @@ func (m *memMarker) Active(alert model.Fingerprint) bool {
func (m *memMarker) Inhibited(alert model.Fingerprint) ([]string, bool) {
s := m.Status(alert)
return s.InhibitedBy,
s.Status == AlertStateSuppressed && len(s.InhibitedBy) > 0
s.State == AlertStateSuppressed && len(s.InhibitedBy) > 0
}
// Silenced returns whether the alert for the given Fingerprint is in the
@ -214,7 +184,7 @@ func (m *memMarker) Inhibited(alert model.Fingerprint) ([]string, bool) {
func (m *memMarker) Silenced(alert model.Fingerprint) ([]string, bool) {
s := m.Status(alert)
return s.SilencedBy,
s.Status == AlertStateSuppressed && len(s.SilencedBy) > 0
s.State == AlertStateSuppressed && len(s.SilencedBy) > 0
}
// MultiError contains multiple errors and implements the error interface. Its

View File

@ -14,7 +14,6 @@
package types
import (
"encoding/json"
"reflect"
"testing"
"time"
@ -62,70 +61,3 @@ func TestAlertMerge(t *testing.T) {
}
}
}
func TestAlertStatusMarshal(t *testing.T) {
type statusTest struct {
alertStatus AlertStatus
status string
inhibitedBy, silencedBy []string
}
tests := []statusTest{
statusTest{
alertStatus: AlertStatus{},
status: "unprocessed",
inhibitedBy: []string{},
silencedBy: []string{},
},
statusTest{
alertStatus: AlertStatus{Status: AlertStateUnprocessed},
status: "unprocessed",
inhibitedBy: []string{},
silencedBy: []string{},
},
statusTest{
alertStatus: AlertStatus{Status: AlertStateActive},
status: "active",
inhibitedBy: []string{},
silencedBy: []string{},
},
statusTest{
alertStatus: AlertStatus{Status: AlertStateSuppressed, SilencedBy: []string{"123456"}},
status: "suppressed",
inhibitedBy: []string{},
silencedBy: []string{"123456"},
},
statusTest{
alertStatus: AlertStatus{Status: AlertStateSuppressed, SilencedBy: []string{"123456"}, InhibitedBy: []string{"123", "456"}},
status: "suppressed",
inhibitedBy: []string{"123", "456"},
silencedBy: []string{"123456"},
},
statusTest{
alertStatus: AlertStatus{Status: AlertStateSuppressed},
status: "suppressed",
silencedBy: []string{},
inhibitedBy: []string{},
},
statusTest{
alertStatus: AlertStatus{Status: 255},
status: "unknown",
silencedBy: []string{},
inhibitedBy: []string{},
},
}
for _, asTest := range tests {
b, err := json.Marshal(&asTest.alertStatus)
if err != nil {
t.Error(err)
}
expectedJSON, _ := json.Marshal(map[string]interface{}{
"status": asTest.status,
"silencedBy": asTest.silencedBy,
"inhibitedBy": asTest.inhibitedBy,
})
if string(b) != string(expectedJSON) {
t.Errorf("%v serialization failed, expected %s, got %s", asTest.alertStatus, expectedJSON, b)
}
}
}