Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 0.20.0-rc.0 / 2019-11-27
## 0.20.0 / 2019-12-11

* [CHANGE] Check that at least one silence matcher matches a non-empty string. #2081
* [ENHANCEMENT] [pagerduty] Check that PagerDuty keys aren't empty. #2085
Expand All @@ -11,7 +11,6 @@
* [BUGFIX] Don't garbage-collect alerts from the store. #2040
* [BUGFIX] [ui] Disable the grammarly plugin on all textareas. #2061
* [BUGFIX] [config] Forbid nil regexp matchers. #2083
* [BUGFIX] [slack] Retry 429 errors. #2112
* [BUGFIX] [ui] Fix Silences UI when several filters are applied. #2075

Contributors:
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.20.0-rc.0
0.20.0
13 changes: 11 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,18 @@ func TestAPI(t *testing.T) {
client := &fakeAPIClient{T: t, ch: make(chan fakeAPIResponse, 1)}
now := time.Now()

u, err := url.Parse("http://example.com")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
statusData := &ServerStatus{
ConfigYAML: "{}",
ConfigJSON: &config.Config{},
ConfigYAML: "{}",
ConfigJSON: &config.Config{
Global: &config.GlobalConfig{
PagerdutyURL: &config.URL{URL: u},
SMTPSmarthost: config.HostPort{Host: "localhost", Port: "25"},
},
},
VersionInfo: map[string]string{"version": "v1"},
Uptime: now,
ClusterStatus: &ClusterStatus{Peers: []PeerStatus{}},
Expand Down
71 changes: 71 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ func (u URL) MarshalJSON() ([]byte, error) {
return nil, nil
}

// UnmarshalJSON implements the json.Marshaler interface for URL.
func (u *URL) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
urlp, err := parseURL(s)
if err != nil {
return err
}
u.URL = urlp.URL
return nil
}

// SecretURL is a URL that must not be revealed on marshaling.
type SecretURL URL

Expand Down Expand Up @@ -137,6 +151,18 @@ func (s SecretURL) MarshalJSON() ([]byte, error) {
return json.Marshal(secretToken)
}

// UnmarshalJSON implements the json.Marshaler interface for SecretURL.
func (s *SecretURL) UnmarshalJSON(data []byte) error {
// In order to deserialize a previously serialized configuration (eg from
// the Alertmanager API with amtool), `<secret>` needs to be treated
// specially, as it isn't a valid URL.
if string(data) == secretToken || string(data) == secretTokenJSON {
s.URL = &url.URL{}
return nil
}
return json.Unmarshal(data, (*URL)(s))
}

// Load parses the YAML input s into a Config.
func Load(s string) (*Config, error) {
cfg := &Config{}
Expand Down Expand Up @@ -490,6 +516,28 @@ func (hp *HostPort) UnmarshalYAML(unmarshal func(interface{}) error) error {
return nil
}

// UnmarshalJSON implements the json.Unmarshaler interface for HostPort.
func (hp *HostPort) UnmarshalJSON(data []byte) error {
var (
s string
err error
)
if err = json.Unmarshal(data, &s); err != nil {
return err
}
if s == "" {
return nil
}
hp.Host, hp.Port, err = net.SplitHostPort(s)
if err != nil {
return err
}
if hp.Port == "" {
return errors.Errorf("address %q: port cannot be empty", s)
}
return nil
}

// MarshalYAML implements the yaml.Marshaler interface for HostPort.
func (hp HostPort) MarshalYAML() (interface{}, error) {
return hp.String(), nil
Expand Down Expand Up @@ -729,3 +777,26 @@ func (re Regexp) MarshalYAML() (interface{}, error) {
}
return nil, nil
}

// UnmarshalJSON implements the json.Marshaler interface for Regexp
func (re *Regexp) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
regex, err := regexp.Compile("^(?:" + s + ")$")
if err != nil {
return err
}
re.Regexp = regex
re.original = s
return nil
}

// MarshalJSON implements the json.Marshaler interface for Regexp.
func (re Regexp) MarshalJSON() ([]byte, error) {
if re.original != "" {
return json.Marshal(re.original)
}
return nil, nil
}
60 changes: 54 additions & 6 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,13 +367,27 @@ func TestMarshalSecretURL(t *testing.T) {
}
u := &SecretURL{urlp}

c, err := yaml.Marshal(u)
c, err := json.Marshal(u)
if err != nil {
t.Fatal(err)
}
require.Equal(t, "<secret>\n", string(c), "SecretURL not properly elided in YAML.")
// u003c -> "<"
// u003e -> ">"
require.Equal(t, "\"\\u003csecret\\u003e\"", string(c), "SecretURL not properly elided in JSON.")
// Check that the marshaled data can be unmarshaled again.
out := &SecretURL{}
err = json.Unmarshal(c, out)
if err != nil {
t.Fatal(err)
}

c, err = yaml.Marshal(u)
if err != nil {
t.Fatal(err)
}
require.Equal(t, "<secret>\n", string(c), "SecretURL not properly elided in YAML.")
// Check that the marshaled data can be unmarshaled again.
out = &SecretURL{}
err = yaml.Unmarshal(c, &out)
if err != nil {
t.Fatal(err)
Expand All @@ -384,7 +398,13 @@ func TestUnmarshalSecretURL(t *testing.T) {
b := []byte(`"http://example.com/se cret"`)
var u SecretURL

err := yaml.Unmarshal(b, &u)
err := json.Unmarshal(b, &u)
if err != nil {
t.Fatal(err)
}
require.Equal(t, "http://example.com/se%20cret", u.String(), "SecretURL not properly unmarshalled in JSON.")

err = yaml.Unmarshal(b, &u)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -416,7 +436,13 @@ func TestUnmarshalURL(t *testing.T) {
b := []byte(`"http://example.com/a b"`)
var u URL

err := yaml.Unmarshal(b, &u)
err := json.Unmarshal(b, &u)
if err != nil {
t.Fatal(err)
}
require.Equal(t, "http://example.com/a%20b", u.String(), "URL not properly unmarshalled in JSON.")

err = yaml.Unmarshal(b, &u)
if err != nil {
t.Fatal(err)
}
Expand All @@ -431,7 +457,12 @@ func TestUnmarshalInvalidURL(t *testing.T) {
} {
var u URL

err := yaml.Unmarshal(b, &u)
err := json.Unmarshal(b, &u)
if err == nil {
t.Errorf("Expected an error unmarshalling %q from JSON", string(b))
}

err = yaml.Unmarshal(b, &u)
if err == nil {
t.Errorf("Expected an error unmarshalling %q from YAML", string(b))
}
Expand All @@ -443,10 +474,27 @@ func TestUnmarshalRelativeURL(t *testing.T) {
b := []byte(`"/home"`)
var u URL

err := yaml.Unmarshal(b, &u)
err := json.Unmarshal(b, &u)
if err == nil {
t.Errorf("Expected an error parsing URL")
}

err = yaml.Unmarshal(b, &u)
if err == nil {
t.Errorf("Expected an error parsing URL")
}
}

func TestJSONUnmarshal(t *testing.T) {
c, err := LoadFile("testdata/conf.good.yml")
if err != nil {
t.Errorf("Error parsing %s: %s", "testdata/conf.good.yml", err)
}

_, err = json.Marshal(c)
if err != nil {
t.Fatal("JSON Marshaling failed:", err)
}
}

func TestMarshalIdempotency(t *testing.T) {
Expand Down
24 changes: 24 additions & 0 deletions dispatch/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package dispatch

import (
"encoding/json"
"fmt"
"sort"
"strings"
Expand Down Expand Up @@ -181,3 +182,26 @@ func (ro *RouteOpts) String() string {
return fmt.Sprintf("<RouteOpts send_to:%q group_by:%q group_by_all:%t timers:%q|%q>",
ro.Receiver, labels, ro.GroupByAll, ro.GroupWait, ro.GroupInterval)
}

// MarshalJSON returns a JSON representation of the routing options.
func (ro *RouteOpts) MarshalJSON() ([]byte, error) {
v := struct {
Receiver string `json:"receiver"`
GroupBy model.LabelNames `json:"groupBy"`
GroupByAll bool `json:"groupByAll"`
GroupWait time.Duration `json:"groupWait"`
GroupInterval time.Duration `json:"groupInterval"`
RepeatInterval time.Duration `json:"repeatInterval"`
}{
Receiver: ro.Receiver,
GroupByAll: ro.GroupByAll,
GroupWait: ro.GroupWait,
GroupInterval: ro.GroupInterval,
RepeatInterval: ro.RepeatInterval,
}
for ln := range ro.GroupBy {
v.GroupBy = append(v.GroupBy, ln)
}

return json.Marshal(&v)
}
2 changes: 1 addition & 1 deletion notify/slack/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func New(c *config.SlackConfig, t *template.Template, l log.Logger) (*Notifier,
tmpl: t,
logger: l,
client: client,
retrier: &notify.Retrier{RetryCodes: []int{http.StatusTooManyRequests}},
retrier: &notify.Retrier{},
}, nil
}

Expand Down
4 changes: 1 addition & 3 deletions notify/slack/slack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ package slack

import (
"fmt"
"net/http"
"testing"

"github.com/go-kit/kit/log"
Expand All @@ -36,8 +35,7 @@ func TestSlackRetry(t *testing.T) {
)
require.NoError(t, err)

retryCodes := append(test.DefaultRetryCodes(), http.StatusTooManyRequests)
for statusCode, expected := range test.RetryTests(retryCodes) {
for statusCode, expected := range test.RetryTests(test.DefaultRetryCodes()) {
actual, _ := notifier.retrier.Check(statusCode, nil)
require.Equal(t, expected, actual, fmt.Sprintf("error on status %d", statusCode))
}
Expand Down