From 117c8ba8f1476f8546c4a6a1ac972ee0f29b6668 Mon Sep 17 00:00:00 2001 From: ricoberger Date: Thu, 4 Jun 2020 09:09:12 +0200 Subject: [PATCH 1/6] Propagate labels to Opsgenie details Signed-off-by: ricoberger --- config/notifiers.go | 22 ++++++++++++---------- notify/opsgenie/opsgenie.go | 24 +++++++++++++++++++++--- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/config/notifiers.go b/config/notifiers.go index 82829ded36..f88964362d 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -456,16 +456,18 @@ type OpsGenieConfig struct { HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` - APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` - APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` - Message string `yaml:"message,omitempty" json:"message,omitempty"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - Source string `yaml:"source,omitempty" json:"source,omitempty"` - Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` - Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` - Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` - Note string `yaml:"note,omitempty" json:"note,omitempty"` - Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` + APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` + APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` + Message string `yaml:"message,omitempty" json:"message,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Source string `yaml:"source,omitempty" json:"source,omitempty"` + AllLabelsAsDetails bool `yaml:"all_labels_as_details,omitempty" json:"all_labels_as_details,omitempty"` + LabelsAsDetails []string `yaml:"labels_as_details,omitempty" json:"labels_as_details,omitempty"` + Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` + Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` + Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` + Note string `yaml:"note,omitempty" json:"note,omitempty"` + Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` } const opsgenieValidTypesRe = `^(team|user|escalation|schedule)$` diff --git a/notify/opsgenie/opsgenie.go b/notify/opsgenie/opsgenie.go index 078fcc62c8..dcb5d1e9a5 100644 --- a/notify/opsgenie/opsgenie.go +++ b/notify/opsgenie/opsgenie.go @@ -120,9 +120,27 @@ func (n *Notifier) createRequest(ctx context.Context, as ...*types.Alert) (*http tmpl := notify.TmplText(n.tmpl, data, &err) - details := make(map[string]string, len(n.conf.Details)) - for k, v := range n.conf.Details { - details[k] = tmpl(v) + var details map[string]string + + if n.conf.AllLabelsAsDetails { + details = make(map[string]string, len(data.CommonLabels)) + for k, v := range data.CommonLabels { + details[k] = v + } + } else if len(n.conf.LabelsAsDetails) > 0 { + details = make(map[string]string, len(n.conf.LabelsAsDetails)) + for _, k := range n.conf.LabelsAsDetails { + if v, ok := data.CommonLabels[k]; ok { + details[k] = v + } else { + details[k] = "N/A" + } + } + } else { + details = make(map[string]string, len(n.conf.Details)) + for k, v := range n.conf.Details { + details[k] = tmpl(v) + } } var ( From dcccf542f1e24899113ff7ee16d08705c321d96e Mon Sep 17 00:00:00 2001 From: ricoberger Date: Thu, 4 Jun 2020 15:47:18 +0200 Subject: [PATCH 2/6] Adjust Opsgenie config for labels propagation Signed-off-by: ricoberger --- config/notifiers.go | 40 ++++++++++++++++++++++++++----------- notify/opsgenie/opsgenie.go | 16 ++++++++------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/config/notifiers.go b/config/notifiers.go index f88964362d..fc6356c0dc 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -22,6 +22,7 @@ import ( "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" + "github.com/prometheus/common/model" ) var ( @@ -456,18 +457,18 @@ type OpsGenieConfig struct { HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` - APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` - APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` - Message string `yaml:"message,omitempty" json:"message,omitempty"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - Source string `yaml:"source,omitempty" json:"source,omitempty"` - AllLabelsAsDetails bool `yaml:"all_labels_as_details,omitempty" json:"all_labels_as_details,omitempty"` - LabelsAsDetails []string `yaml:"labels_as_details,omitempty" json:"labels_as_details,omitempty"` - Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` - Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` - Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` - Note string `yaml:"note,omitempty" json:"note,omitempty"` - Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` + APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` + APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` + Message string `yaml:"message,omitempty" json:"message,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Source string `yaml:"source,omitempty" json:"source,omitempty"` + Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` + DetailsLabels []string `yaml:"details_labels,omitempty" json:"details_labels,omitempty"` + DetailsLabelsAll bool `yaml:"-" json:"-"` + Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` + Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` + Note string `yaml:"note,omitempty" json:"note,omitempty"` + Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` } const opsgenieValidTypesRe = `^(team|user|escalation|schedule)$` @@ -493,6 +494,21 @@ func (c *OpsGenieConfig) UnmarshalYAML(unmarshal func(interface{}) error) error } } + if c.DetailsLabels != nil && c.Details != nil { + return errors.Errorf("OpsGenieConfig can only contain details or details_labels, but both fields were provided") + } + + for _, l := range c.DetailsLabels { + if l == "..." { + c.DetailsLabelsAll = true + } else { + labelName := model.LabelName(l) + if !labelName.IsValid() { + return errors.Errorf("invalid label name %q in details_labels list", l) + } + } + } + return nil } diff --git a/notify/opsgenie/opsgenie.go b/notify/opsgenie/opsgenie.go index dcb5d1e9a5..6584bf9689 100644 --- a/notify/opsgenie/opsgenie.go +++ b/notify/opsgenie/opsgenie.go @@ -122,18 +122,20 @@ func (n *Notifier) createRequest(ctx context.Context, as ...*types.Alert) (*http var details map[string]string - if n.conf.AllLabelsAsDetails { + if n.conf.DetailsLabelsAll { details = make(map[string]string, len(data.CommonLabels)) for k, v := range data.CommonLabels { details[k] = v } - } else if len(n.conf.LabelsAsDetails) > 0 { - details = make(map[string]string, len(n.conf.LabelsAsDetails)) - for _, k := range n.conf.LabelsAsDetails { - if v, ok := data.CommonLabels[k]; ok { - details[k] = v + } else if len(n.conf.DetailsLabels) > 0 { + details = make(map[string]string, len(n.conf.DetailsLabels)) + for _, k := range n.conf.DetailsLabels { + label := string(k) + + if v, ok := data.CommonLabels[label]; ok { + details[label] = v } else { - details[k] = "N/A" + details[label] = "N/A" } } } else { From 8248c50365f5e9cc0320b1bdbc3157d60fe2b199 Mon Sep 17 00:00:00 2001 From: ricoberger Date: Fri, 5 Jun 2020 08:07:58 +0200 Subject: [PATCH 3/6] Provide option to use common labels for OpsGenie details Signed-off-by: ricoberger --- config/notifiers.go | 39 +++++++++++++------------------------ notify/opsgenie/opsgenie.go | 13 +------------ 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/config/notifiers.go b/config/notifiers.go index fc6356c0dc..00824211a6 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -22,7 +22,6 @@ import ( "github.com/pkg/errors" commoncfg "github.com/prometheus/common/config" - "github.com/prometheus/common/model" ) var ( @@ -457,18 +456,17 @@ type OpsGenieConfig struct { HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` - APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` - APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` - Message string `yaml:"message,omitempty" json:"message,omitempty"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - Source string `yaml:"source,omitempty" json:"source,omitempty"` - Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` - DetailsLabels []string `yaml:"details_labels,omitempty" json:"details_labels,omitempty"` - DetailsLabelsAll bool `yaml:"-" json:"-"` - Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` - Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` - Note string `yaml:"note,omitempty" json:"note,omitempty"` - Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` + APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` + APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` + Message string `yaml:"message,omitempty" json:"message,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Source string `yaml:"source,omitempty" json:"source,omitempty"` + Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` + DetailsUseCommonLabels bool `yaml:"details_use_common_labels,omitempty" json:"details_use_common_labels,omitempty"` + Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` + Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` + Note string `yaml:"note,omitempty" json:"note,omitempty"` + Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` } const opsgenieValidTypesRe = `^(team|user|escalation|schedule)$` @@ -494,19 +492,8 @@ func (c *OpsGenieConfig) UnmarshalYAML(unmarshal func(interface{}) error) error } } - if c.DetailsLabels != nil && c.Details != nil { - return errors.Errorf("OpsGenieConfig can only contain details or details_labels, but both fields were provided") - } - - for _, l := range c.DetailsLabels { - if l == "..." { - c.DetailsLabelsAll = true - } else { - labelName := model.LabelName(l) - if !labelName.IsValid() { - return errors.Errorf("invalid label name %q in details_labels list", l) - } - } + if c.Details != nil && c.DetailsUseCommonLabels == true { + return errors.Errorf("OpsGenieConfig can only contain details or details_use_common_labels, but both fields were provided") } return nil diff --git a/notify/opsgenie/opsgenie.go b/notify/opsgenie/opsgenie.go index 6584bf9689..37054fa21e 100644 --- a/notify/opsgenie/opsgenie.go +++ b/notify/opsgenie/opsgenie.go @@ -122,22 +122,11 @@ func (n *Notifier) createRequest(ctx context.Context, as ...*types.Alert) (*http var details map[string]string - if n.conf.DetailsLabelsAll { + if n.conf.DetailsUseCommonLabels { details = make(map[string]string, len(data.CommonLabels)) for k, v := range data.CommonLabels { details[k] = v } - } else if len(n.conf.DetailsLabels) > 0 { - details = make(map[string]string, len(n.conf.DetailsLabels)) - for _, k := range n.conf.DetailsLabels { - label := string(k) - - if v, ok := data.CommonLabels[label]; ok { - details[label] = v - } else { - details[label] = "N/A" - } - } } else { details = make(map[string]string, len(n.conf.Details)) for k, v := range n.conf.Details { From 9a87f5c113d6cbeb0faff3cda1b742357d088b83 Mon Sep 17 00:00:00 2001 From: ricoberger Date: Tue, 9 Jun 2020 07:38:38 +0200 Subject: [PATCH 4/6] Populate details from common labels and details Signed-off-by: ricoberger --- config/notifiers.go | 26 +++++++++++--------------- notify/opsgenie/opsgenie.go | 14 ++++++-------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/config/notifiers.go b/config/notifiers.go index 00824211a6..d5274e2b0a 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -456,17 +456,17 @@ type OpsGenieConfig struct { HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` - APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` - APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` - Message string `yaml:"message,omitempty" json:"message,omitempty"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - Source string `yaml:"source,omitempty" json:"source,omitempty"` - Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` - DetailsUseCommonLabels bool `yaml:"details_use_common_labels,omitempty" json:"details_use_common_labels,omitempty"` - Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` - Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` - Note string `yaml:"note,omitempty" json:"note,omitempty"` - Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` + APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` + APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` + Message string `yaml:"message,omitempty" json:"message,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Source string `yaml:"source,omitempty" json:"source,omitempty"` + Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` + CommonLabelsAsDetails bool `yaml:"common_labels_as_details,omitempty" json:"common_labels_as_details,omitempty"` + Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` + Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` + Note string `yaml:"note,omitempty" json:"note,omitempty"` + Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` } const opsgenieValidTypesRe = `^(team|user|escalation|schedule)$` @@ -492,10 +492,6 @@ func (c *OpsGenieConfig) UnmarshalYAML(unmarshal func(interface{}) error) error } } - if c.Details != nil && c.DetailsUseCommonLabels == true { - return errors.Errorf("OpsGenieConfig can only contain details or details_use_common_labels, but both fields were provided") - } - return nil } diff --git a/notify/opsgenie/opsgenie.go b/notify/opsgenie/opsgenie.go index 37054fa21e..515d2fc0f6 100644 --- a/notify/opsgenie/opsgenie.go +++ b/notify/opsgenie/opsgenie.go @@ -120,18 +120,16 @@ func (n *Notifier) createRequest(ctx context.Context, as ...*types.Alert) (*http tmpl := notify.TmplText(n.tmpl, data, &err) - var details map[string]string + details := make(map[string]string) - if n.conf.DetailsUseCommonLabels { - details = make(map[string]string, len(data.CommonLabels)) + if n.conf.CommonLabelsAsDetails { for k, v := range data.CommonLabels { details[k] = v } - } else { - details = make(map[string]string, len(n.conf.Details)) - for k, v := range n.conf.Details { - details[k] = tmpl(v) - } + } + + for k, v := range n.conf.Details { + details[k] = tmpl(v) } var ( From 3cff6cb5b530d58b922f2caccf448a539921cad7 Mon Sep 17 00:00:00 2001 From: ricoberger Date: Tue, 9 Jun 2020 09:00:52 +0200 Subject: [PATCH 5/6] Add tests for Opsgenie details Signed-off-by: ricoberger --- notify/opsgenie/opsgenie_test.go | 259 ++++++++++++++++++++++--------- 1 file changed, 188 insertions(+), 71 deletions(-) diff --git a/notify/opsgenie/opsgenie_test.go b/notify/opsgenie/opsgenie_test.go index 7fb3489e43..f3bc4724c5 100644 --- a/notify/opsgenie/opsgenie_test.go +++ b/notify/opsgenie/opsgenie_test.go @@ -76,85 +76,202 @@ func TestOpsGenie(t *testing.T) { } logger := log.NewNopLogger() tmpl := test.CreateTmpl(t) - conf := &config.OpsGenieConfig{ - NotifierConfig: config.NotifierConfig{ - VSendResolved: true, + + for _, tc := range []struct { + title string + cfg *config.OpsGenieConfig + + expectedEmptyAlertBody string + expectedBody string + }{ + { + title: "config without details", + cfg: &config.OpsGenieConfig{ + NotifierConfig: config.NotifierConfig{ + VSendResolved: true, + }, + Message: `{{ .CommonLabels.Message }}`, + Description: `{{ .CommonLabels.Description }}`, + Source: `{{ .CommonLabels.Source }}`, + Responders: []config.OpsGenieConfigResponder{ + { + Name: `{{ .CommonLabels.ResponderName1 }}`, + Type: `{{ .CommonLabels.ResponderType1 }}`, + }, + { + Name: `{{ .CommonLabels.ResponderName2 }}`, + Type: `{{ .CommonLabels.ResponderType2 }}`, + }, + }, + Tags: `{{ .CommonLabels.Tags }}`, + Note: `{{ .CommonLabels.Note }}`, + Priority: `{{ .CommonLabels.Priority }}`, + APIKey: `{{ .ExternalURL }}`, + APIURL: &config.URL{URL: u}, + HTTPConfig: &commoncfg.HTTPClientConfig{}, + }, + expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{},"source":""} +`, + expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} +`, }, - Message: `{{ .CommonLabels.Message }}`, - Description: `{{ .CommonLabels.Description }}`, - Source: `{{ .CommonLabels.Source }}`, - Responders: []config.OpsGenieConfigResponder{ - { - Name: `{{ .CommonLabels.ResponderName1 }}`, - Type: `{{ .CommonLabels.ResponderType1 }}`, + { + title: "config with details", + cfg: &config.OpsGenieConfig{ + NotifierConfig: config.NotifierConfig{ + VSendResolved: true, + }, + Message: `{{ .CommonLabels.Message }}`, + Description: `{{ .CommonLabels.Description }}`, + Source: `{{ .CommonLabels.Source }}`, + Details: map[string]string{ + "Description": `{{ .CommonLabels.Description }}`, + }, + Responders: []config.OpsGenieConfigResponder{ + { + Name: `{{ .CommonLabels.ResponderName1 }}`, + Type: `{{ .CommonLabels.ResponderType1 }}`, + }, + { + Name: `{{ .CommonLabels.ResponderName2 }}`, + Type: `{{ .CommonLabels.ResponderType2 }}`, + }, + }, + Tags: `{{ .CommonLabels.Tags }}`, + Note: `{{ .CommonLabels.Note }}`, + Priority: `{{ .CommonLabels.Priority }}`, + APIKey: `{{ .ExternalURL }}`, + APIURL: &config.URL{URL: u}, + HTTPConfig: &commoncfg.HTTPClientConfig{}, }, - { - Name: `{{ .CommonLabels.ResponderName2 }}`, - Type: `{{ .CommonLabels.ResponderType2 }}`, + expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{"Description":""},"source":""} +`, + expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"description"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} +`, + }, + { + title: "config with common labels as details", + cfg: &config.OpsGenieConfig{ + NotifierConfig: config.NotifierConfig{ + VSendResolved: true, + }, + Message: `{{ .CommonLabels.Message }}`, + Description: `{{ .CommonLabels.Description }}`, + Source: `{{ .CommonLabels.Source }}`, + CommonLabelsAsDetails: true, + Responders: []config.OpsGenieConfigResponder{ + { + Name: `{{ .CommonLabels.ResponderName1 }}`, + Type: `{{ .CommonLabels.ResponderType1 }}`, + }, + { + Name: `{{ .CommonLabels.ResponderName2 }}`, + Type: `{{ .CommonLabels.ResponderType2 }}`, + }, + }, + Tags: `{{ .CommonLabels.Tags }}`, + Note: `{{ .CommonLabels.Note }}`, + Priority: `{{ .CommonLabels.Priority }}`, + APIKey: `{{ .ExternalURL }}`, + APIURL: &config.URL{URL: u}, + HTTPConfig: &commoncfg.HTTPClientConfig{}, }, + expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{},"source":""} +`, + expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"description","Message":"message","Note":"this is a note","Priority":"P1","ResponderName1":"TeamA","ResponderName2":"EscalationA","ResponderType1":"team","ResponderType2":"escalation","Source":"http://prometheus","Tags":"tag1,tag2"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} +`, }, - Tags: `{{ .CommonLabels.Tags }}`, - Note: `{{ .CommonLabels.Note }}`, - Priority: `{{ .CommonLabels.Priority }}`, - APIKey: `{{ .ExternalURL }}`, - APIURL: &config.URL{URL: u}, - HTTPConfig: &commoncfg.HTTPClientConfig{}, - } - notifier, err := New(conf, tmpl, logger) - require.NoError(t, err) + { + title: "config with details and common labels as details", + cfg: &config.OpsGenieConfig{ + NotifierConfig: config.NotifierConfig{ + VSendResolved: true, + }, + Message: `{{ .CommonLabels.Message }}`, + Description: `{{ .CommonLabels.Description }}`, + Source: `{{ .CommonLabels.Source }}`, + Details: map[string]string{ + "Description": `Adjusted {{ .CommonLabels.Description }}`, + }, + CommonLabelsAsDetails: true, + Responders: []config.OpsGenieConfigResponder{ + { + Name: `{{ .CommonLabels.ResponderName1 }}`, + Type: `{{ .CommonLabels.ResponderType1 }}`, + }, + { + Name: `{{ .CommonLabels.ResponderName2 }}`, + Type: `{{ .CommonLabels.ResponderType2 }}`, + }, + }, + Tags: `{{ .CommonLabels.Tags }}`, + Note: `{{ .CommonLabels.Note }}`, + Priority: `{{ .CommonLabels.Priority }}`, + APIKey: `{{ .ExternalURL }}`, + APIURL: &config.URL{URL: u}, + HTTPConfig: &commoncfg.HTTPClientConfig{}, + }, + expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{"Description":"Adjusted "},"source":""} +`, + expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"Adjusted description","Message":"message","Note":"this is a note","Priority":"P1","ResponderName1":"TeamA","ResponderName2":"EscalationA","ResponderType1":"team","ResponderType2":"escalation","Source":"http://prometheus","Tags":"tag1,tag2"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} +`, + }, + } { + t.Run(tc.title, func(t *testing.T) { + notifier, err := New(tc.cfg, tmpl, logger) + require.NoError(t, err) - ctx := context.Background() - ctx = notify.WithGroupKey(ctx, "1") + ctx := context.Background() + ctx = notify.WithGroupKey(ctx, "1") - expectedURL, _ := url.Parse("https://opsgenie/apiv2/alerts") + expectedURL, _ := url.Parse("https://opsgenie/apiv2/alerts") - // Empty alert. - alert1 := &types.Alert{ - Alert: model.Alert{ - StartsAt: time.Now(), - EndsAt: time.Now().Add(time.Hour), - }, - } - expectedBody := `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{},"source":""} -` - req, retry, err := notifier.createRequest(ctx, alert1) - require.NoError(t, err) - require.Equal(t, true, retry) - require.Equal(t, expectedURL, req.URL) - require.Equal(t, "GenieKey http://am", req.Header.Get("Authorization")) - require.Equal(t, expectedBody, readBody(t, req)) - - // Fully defined alert. - alert2 := &types.Alert{ - Alert: model.Alert{ - Labels: model.LabelSet{ - "Message": "message", - "Description": "description", - "Source": "http://prometheus", - "ResponderName1": "TeamA", - "ResponderType1": "team", - "ResponderName2": "EscalationA", - "ResponderType2": "escalation", - "Tags": "tag1,tag2", - "Note": "this is a note", - "Priority": "P1", - }, - StartsAt: time.Now(), - EndsAt: time.Now().Add(time.Hour), - }, + // Empty alert. + alert1 := &types.Alert{ + Alert: model.Alert{ + StartsAt: time.Now(), + EndsAt: time.Now().Add(time.Hour), + }, + } + + req, retry, err := notifier.createRequest(ctx, alert1) + require.NoError(t, err) + require.Equal(t, true, retry) + require.Equal(t, expectedURL, req.URL) + require.Equal(t, "GenieKey http://am", req.Header.Get("Authorization")) + require.Equal(t, tc.expectedEmptyAlertBody, readBody(t, req)) + + // Fully defined alert. + alert2 := &types.Alert{ + Alert: model.Alert{ + Labels: model.LabelSet{ + "Message": "message", + "Description": "description", + "Source": "http://prometheus", + "ResponderName1": "TeamA", + "ResponderType1": "team", + "ResponderName2": "EscalationA", + "ResponderType2": "escalation", + "Tags": "tag1,tag2", + "Note": "this is a note", + "Priority": "P1", + }, + StartsAt: time.Now(), + EndsAt: time.Now().Add(time.Hour), + }, + } + req, retry, err = notifier.createRequest(ctx, alert2) + require.NoError(t, err) + require.Equal(t, true, retry) + require.Equal(t, tc.expectedBody, readBody(t, req)) + + // Broken API Key Template. + tc.cfg.APIKey = "{{ kaput " + _, _, err = notifier.createRequest(ctx, alert2) + require.Error(t, err) + require.Equal(t, err.Error(), "templating error: template: :1: function \"kaput\" not defined") + }) } - expectedBody = `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} -` - req, retry, err = notifier.createRequest(ctx, alert2) - require.NoError(t, err) - require.Equal(t, true, retry) - require.Equal(t, expectedBody, readBody(t, req)) - - // Broken API Key Template. - conf.APIKey = "{{ kaput " - _, _, err = notifier.createRequest(ctx, alert2) - require.Error(t, err) - require.Equal(t, err.Error(), "templating error: template: :1: function \"kaput\" not defined") } func readBody(t *testing.T, r *http.Request) string { From 4b59db0adcb14f3e6b0b75efdbab3ffb7be737f6 Mon Sep 17 00:00:00 2001 From: ricoberger Date: Tue, 9 Jun 2020 13:51:46 +0200 Subject: [PATCH 6/6] Always pass all labels to Opsgenie Signed-off-by: ricoberger --- config/notifiers.go | 21 +++++---- notify/opsgenie/opsgenie.go | 6 +-- notify/opsgenie/opsgenie_test.go | 75 ++------------------------------ 3 files changed, 16 insertions(+), 86 deletions(-) diff --git a/config/notifiers.go b/config/notifiers.go index d5274e2b0a..82829ded36 100644 --- a/config/notifiers.go +++ b/config/notifiers.go @@ -456,17 +456,16 @@ type OpsGenieConfig struct { HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` - APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` - APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` - Message string `yaml:"message,omitempty" json:"message,omitempty"` - Description string `yaml:"description,omitempty" json:"description,omitempty"` - Source string `yaml:"source,omitempty" json:"source,omitempty"` - Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` - CommonLabelsAsDetails bool `yaml:"common_labels_as_details,omitempty" json:"common_labels_as_details,omitempty"` - Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` - Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` - Note string `yaml:"note,omitempty" json:"note,omitempty"` - Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` + APIKey Secret `yaml:"api_key,omitempty" json:"api_key,omitempty"` + APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"` + Message string `yaml:"message,omitempty" json:"message,omitempty"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + Source string `yaml:"source,omitempty" json:"source,omitempty"` + Details map[string]string `yaml:"details,omitempty" json:"details,omitempty"` + Responders []OpsGenieConfigResponder `yaml:"responders,omitempty" json:"responders,omitempty"` + Tags string `yaml:"tags,omitempty" json:"tags,omitempty"` + Note string `yaml:"note,omitempty" json:"note,omitempty"` + Priority string `yaml:"priority,omitempty" json:"priority,omitempty"` } const opsgenieValidTypesRe = `^(team|user|escalation|schedule)$` diff --git a/notify/opsgenie/opsgenie.go b/notify/opsgenie/opsgenie.go index 515d2fc0f6..7e3ba5c229 100644 --- a/notify/opsgenie/opsgenie.go +++ b/notify/opsgenie/opsgenie.go @@ -122,10 +122,8 @@ func (n *Notifier) createRequest(ctx context.Context, as ...*types.Alert) (*http details := make(map[string]string) - if n.conf.CommonLabelsAsDetails { - for k, v := range data.CommonLabels { - details[k] = v - } + for k, v := range data.CommonLabels { + details[k] = v } for k, v := range n.conf.Details { diff --git a/notify/opsgenie/opsgenie_test.go b/notify/opsgenie/opsgenie_test.go index f3bc4724c5..33246426c4 100644 --- a/notify/opsgenie/opsgenie_test.go +++ b/notify/opsgenie/opsgenie_test.go @@ -111,78 +111,12 @@ func TestOpsGenie(t *testing.T) { HTTPConfig: &commoncfg.HTTPClientConfig{}, }, expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{},"source":""} -`, - expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} -`, - }, - { - title: "config with details", - cfg: &config.OpsGenieConfig{ - NotifierConfig: config.NotifierConfig{ - VSendResolved: true, - }, - Message: `{{ .CommonLabels.Message }}`, - Description: `{{ .CommonLabels.Description }}`, - Source: `{{ .CommonLabels.Source }}`, - Details: map[string]string{ - "Description": `{{ .CommonLabels.Description }}`, - }, - Responders: []config.OpsGenieConfigResponder{ - { - Name: `{{ .CommonLabels.ResponderName1 }}`, - Type: `{{ .CommonLabels.ResponderType1 }}`, - }, - { - Name: `{{ .CommonLabels.ResponderName2 }}`, - Type: `{{ .CommonLabels.ResponderType2 }}`, - }, - }, - Tags: `{{ .CommonLabels.Tags }}`, - Note: `{{ .CommonLabels.Note }}`, - Priority: `{{ .CommonLabels.Priority }}`, - APIKey: `{{ .ExternalURL }}`, - APIURL: &config.URL{URL: u}, - HTTPConfig: &commoncfg.HTTPClientConfig{}, - }, - expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{"Description":""},"source":""} -`, - expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"description"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} -`, - }, - { - title: "config with common labels as details", - cfg: &config.OpsGenieConfig{ - NotifierConfig: config.NotifierConfig{ - VSendResolved: true, - }, - Message: `{{ .CommonLabels.Message }}`, - Description: `{{ .CommonLabels.Description }}`, - Source: `{{ .CommonLabels.Source }}`, - CommonLabelsAsDetails: true, - Responders: []config.OpsGenieConfigResponder{ - { - Name: `{{ .CommonLabels.ResponderName1 }}`, - Type: `{{ .CommonLabels.ResponderType1 }}`, - }, - { - Name: `{{ .CommonLabels.ResponderName2 }}`, - Type: `{{ .CommonLabels.ResponderType2 }}`, - }, - }, - Tags: `{{ .CommonLabels.Tags }}`, - Note: `{{ .CommonLabels.Note }}`, - Priority: `{{ .CommonLabels.Priority }}`, - APIKey: `{{ .ExternalURL }}`, - APIURL: &config.URL{URL: u}, - HTTPConfig: &commoncfg.HTTPClientConfig{}, - }, - expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{},"source":""} `, expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"description","Message":"message","Note":"this is a note","Priority":"P1","ResponderName1":"TeamA","ResponderName2":"EscalationA","ResponderType1":"team","ResponderType2":"escalation","Source":"http://prometheus","Tags":"tag1,tag2"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} `, }, { - title: "config with details and common labels as details", + title: "config with details", cfg: &config.OpsGenieConfig{ NotifierConfig: config.NotifierConfig{ VSendResolved: true, @@ -191,9 +125,8 @@ func TestOpsGenie(t *testing.T) { Description: `{{ .CommonLabels.Description }}`, Source: `{{ .CommonLabels.Source }}`, Details: map[string]string{ - "Description": `Adjusted {{ .CommonLabels.Description }}`, + "Description": `adjusted {{ .CommonLabels.Description }}`, }, - CommonLabelsAsDetails: true, Responders: []config.OpsGenieConfigResponder{ { Name: `{{ .CommonLabels.ResponderName1 }}`, @@ -211,9 +144,9 @@ func TestOpsGenie(t *testing.T) { APIURL: &config.URL{URL: u}, HTTPConfig: &commoncfg.HTTPClientConfig{}, }, - expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{"Description":"Adjusted "},"source":""} + expectedEmptyAlertBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"","details":{"Description":"adjusted "},"source":""} `, - expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"Adjusted description","Message":"message","Note":"this is a note","Priority":"P1","ResponderName1":"TeamA","ResponderName2":"EscalationA","ResponderType1":"team","ResponderType2":"escalation","Source":"http://prometheus","Tags":"tag1,tag2"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} + expectedBody: `{"alias":"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b","message":"message","description":"description","details":{"Description":"adjusted description","Message":"message","Note":"this is a note","Priority":"P1","ResponderName1":"TeamA","ResponderName2":"EscalationA","ResponderType1":"team","ResponderType2":"escalation","Source":"http://prometheus","Tags":"tag1,tag2"},"source":"http://prometheus","responders":[{"name":"TeamA","type":"team"},{"name":"EscalationA","type":"escalation"}],"tags":["tag1","tag2"],"note":"this is a note","priority":"P1"} `, }, } {