From 2da7a9c0fda909e9f3b17e53816e66f75644abbc Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Mon, 9 Nov 2020 16:37:31 +0000 Subject: [PATCH 01/32] feat: add support for opsgenie --- docs/services/opsgenie.md | 50 +++++++++ docs/services/opsgenie/1.png | Bin 0 -> 190988 bytes docs/services/opsgenie/2.png | Bin 0 -> 134708 bytes docs/services/overview.md | 5 +- pkg/router/router.go | 2 + pkg/services/opsgenie/opsgenie.go | 72 ++++++++++++ pkg/services/opsgenie/opsgenie_config.go | 37 +++++++ pkg/services/opsgenie/opsgenie_json.go | 75 +++++++++++++ pkg/services/opsgenie/opsgenie_test.go | 134 +++++++++++++++++++++++ 9 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 docs/services/opsgenie.md create mode 100644 docs/services/opsgenie/1.png create mode 100644 docs/services/opsgenie/2.png create mode 100644 pkg/services/opsgenie/opsgenie.go create mode 100644 pkg/services/opsgenie/opsgenie_config.go create mode 100644 pkg/services/opsgenie/opsgenie_json.go create mode 100644 pkg/services/opsgenie/opsgenie_test.go diff --git a/docs/services/opsgenie.md b/docs/services/opsgenie.md new file mode 100644 index 00000000..4229314d --- /dev/null +++ b/docs/services/opsgenie.md @@ -0,0 +1,50 @@ +# OpsGenie + +## URL Format + +## Creating a REST API endpoint in OpsGenie + +1. Open up the Integration List page by clicking on *Settings => Integration List* within the menu +![Screenshot 1](opsgenie/1.png) + +2. Click *API => Add* + +3. Make sure *Create and Update Access* and *Enabled* are checked and click *Save Integration* +![Screenshot 2](opsgenie/2.png) + +4. Copy the *API Key* + +5. Format the service URL + +The host can be either api.opsgenie.com or api.eu.opsgenie.com depending on the location of your instance. See +the [OpsGenie documentation](https://docs.opsgenie.com/docs/alert-api) for details. + +``` +opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889 + └───────────────────────────────────┘ + token +``` + +## Passing parameters via code + +If you want to, you can pass additional parameters to the `send` function. +
+The following example contains all parameters that are currently supported. + +```gotemplate +service.Send("An example alert message", &types.Params{ + "alias": "Life is too short for no alias", + "description": "Every alert needs a description", + "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, + "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, + "actions": "An action", + "tags": "tag1 tag2", + "details": `{"key1": "value1", "key2": "value2"}`, + "entity": "An example entity", + "source": "The source", + "priority": "P1", + "user": "Dracula", + "note": "Here is a note", +}) +``` + diff --git a/docs/services/opsgenie/1.png b/docs/services/opsgenie/1.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4cadf20091c578041f57578d469dc379b032f9 GIT binary patch literal 190988 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

;T`$!zKUM-2J+SPI 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 F{$FQ~M4tcv literal 0 HcmV?d00001 diff --git a/docs/services/opsgenie/2.png b/docs/services/opsgenie/2.png new file mode 100644 index 0000000000000000000000000000000000000000..0bf1cc29e41b8386af47c75380f3a49225363126 GIT binary patch literal 134708 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 Z-0P&}Kd-2eh{cR= 300 { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("OpsGenie notification returned %d HTTP status code. Cannot read body: %s", resp.StatusCode, err) + } + return fmt.Errorf("OpsGenie notification returned %d HTTP status code: %s", resp.StatusCode, body) + } + + return nil +} + +// Initialize loads ServiceConfig from configURL and sets logger for this Service +func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error { + service.Logger.SetLogger(logger) + service.config = &Config{} + err := service.config.SetURL(configURL) + return err +} + +// Send a notification message to OpsGenie +// See: https://docs.opsgenie.com/docs/alert-api#create-alert +func (service *Service) Send(message string, params *types.Params) error { + config := service.config + url := fmt.Sprintf(alertEndpointTemplate, config.Host) + payload := NewJSON(message, params) + + return service.sendAlert(url, config.ApiKey, payload) +} diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go new file mode 100644 index 00000000..00405e74 --- /dev/null +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -0,0 +1,37 @@ +package opsgenie + +import ( + "net/url" + + "github.com/containrrr/shoutrrr/pkg/services/standard" +) + +// Config for use within the opsgenie plugin +type Config struct { + ApiKey string `desc:"The OpsGenie API key"` + Host string `desc:"The OpsGenie API host. Use 'api.opsgenie.com' for US and 'api.eu.opsgenie.com' for EU instances"` + standard.QuerylessConfig + standard.EnumlessConfig +} + +// GetURL returns a URL representation of it's current field values +func (config *Config) GetURL() *url.URL { + return &url.URL{ + Host: config.Host, + Scheme: Scheme, + ForceQuery: false, + Path: config.ApiKey, + } +} + +// SetURL updates a ServiceConfig from a URL representation of it's field values +func (config *Config) SetURL(url *url.URL) error { + config.Host = url.Hostname() + ":" + url.Port() + config.ApiKey = url.Path[1:] + return nil +} + +const ( + // Scheme is the identifying part of this service's configuration URL + Scheme = "opsgenie" +) diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go new file mode 100644 index 00000000..bc87a3c3 --- /dev/null +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -0,0 +1,75 @@ +package opsgenie + +import ( + "encoding/json" + "github.com/containrrr/shoutrrr/pkg/types" +) + +// JSON represents the payload being sent to the OpsGenie API +// +// See: https://docs.opsgenie.com/docs/alert-api#create-alert +// +// Some fields contain complex values like arrays and objects. +// Because `params` are strings only we cannot pass in slices +// or maps. Instead we "preserve" the JSON in those fields. That +// way we can pass in complex types as JSON like so: +// +// service.Send("An example alert message", &types.Params{ +// "alias": "Life is too short for no alias", +// "description": "Every alert needs a description", +// "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, +// "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, +// "details": `{"key1": "value1", "key2": "value2"}`, +// }) +type JSON struct { + Message string `json:"message"` + Alias string `json:"alias,omitempty"` + Description string `json:"description,omitempty"` + Responders json.RawMessage `json:"responders,omitempty"` + VisibleTo json.RawMessage `json:"visibleTo,omitempty"` + Actions string `json:"actions,omitempty"` + Tags string `json:"tags,omitempty"` + Details json.RawMessage `json:"details,omitempty"` + Entity string `json:"entity,omitempty"` + Source string `json:"source,omitempty"` + Priority string `json:"priority,omitempty"` + User string `json:"user,omitempty"` + Note string `json:"note,omitempty"` +} + +func (j JSON) setStringValue(variable *string, key string, params *types.Params) { + paramValue, ok := (*params)[key] + if ok { + *variable = paramValue + } +} + +func (j JSON) setRawMessageValue(variable *json.RawMessage, key string, params *types.Params) { + paramValue, ok := (*params)[key] + if ok { + *variable = json.RawMessage(paramValue) + } +} + +// NewJSON instantiates JSON +func NewJSON(message string, params *types.Params) JSON { + if params == nil { + params = &types.Params{} + } + + result := JSON{Message: message} + result.setStringValue(&result.Alias, "alias", params) + result.setStringValue(&result.Description, "description", params) + result.setRawMessageValue(&result.Responders, "responders", params) + result.setRawMessageValue(&result.VisibleTo, "visibleTo", params) + result.setStringValue(&result.Actions, "actions", params) + result.setStringValue(&result.Tags, "tags", params) + result.setRawMessageValue(&result.Details, "details", params) + result.setStringValue(&result.Entity, "entity", params) + result.setStringValue(&result.Source, "source", params) + result.setStringValue(&result.Priority, "priority", params) + result.setStringValue(&result.User, "user", params) + result.setStringValue(&result.Note, "note", params) + + return result +} diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go new file mode 100644 index 00000000..635040ce --- /dev/null +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -0,0 +1,134 @@ +package opsgenie + +import ( + "bytes" + "crypto/tls" + "fmt" + "io/ioutil" + "log" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/containrrr/shoutrrr/pkg/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + mockAPIKey = "eb243592-faa2-4ba2-a551q-1afdf565c889" +) + +func TestOpsGenie(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shoutrrr OpsGenie Suite") +} + +var _ = Describe("the OpsGenie plugin", func() { + var ( + mockServer *httptest.Server + service *Service + checkRequest func(body string, header http.Header) + ) + + BeforeEach(func() { + // Initialize a mock http server + httpHandler := func(w http.ResponseWriter, r *http.Request) { + body, err := ioutil.ReadAll(r.Body) + Expect(err).To(BeNil()) + defer r.Body.Close() + + checkRequest(string(body), r.Header) + } + mockServer = httptest.NewTLSServer(http.HandlerFunc(httpHandler)) + + // Our mock server doesn't have a valid cert + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + + // Building a mock URL. + // It'll look something like: opsgenie://127.0.0.1:63457/eb243592-faa2-4ba2-a551q-1afdf565c889 + mockServerURL, err := url.Parse(mockServer.URL) + Expect(err).To(BeNil()) + mockURL, err := url.Parse(fmt.Sprintf("opsgenie://%s/%s", mockServerURL.Host, mockAPIKey)) + Expect(err).To(BeNil()) + + // Initialize a mock logger + var buf bytes.Buffer + logger := log.New(&buf, "", 0) + + // Initialize the OpsGenie service + service = &Service{} + err = service.Initialize(mockURL, logger) + Expect(err).To(BeNil()) + }) + + AfterEach(func() { + mockServer.Close() + }) + + It("should send an alert", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"message":"hello world"}`)) + } + + err := service.Send("hello world", &types.Params{}) + Expect(err).To(BeNil()) + }) + + When("provided nil params", func() { + It("should send an alert without additional fields", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"message":"hello world"}`)) + } + + err := service.Send("hello world", nil) + Expect(err).To(BeNil()) + }) + }) + + When("provided params", func() { + It("should send an alert with all field", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"` + + `message":"An example alert message",` + + `"alias":"Life is too short for no alias",` + + `"description":"Every alert needs a description",` + + `"responders":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}],` + + `"visibleTo":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}],` + + `"actions":"An action",` + + `"tags":"tag1 tag2",` + + `"details":{"key1":"value1","key2":"value2"},` + + `"entity":"An example entity",` + + `"source":"The source",` + + `"priority":"P1",` + + `"user":"Dracula",` + + `"note":"Here is a note"` + + `}`)) + } + + err := service.Send("An example alert message", &types.Params{ + "alias": "Life is too short for no alias", + "description": "Every alert needs a description", + "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, + "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, + "actions": "An action", + "tags": "tag1 tag2", + "details": `{"key1": "value1", "key2": "value2"}`, + "entity": "An example entity", + "source": "The source", + "priority": "P1", + "user": "Dracula", + "note": "Here is a note", + }) + Expect(err).To(BeNil()) + }) + }) +}) From 3530a13f9ec3bd688b7c892407b3a4373ba9bedb Mon Sep 17 00:00:00 2001 From: Alexei Tighineanu Date: Sun, 15 Nov 2020 11:10:50 +0100 Subject: [PATCH 02/32] Fix for issue https://github.com/containrrr/shoutrrr/issues/71 (#75) --- pkg/services/rocketchat/rocketchat.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/services/rocketchat/rocketchat.go b/pkg/services/rocketchat/rocketchat.go index 88e3edc7..ff121be6 100644 --- a/pkg/services/rocketchat/rocketchat.go +++ b/pkg/services/rocketchat/rocketchat.go @@ -34,7 +34,9 @@ func (service *Service) Send(message string, params *types.Params) error { apiURL := buildURL(config) json, _ := CreateJSONPayload(config, message, params) res, err := http.Post(apiURL, "application/json", bytes.NewReader(json)) - + if err != nil { + return fmt.Errorf("Error while posting to URL: %v", err) + } if res.StatusCode != http.StatusOK { return fmt.Errorf("failed to send notification to service, response status code %s", res.Status) } @@ -44,4 +46,3 @@ func (service *Service) Send(message string, params *types.Params) error { func buildURL(config *Config) string { return fmt.Sprintf("https://%s/hooks/%s/%s", config.Host, config.TokenA, config.TokenB) } - From c78b7692ffb0feca178d8c8cf4006a44e6a92e31 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 15 Nov 2020 11:11:56 +0100 Subject: [PATCH 03/32] docs: add atighineanu as a contributor (#81) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 5 ++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a0f4b9bc..223f0a84 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -65,6 +65,15 @@ "doc", "code" ] + }, + { + "login": "atighineanu", + "name": "Alexei Tighineanu", + "avatar_url": "https://avatars1.githubusercontent.com/u/27206712?v=4", + "profile": "https://github.com/atighineanu", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index adc46b19..bf20b99e 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,7 @@ Heavily inspired by caronc/apprise -[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-) - +[![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors-) @@ -84,12 +83,12 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
MrLuje

💻 📖
Simon Aronsson

💻 📖 🚧
Arne Jørgensen

📖 💻 +
Alexei Tighineanu

💻 - This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! From b67f9b1b9bd2a5793ce7a899282e3484c3c2379d Mon Sep 17 00:00:00 2001 From: Alexei Tighineanu Date: Sun, 15 Nov 2020 20:51:07 +0100 Subject: [PATCH 04/32] added custom port option for rocketchat (#80) --- go.mod | 6 +++--- pkg/services/rocketchat/rocketchat.go | 14 ++++++++++---- pkg/services/rocketchat/rocketchat_config.go | 2 ++ pkg/services/rocketchat/rocketchat_test.go | 9 +++++++++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index c1893d58..9200f582 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,6 @@ require ( github.com/mitchellh/mapstructure v1.2.2 // indirect github.com/onsi/ginkgo v1.8.0 github.com/onsi/gomega v1.5.0 - golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect github.com/pelletier/go-toml v1.7.0 // indirect github.com/sirupsen/logrus v1.2.0 github.com/spf13/afero v1.2.2 // indirect @@ -20,6 +17,9 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.6.3 + golang.org/x/net v0.0.0-20190522155817-f3200d17e092 + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d + golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect golang.org/x/text v0.3.2 // indirect golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect diff --git a/pkg/services/rocketchat/rocketchat.go b/pkg/services/rocketchat/rocketchat.go index ff121be6..88e31de6 100644 --- a/pkg/services/rocketchat/rocketchat.go +++ b/pkg/services/rocketchat/rocketchat.go @@ -6,7 +6,6 @@ import ( "log" "net/http" "net/url" - "github.com/containrrr/shoutrrr/pkg/services/standard" "github.com/containrrr/shoutrrr/pkg/types" ) @@ -30,12 +29,14 @@ func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error // Send a notification message to Rocket.chat func (service *Service) Send(message string, params *types.Params) error { + var res *http.Response + var err error config := service.config apiURL := buildURL(config) json, _ := CreateJSONPayload(config, message, params) - res, err := http.Post(apiURL, "application/json", bytes.NewReader(json)) + res, err = http.Post(apiURL, "application/json", bytes.NewReader(json)) if err != nil { - return fmt.Errorf("Error while posting to URL: %v", err) + return fmt.Errorf("Error while posting to URL: %v\nHOST: %s\nPORT: %s\n", err, config.Host, config.Port) } if res.StatusCode != http.StatusOK { return fmt.Errorf("failed to send notification to service, response status code %s", res.Status) @@ -44,5 +45,10 @@ func (service *Service) Send(message string, params *types.Params) error { } func buildURL(config *Config) string { - return fmt.Sprintf("https://%s/hooks/%s/%s", config.Host, config.TokenA, config.TokenB) + if config.Port != "" { + return fmt.Sprintf("https://%s:%s/hooks/%s/%s", config.Host, config.Port, config.TokenA, config.TokenB) + } else { + return fmt.Sprintf("https://%s/hooks/%s/%s", config.Host, config.TokenA, config.TokenB) + } } + diff --git a/pkg/services/rocketchat/rocketchat_config.go b/pkg/services/rocketchat/rocketchat_config.go index d767d41c..d6fbfd5b 100644 --- a/pkg/services/rocketchat/rocketchat_config.go +++ b/pkg/services/rocketchat/rocketchat_config.go @@ -14,6 +14,7 @@ type Config struct { standard.EnumlessConfig UserName string Host string + Port string TokenA string Channel string TokenB string @@ -41,6 +42,7 @@ func (config *Config) SetURL(serviceURL *url.URL) error { return errors.New(NotEnoughArguments) } + config.Port = serviceURL.Port() config.UserName = UserName config.Host = host config.TokenA = path[1] diff --git a/pkg/services/rocketchat/rocketchat_test.go b/pkg/services/rocketchat/rocketchat_test.go index 50761afd..1b4cbb4f 100644 --- a/pkg/services/rocketchat/rocketchat_test.go +++ b/pkg/services/rocketchat/rocketchat_test.go @@ -162,5 +162,14 @@ var _ = Describe("the rocketchat service", func() { Expect(string(json)).To(Equal("{\"text\":\"this is a message\",\"username\":\"overwriteUserName\",\"channel\":\"overwriteChannel\"}")) }) }) + When("sending to an URL which contains HOST:PORT", func() { + rocketchatURL, _ := url.Parse("rocketchat://testUserName@rocketchat.my-domain.com:5055/tokenA/tokenB/testChannel") + config := &Config{} + config.SetURL(rocketchatURL) + It("should generate a correct hook URL https://HOST:PORT", func() { + hookURL := buildURL(config) + Expect(hookURL).To(ContainSubstring("my-domain.com:5055")) + }) + }) }) }) From d3c987dfc0125bcec073a301b3071e50bc62c22d Mon Sep 17 00:00:00 2001 From: Alexandru Bonini Date: Sun, 15 Nov 2020 20:52:10 +0100 Subject: [PATCH 05/32] fix for https://github.com/containrrr/shoutrrr/issues/70 (#74) --- pkg/services/rocketchat/rocketchat_config.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/services/rocketchat/rocketchat_config.go b/pkg/services/rocketchat/rocketchat_config.go index d6fbfd5b..d09d9f9f 100644 --- a/pkg/services/rocketchat/rocketchat_config.go +++ b/pkg/services/rocketchat/rocketchat_config.go @@ -3,9 +3,10 @@ package rocketchat import ( "errors" "fmt" - "github.com/containrrr/shoutrrr/pkg/services/standard" "net/url" "strings" + + "github.com/containrrr/shoutrrr/pkg/services/standard" ) // Config for the rocket.chat service @@ -48,7 +49,9 @@ func (config *Config) SetURL(serviceURL *url.URL) error { config.TokenA = path[1] config.TokenB = path[2] if len(path) > 3 { - if path[3][0:1] != "@" { + if serviceURL.Fragment != "" { + config.Channel = "#" + strings.TrimPrefix(serviceURL.Fragment, "#") + } else if !strings.HasPrefix(path[3], "@") { config.Channel = "#" + path[3] } else { config.Channel = path[3] From ca5e1f2d42299e2b26933cc259574d2187d94385 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 15 Nov 2020 20:53:04 +0100 Subject: [PATCH 06/32] docs: add ellisab as a contributor (#82) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 223f0a84..6d3e5364 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -74,6 +74,15 @@ "contributions": [ "code" ] + }, + { + "login": "ellisab", + "name": "Alexandru Bonini", + "avatar_url": "https://avatars2.githubusercontent.com/u/1402047?v=4", + "profile": "https://github.com/ellisab", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index bf20b99e..0c836d9b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Heavily inspired by caronc/apprise -[![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-8-orange.svg?style=flat-square)](#contributors-) @@ -85,6 +85,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Arne Jørgensen

📖 💻
Alexei Tighineanu

💻 + +
Alexandru Bonini

💻 + From bdbdcf4f7c17e3601d957543a2b41282665f983c Mon Sep 17 00:00:00 2001 From: Alexandru Bonini Date: Tue, 17 Nov 2020 21:45:14 +0100 Subject: [PATCH 07/32] do not rewrite channel name without hashes (#85) --- pkg/services/rocketchat/rocketchat.go | 9 ++++++--- pkg/services/rocketchat/rocketchat_config.go | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/services/rocketchat/rocketchat.go b/pkg/services/rocketchat/rocketchat.go index 88e31de6..4f2f4c61 100644 --- a/pkg/services/rocketchat/rocketchat.go +++ b/pkg/services/rocketchat/rocketchat.go @@ -3,9 +3,11 @@ package rocketchat import ( "bytes" "fmt" + "io/ioutil" "log" "net/http" "net/url" + "github.com/containrrr/shoutrrr/pkg/services/standard" "github.com/containrrr/shoutrrr/pkg/types" ) @@ -36,10 +38,12 @@ func (service *Service) Send(message string, params *types.Params) error { json, _ := CreateJSONPayload(config, message, params) res, err = http.Post(apiURL, "application/json", bytes.NewReader(json)) if err != nil { - return fmt.Errorf("Error while posting to URL: %v\nHOST: %s\nPORT: %s\n", err, config.Host, config.Port) + return fmt.Errorf("Error while posting to URL: %v\nHOST: %s\nPORT: %s", err, config.Host, config.Port) } + defer res.Body.Close() if res.StatusCode != http.StatusOK { - return fmt.Errorf("failed to send notification to service, response status code %s", res.Status) + resBody, _ := ioutil.ReadAll(res.Body) + return fmt.Errorf("notification failed: %d %s", res.StatusCode, resBody) } return err } @@ -51,4 +55,3 @@ func buildURL(config *Config) string { return fmt.Sprintf("https://%s/hooks/%s/%s", config.Host, config.TokenA, config.TokenB) } } - diff --git a/pkg/services/rocketchat/rocketchat_config.go b/pkg/services/rocketchat/rocketchat_config.go index d09d9f9f..d3d8dd8d 100644 --- a/pkg/services/rocketchat/rocketchat_config.go +++ b/pkg/services/rocketchat/rocketchat_config.go @@ -50,7 +50,7 @@ func (config *Config) SetURL(serviceURL *url.URL) error { config.TokenB = path[2] if len(path) > 3 { if serviceURL.Fragment != "" { - config.Channel = "#" + strings.TrimPrefix(serviceURL.Fragment, "#") + config.Channel = "#" + serviceURL.Fragment } else if !strings.HasPrefix(path[3], "@") { config.Channel = "#" + path[3] } else { From 0f4ed7ce5fce840bd13d90b49c0d549331bfd1b7 Mon Sep 17 00:00:00 2001 From: Alexei Tighineanu Date: Tue, 24 Nov 2020 21:36:06 +0100 Subject: [PATCH 08/32] Added few testcases for rawURL passed as path/#####channel and path/#channel (used to segfault) (#83) Co-authored-by: Simon Aronsson --- pkg/services/rocketchat/rocketchat_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/services/rocketchat/rocketchat_test.go b/pkg/services/rocketchat/rocketchat_test.go index 1b4cbb4f..46ee3f52 100644 --- a/pkg/services/rocketchat/rocketchat_test.go +++ b/pkg/services/rocketchat/rocketchat_test.go @@ -171,5 +171,19 @@ var _ = Describe("the rocketchat service", func() { Expect(hookURL).To(ContainSubstring("my-domain.com:5055")) }) }) + When("sending to an URL with badly syntaxed #channel name", func() { + It("should properly parse the Channel", func() { + rocketchatURL, _ := url.Parse("rocketchat://testUserName@rocketchat.my-domain.com:5055/tokenA/tokenB/###########################testChannel") + config := &Config{} + config.SetURL(rocketchatURL) + Expect(config.Channel).To(ContainSubstring("###########################testChannel")) + }) + It("should properly parse the Channel", func() { + rocketchatURL, _ := url.Parse("rocketchat://testUserName@rocketchat.my-domain.com:5055/tokenA/tokenB/#testChannel") + config := &Config{} + config.SetURL(rocketchatURL) + Expect(config.Channel).To(ContainSubstring("#testChannel")) + }) + }) }) }) From 54f0f630d1375dea076a9c9dd21de2e9efe2b43d Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Fri, 27 Nov 2020 16:21:05 +0000 Subject: [PATCH 09/32] refactor: rename JSON to AlertPayload JSON is too generic. OpsGenie uses the term "payload" in their documentation so I've used that instead. --- pkg/services/opsgenie/opsgenie.go | 4 ++-- pkg/services/opsgenie/opsgenie_json.go | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index 42509d58..86be35fa 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -23,7 +23,7 @@ type Service struct { config *Config } -func (service *Service) sendAlert(url string, apiKey string, payload JSON) error { +func (service *Service) sendAlert(url string, apiKey string, payload AlertPayload) error { jsonBody, err := json.Marshal(payload) if err != nil { return err @@ -66,7 +66,7 @@ func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error func (service *Service) Send(message string, params *types.Params) error { config := service.config url := fmt.Sprintf(alertEndpointTemplate, config.Host) - payload := NewJSON(message, params) + payload := NewAlertPayload(message, params) return service.sendAlert(url, config.ApiKey, payload) } diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go index bc87a3c3..6917e22c 100644 --- a/pkg/services/opsgenie/opsgenie_json.go +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -5,7 +5,7 @@ import ( "github.com/containrrr/shoutrrr/pkg/types" ) -// JSON represents the payload being sent to the OpsGenie API +// AlertPayload represents the payload being sent to the OpsGenie API // // See: https://docs.opsgenie.com/docs/alert-api#create-alert // @@ -21,7 +21,7 @@ import ( // "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, // "details": `{"key1": "value1", "key2": "value2"}`, // }) -type JSON struct { +type AlertPayload struct { Message string `json:"message"` Alias string `json:"alias,omitempty"` Description string `json:"description,omitempty"` @@ -37,27 +37,27 @@ type JSON struct { Note string `json:"note,omitempty"` } -func (j JSON) setStringValue(variable *string, key string, params *types.Params) { +func (j AlertPayload) setStringValue(variable *string, key string, params *types.Params) { paramValue, ok := (*params)[key] if ok { *variable = paramValue } } -func (j JSON) setRawMessageValue(variable *json.RawMessage, key string, params *types.Params) { +func (j AlertPayload) setRawMessageValue(variable *json.RawMessage, key string, params *types.Params) { paramValue, ok := (*params)[key] if ok { *variable = json.RawMessage(paramValue) } } -// NewJSON instantiates JSON -func NewJSON(message string, params *types.Params) JSON { +// NewAlertPayload instantiates AlertPayload +func NewAlertPayload(message string, params *types.Params) AlertPayload { if params == nil { params = &types.Params{} } - result := JSON{Message: message} + result := AlertPayload{Message: message} result.setStringValue(&result.Alias, "alias", params) result.setStringValue(&result.Description, "description", params) result.setRawMessageValue(&result.Responders, "responders", params) From c4ba3b9c0237858671d874aa3ae949f070a2105d Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Fri, 27 Nov 2020 16:21:38 +0000 Subject: [PATCH 10/32] refactor: rename `plugin` to `service` Shoutrrr uses the term `service` by convention --- pkg/services/opsgenie/opsgenie_config.go | 2 +- pkg/services/opsgenie/opsgenie_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 00405e74..01378fdb 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -6,7 +6,7 @@ import ( "github.com/containrrr/shoutrrr/pkg/services/standard" ) -// Config for use within the opsgenie plugin +// Config for use within the opsgenie service type Config struct { ApiKey string `desc:"The OpsGenie API key"` Host string `desc:"The OpsGenie API host. Use 'api.opsgenie.com' for US and 'api.eu.opsgenie.com' for EU instances"` diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index 635040ce..8cb9ca9a 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -26,7 +26,7 @@ func TestOpsGenie(t *testing.T) { RunSpecs(t, "Shoutrrr OpsGenie Suite") } -var _ = Describe("the OpsGenie plugin", func() { +var _ = Describe("the OpsGenie service", func() { var ( mockServer *httptest.Server service *Service From c108686389f1e4d55d91661537fc30a7dfe71d34 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 10 Dec 2020 20:51:02 +0000 Subject: [PATCH 11/32] feat: add support for setting parameters via query string --- docs/services/opsgenie.md | 10 +++ pkg/services/opsgenie/opsgenie.go | 4 +- pkg/services/opsgenie/opsgenie_config.go | 77 ++++++++++++++-- pkg/services/opsgenie/opsgenie_json.go | 29 +++++-- pkg/services/opsgenie/opsgenie_test.go | 106 +++++++++++++++++++++-- 5 files changed, 202 insertions(+), 24 deletions(-) diff --git a/docs/services/opsgenie.md b/docs/services/opsgenie.md index 4229314d..6d659e8d 100644 --- a/docs/services/opsgenie.md +++ b/docs/services/opsgenie.md @@ -48,3 +48,13 @@ service.Send("An example alert message", &types.Params{ }) ``` +# Optional parameters + +You can optionally specify the parameters in the URL: +pushover://shoutrrr:token@userKey/?devices=device&title=Custom+Title&priority=1 + +Example using the command line: + + shoutrrr send -u 'opsgenie://api.eu.opsgenie.com/token?tags=["tag1","tag2"]&description=testing&responders=[{"username":"superuser", "type": "user"}]&entity=Example Entity&source=Example Source&actions=["asdf", "bcde"]' -m "Hello World6" + + diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index 86be35fa..5fddbb4a 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -28,6 +28,7 @@ func (service *Service) sendAlert(url string, apiKey string, payload AlertPayloa if err != nil { return err } + jsonBuffer := bytes.NewBuffer(jsonBody) req, err := http.NewRequest("POST", url, jsonBuffer) @@ -66,7 +67,6 @@ func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error func (service *Service) Send(message string, params *types.Params) error { config := service.config url := fmt.Sprintf(alertEndpointTemplate, config.Host) - payload := NewAlertPayload(message, params) - + payload := NewAlertPayload(message, config, params) return service.sendAlert(url, config.ApiKey, payload) } diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 01378fdb..f9dd3242 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -1,6 +1,7 @@ package opsgenie import ( + "fmt" "net/url" "github.com/containrrr/shoutrrr/pkg/services/standard" @@ -10,24 +11,84 @@ import ( type Config struct { ApiKey string `desc:"The OpsGenie API key"` Host string `desc:"The OpsGenie API host. Use 'api.opsgenie.com' for US and 'api.eu.opsgenie.com' for EU instances"` - standard.QuerylessConfig standard.EnumlessConfig + Alias string + Description string + Responders string + VisibleTo string + Actions string + Tags string + Details string + Entity string + Source string + Priority string + Note string + User string } -// GetURL returns a URL representation of it's current field values -func (config *Config) GetURL() *url.URL { - return &url.URL{ - Host: config.Host, - Scheme: Scheme, - ForceQuery: false, - Path: config.ApiKey, +// QueryFields returns the fields that are part of the Query of the service URL +func (config *Config) QueryFields() []string { + return []string{ + "alias", + "responders", + "description", + "visibleTo", + "actions", + "tags", + "details", + "entity", + "source", + "priority", + "note", + "user", } } +// Set updates the value of a Query field +func (config *Config) Set(key string, value string) error { + switch key { + case "alias": + config.Alias = value + case "description": + config.Description = value + case "responders": + config.Responders = value + case "visibleTo": + config.VisibleTo = value + case "actions": + config.Actions = value + case "tags": + config.Tags = value + case "details": + config.Details = value + case "entity": + config.Entity = value + case "source": + config.Source = value + case "priority": + config.Priority = value + case "note": + config.Note = value + case "user": + config.User = value + default: + return fmt.Errorf("invalid query key \"%s\"", key) + } + + return nil +} + // SetURL updates a ServiceConfig from a URL representation of it's field values func (config *Config) SetURL(url *url.URL) error { config.Host = url.Hostname() + ":" + url.Port() config.ApiKey = url.Path[1:] + + for key, vals := range url.Query() { + if err := config.Set(key, vals[0]); err != nil { + return err + } + } + return nil } diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go index 6917e22c..5a0bdc16 100644 --- a/pkg/services/opsgenie/opsgenie_json.go +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -27,8 +27,8 @@ type AlertPayload struct { Description string `json:"description,omitempty"` Responders json.RawMessage `json:"responders,omitempty"` VisibleTo json.RawMessage `json:"visibleTo,omitempty"` - Actions string `json:"actions,omitempty"` - Tags string `json:"tags,omitempty"` + Actions json.RawMessage `json:"actions,omitempty"` + Tags json.RawMessage `json:"tags,omitempty"` Details json.RawMessage `json:"details,omitempty"` Entity string `json:"entity,omitempty"` Source string `json:"source,omitempty"` @@ -52,18 +52,35 @@ func (j AlertPayload) setRawMessageValue(variable *json.RawMessage, key string, } // NewAlertPayload instantiates AlertPayload -func NewAlertPayload(message string, params *types.Params) AlertPayload { +func NewAlertPayload(message string, config *Config, params *types.Params) AlertPayload { if params == nil { params = &types.Params{} } - result := AlertPayload{Message: message} + result := AlertPayload{ + Message: message, + // Populate with values from the query string as defaults + Alias: config.Alias, + Description: config.Description, + Responders: json.RawMessage(config.Responders), + VisibleTo: json.RawMessage(config.VisibleTo), + Actions: json.RawMessage(config.Actions), + Tags: json.RawMessage(config.Tags), + Details: json.RawMessage(config.Details), + Entity: config.Entity, + Source: config.Source, + Priority: config.Priority, + User: config.User, + Note: config.Note, + } + + // If specified, overwrite the values from the query string result.setStringValue(&result.Alias, "alias", params) result.setStringValue(&result.Description, "description", params) result.setRawMessageValue(&result.Responders, "responders", params) result.setRawMessageValue(&result.VisibleTo, "visibleTo", params) - result.setStringValue(&result.Actions, "actions", params) - result.setStringValue(&result.Tags, "tags", params) + result.setRawMessageValue(&result.Actions, "actions", params) + result.setRawMessageValue(&result.Tags, "tags", params) result.setRawMessageValue(&result.Details, "details", params) result.setStringValue(&result.Entity, "entity", params) result.setStringValue(&result.Source, "source", params) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index 8cb9ca9a..4f6192e6 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -29,11 +29,12 @@ func TestOpsGenie(t *testing.T) { var _ = Describe("the OpsGenie service", func() { var ( mockServer *httptest.Server + mockQuery map[string]string service *Service checkRequest func(body string, header http.Header) ) - BeforeEach(func() { + JustBeforeEach(func() { // Initialize a mock http server httpHandler := func(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) @@ -52,6 +53,11 @@ var _ = Describe("the OpsGenie service", func() { mockServerURL, err := url.Parse(mockServer.URL) Expect(err).To(BeNil()) mockURL, err := url.Parse(fmt.Sprintf("opsgenie://%s/%s", mockServerURL.Host, mockAPIKey)) + tmpQuery := mockURL.Query() + for key, value := range mockQuery { + tmpQuery.Add(key, value) + } + mockURL.RawQuery = tmpQuery.Encode() Expect(err).To(BeNil()) // Initialize a mock logger @@ -64,7 +70,7 @@ var _ = Describe("the OpsGenie service", func() { Expect(err).To(BeNil()) }) - AfterEach(func() { + JustAfterEach(func() { mockServer.Close() }) @@ -92,8 +98,8 @@ var _ = Describe("the OpsGenie service", func() { }) }) - When("provided params", func() { - It("should send an alert with all field", func() { + When("provided parameters", func() { + It("should send an alert with all fields populated from parameters", func() { checkRequest = func(body string, header http.Header) { Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) Expect(header["Content-Type"][0]).To(Equal("application/json")) @@ -103,8 +109,8 @@ var _ = Describe("the OpsGenie service", func() { `"description":"Every alert needs a description",` + `"responders":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}],` + `"visibleTo":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}],` + - `"actions":"An action",` + - `"tags":"tag1 tag2",` + + `"actions":["action1","action2"],` + + `"tags":["tag1","tag2"],` + `"details":{"key1":"value1","key2":"value2"},` + `"entity":"An example entity",` + `"source":"The source",` + @@ -119,8 +125,8 @@ var _ = Describe("the OpsGenie service", func() { "description": "Every alert needs a description", "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, - "actions": "An action", - "tags": "tag1 tag2", + "actions": `["action1", "action2"]`, + "tags": `["tag1", "tag2"]`, "details": `{"key1": "value1", "key2": "value2"}`, "entity": "An example entity", "source": "The source", @@ -131,4 +137,88 @@ var _ = Describe("the OpsGenie service", func() { Expect(err).To(BeNil()) }) }) + + When("provided query fields", func() { + BeforeEach(func() { + mockQuery = map[string]string{} + mockQuery["alias"] = "query-alias" + mockQuery["description"] = "query-description" + mockQuery["responders"] = `[{"name": "query_team", "type": "team"}]` + mockQuery["visibleTo"] = `[{"username": "query_user", "type": "user"}]` + mockQuery["actions"] = `["queryAction1", "queryAction2"]` + mockQuery["tags"] = `["queryTag1", "queryTag2"]` + mockQuery["details"] = `{"queryKey1": "queryValue1", "queryKey2": "queryValue2"}` + mockQuery["entity"] = "query-entity" + mockQuery["source"] = "query-source" + mockQuery["priority"] = "P2" + mockQuery["user"] = "query-user" + mockQuery["note"] = "query-note" + }) + + It("should send an alert with all fields populated from query fields", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"` + + `message":"An example alert message",` + + `"alias":"query-alias",` + + `"description":"query-description",` + + `"responders":[{"name":"query_team","type":"team"}],` + + `"visibleTo":[{"username":"query_user","type":"user"}],` + + `"actions":["queryAction1","queryAction2"],` + + `"tags":["queryTag1","queryTag2"],` + + `"details":{"queryKey1":"queryValue1","queryKey2":"queryValue2"},` + + `"entity":"query-entity",` + + `"source":"query-source",` + + `"priority":"P2",` + + `"user":"query-user",` + + `"note":"query-note"` + + `}`)) + } + + err := service.Send("An example alert message", &types.Params{}) + Expect(err).To(BeNil()) + }) + + When("provided query fields and parameters", func() { + It("should send an alert with all fields populated from parameters, overwriting the query fields", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"` + + `message":"An example alert message",` + + `"alias":"Life is too short for no alias",` + + `"description":"Every alert needs a description",` + + `"responders":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}],` + + `"visibleTo":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}],` + + `"actions":["action1","action2"],` + + `"tags":["tag1","tag2"],` + + `"details":{"key1":"value1","key2":"value2"},` + + `"entity":"An example entity",` + + `"source":"The source",` + + `"priority":"P1",` + + `"user":"Dracula",` + + `"note":"Here is a note"` + + `}`)) + } + + err := service.Send("An example alert message", &types.Params{ + "alias": "Life is too short for no alias", + "description": "Every alert needs a description", + "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, + "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, + "actions": `["action1", "action2"]`, + "tags": `["tag1", "tag2"]`, + "details": `{"key1": "value1", "key2": "value2"}`, + "entity": "An example entity", + "source": "The source", + "priority": "P1", + "user": "Dracula", + "note": "Here is a note", + }) + Expect(err).To(BeNil()) + }) + }) + }) + }) From 88d19ae34c6907eb0e06a1bbcbd8b9ec10b8b72a Mon Sep 17 00:00:00 2001 From: JonasPf Date: Mon, 28 Dec 2020 17:47:02 +0000 Subject: [PATCH 12/32] Fix query parameter documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: nils måsén --- docs/services/opsgenie.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/services/opsgenie.md b/docs/services/opsgenie.md index 6d659e8d..7d9c74fd 100644 --- a/docs/services/opsgenie.md +++ b/docs/services/opsgenie.md @@ -51,10 +51,9 @@ service.Send("An example alert message", &types.Params{ # Optional parameters You can optionally specify the parameters in the URL: -pushover://shoutrrr:token@userKey/?devices=device&title=Custom+Title&priority=1 +opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&actions=An+action&tags=["tag1","tag2"]&entity=An+example+entity&source=The+source&priority=P1&user=Dracula¬e=Here+is+a+note Example using the command line: shoutrrr send -u 'opsgenie://api.eu.opsgenie.com/token?tags=["tag1","tag2"]&description=testing&responders=[{"username":"superuser", "type": "user"}]&entity=Example Entity&source=Example Source&actions=["asdf", "bcde"]' -m "Hello World6" - From 5277afa5fa444f58400fcb5286b2385c4d74b08d Mon Sep 17 00:00:00 2001 From: JonasPf Date: Mon, 28 Dec 2020 17:47:23 +0000 Subject: [PATCH 13/32] Implement GetURL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: nils måsén --- pkg/services/opsgenie/opsgenie_config.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index f9dd3242..b2ac8b7d 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -92,6 +92,16 @@ func (config *Config) SetURL(url *url.URL) error { return nil } +func (config *Config) GetURL() *url.URL { + return &url.URL{ + Host: fmt.Sprintf("%s:%d", config.Host, config.Port), + Path: fmt.Sprintf("/%s", config.ApiKey), + Scheme: Scheme, + ForceQuery: true, + RawQuery: format.BuildQuery(config), + } +} + const ( // Scheme is the identifying part of this service's configuration URL Scheme = "opsgenie" From 3a4d5c601685436fea836d1e0269eba964c3f90d Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Wed, 6 Jan 2021 20:27:09 +0000 Subject: [PATCH 14/32] Add opsgenie to servicemap --- pkg/router/servicemap.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/router/servicemap.go b/pkg/router/servicemap.go index 0af8cb6e..89aa1efd 100644 --- a/pkg/router/servicemap.go +++ b/pkg/router/servicemap.go @@ -8,6 +8,7 @@ import ( "github.com/containrrr/shoutrrr/pkg/services/join" "github.com/containrrr/shoutrrr/pkg/services/logger" "github.com/containrrr/shoutrrr/pkg/services/mattermost" + "github.com/containrrr/shoutrrr/pkg/services/opsgenie" "github.com/containrrr/shoutrrr/pkg/services/pushbullet" "github.com/containrrr/shoutrrr/pkg/services/pushover" "github.com/containrrr/shoutrrr/pkg/services/rocketchat" @@ -37,4 +38,5 @@ var serviceMap = map[string]func() t.Service{ "zulip": func() t.Service { return &zulip.Service{} }, "join": func() t.Service { return &join.Service{} }, "rocketchat": func() t.Service { return &rocketchat.Service{} }, + "opsgenie": func() t.Service { return &opsgenie.Service{} }, } From 993bce8109b56ca7aa33500577ba3f025fc52872 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Wed, 6 Jan 2021 20:28:34 +0000 Subject: [PATCH 15/32] Support generating and verifying opsgenie URLs --- pkg/services/opsgenie/opsgenie.go | 4 +- pkg/services/opsgenie/opsgenie_config.go | 71 +++++++++++++++++++----- pkg/services/opsgenie/opsgenie_test.go | 69 +++++++++++++++++++++++ 3 files changed, 128 insertions(+), 16 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index 5fddbb4a..8f4265c9 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -14,7 +14,7 @@ import ( ) const ( - alertEndpointTemplate = "https://%s/v2/alerts" + alertEndpointTemplate = "https://%s:%d/v2/alerts" ) // Service providing OpsGenie as a notification service @@ -66,7 +66,7 @@ func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error // See: https://docs.opsgenie.com/docs/alert-api#create-alert func (service *Service) Send(message string, params *types.Params) error { config := service.config - url := fmt.Sprintf(alertEndpointTemplate, config.Host) + url := fmt.Sprintf(alertEndpointTemplate, config.Host, config.Port) payload := NewAlertPayload(message, config, params) return service.sendAlert(url, config.ApiKey, payload) } diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index b2ac8b7d..33026300 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -3,27 +3,30 @@ package opsgenie import ( "fmt" "net/url" + "strconv" + "github.com/containrrr/shoutrrr/pkg/format" "github.com/containrrr/shoutrrr/pkg/services/standard" ) // Config for use within the opsgenie service type Config struct { ApiKey string `desc:"The OpsGenie API key"` - Host string `desc:"The OpsGenie API host. Use 'api.opsgenie.com' for US and 'api.eu.opsgenie.com' for EU instances"` + Host string `desc:"The OpsGenie API host. Use 'api.eu.opsgenie.com' for EU instances" default:"api.opsgenie.com"` + Port uint16 `desc:"The OpsGenie API port." default:"443"` standard.EnumlessConfig - Alias string - Description string - Responders string - VisibleTo string - Actions string - Tags string - Details string - Entity string - Source string - Priority string - Note string - User string + Alias string `desc:"Client-defined identifier of the alert" optional:"true"` + Description string `desc:"Description field of the alert" optional:"true"` + Responders string `desc:"Teams, users, escalations and schedules that the alert will be routed to send notifications" optional:"true"` + VisibleTo string `desc:"Teams and users that the alert will become visible to without sending any notification" optional:"true"` + Actions string `desc:"Custom actions that will be available for the alert" optional:"true"` + Tags string `desc:"Tags of the alert" optional:"true"` + Details string `desc:"Map of key-value pairs to use as custom properties of the alert" optional:"true"` + Entity string `desc:"Entity field of the alert that is generally used to specify which domain the Source field of the alert" optional:"true"` + Source string `desc:"Source field of the alert" optional:"true"` + Priority string `desc:"Priority level of the alert. Possible values are P1, P2, P3, P4 and P5" optional:"true"` + Note string `desc:"Additional note that will be added while creating the alert" optional:"true"` + User string `desc:"Display name of the request owner" optional:"true"` } // QueryFields returns the fields that are part of the Query of the service URL @@ -78,11 +81,51 @@ func (config *Config) Set(key string, value string) error { return nil } +// Get returns the values of a Query field +func (config *Config) Get(key string) (string, error) { + switch key { + case "alias": + return config.Alias, nil + case "description": + return config.Description, nil + case "responders": + return config.Responders, nil + case "visibleTo": + return config.VisibleTo, nil + case "actions": + return config.Actions, nil + case "tags": + return config.Tags, nil + case "details": + return config.Details, nil + case "entity": + return config.Entity, nil + case "source": + return config.Source, nil + case "priority": + return config.Priority, nil + case "note": + return config.Note, nil + case "user": + return config.User, nil + } + + return "", fmt.Errorf("invalid query key \"%s\"", key) +} + // SetURL updates a ServiceConfig from a URL representation of it's field values func (config *Config) SetURL(url *url.URL) error { - config.Host = url.Hostname() + ":" + url.Port() + config.Host = url.Hostname() config.ApiKey = url.Path[1:] + if url.Port() != "" { + port, err := strconv.ParseUint(url.Port(), 10, 16) + if err != nil { + return err + } + config.Port = uint16(port) + } + for key, vals := range url.Query() { if err := config.Set(key, vals[0]); err != nil { return err diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index 4f6192e6..ef09f05d 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -19,6 +19,7 @@ import ( const ( mockAPIKey = "eb243592-faa2-4ba2-a551q-1afdf565c889" + mockHost = "api.opsgenie.com" ) func TestOpsGenie(t *testing.T) { @@ -220,5 +221,73 @@ var _ = Describe("the OpsGenie service", func() { }) }) }) +}) + +var _ = Describe("the OpsGenie Config struct", func() { + When("provided with a simple URL", func() { + It("should populate the config with host and apikey", func() { + url, err := url.Parse(fmt.Sprintf("opsgenie://%s/%s", mockHost, mockAPIKey)) + Expect(err).To(BeNil()) + + config := Config{} + err = config.SetURL(url) + Expect(err).To(BeNil()) + + Expect(config.ApiKey).To(Equal(mockAPIKey)) + Expect(config.Host).To(Equal(mockHost)) + Expect(config.Port).To(Equal(uint16(0))) + }) + }) + + When("provided with an URL with port", func() { + It("should populate the port field", func() { + url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s", mockHost, mockAPIKey)) + Expect(err).To(BeNil()) + config := Config{} + err = config.SetURL(url) + Expect(err).To(BeNil()) + + Expect(config.Port).To(Equal(uint16(12345))) + }) + }) + + When("provided with an URL and query parameters", func() { + It("should populate the relevant fields with the query parameter values", func() { + queryParams := `alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&actions=["An+action"]&tags=["tag1","tag2"]&details=these+are+details&entity=An+example+entity&source=The+source&priority=P1&user=Dracula¬e=Here+is+a+note` + url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s?%s", mockHost, mockAPIKey, queryParams)) + Expect(err).To(BeNil()) + + config := Config{} + err = config.SetURL(url) + Expect(err).To(BeNil()) + + Expect(config.Alias).To(Equal("Life is too short for no alias")) + Expect(config.Description).To(Equal("Every alert needs a description")) + //TODO + //Responders json.RawMessage `json:"responders,omitempty"` + //VisibleTo json.RawMessage `json:"visibleTo,omitempty"` + Expect(config.Actions).To(Equal(`["An action"]`)) + Expect(config.Tags).To(Equal(`["tag1","tag2"]`)) + Expect(config.Details).To(Equal("these are details")) + Expect(config.Entity).To(Equal("An example entity")) + Expect(config.Source).To(Equal("The source")) + Expect(config.Priority).To(Equal("P1")) + Expect(config.User).To(Equal("Dracula")) + Expect(config.Note).To(Equal("Here is a note")) + + }) + }) + + When("provided with an URL and an invalid query parameter", func() { + It("should return an error", func() { + queryParams := `invalid=value` + url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s?%s", mockHost, mockAPIKey, queryParams)) + + config := Config{} + err = config.SetURL(url) + + Expect(err).NotTo(BeNil()) + }) + }) }) From cddfbf85f4afb11335a4fb1a141a09234c4b42c9 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Mon, 25 Jan 2021 20:45:29 +0000 Subject: [PATCH 16/32] Use OpsGenie convention for URL params instead of json --- pkg/format/format_query.go | 4 +- pkg/services/opsgenie/opsgenie.go | 5 +- pkg/services/opsgenie/opsgenie_config.go | 171 +++++-------- pkg/services/opsgenie/opsgenie_entity.go | 88 +++++++ pkg/services/opsgenie/opsgenie_json.go | 134 ++++++++-- pkg/services/opsgenie/opsgenie_test.go | 309 +++++++++++++---------- 6 files changed, 448 insertions(+), 263 deletions(-) create mode 100644 pkg/services/opsgenie/opsgenie_entity.go diff --git a/pkg/format/format_query.go b/pkg/format/format_query.go index cae270d0..132ae992 100644 --- a/pkg/format/format_query.go +++ b/pkg/format/format_query.go @@ -15,7 +15,9 @@ func BuildQuery(cqr types.ConfigQueryResolver) string { if index == 1 { format = "&%s=%s" } - query += fmt.Sprintf(format, key, value) + if value != "" { + query += fmt.Sprintf(format, key, value) + } } return query diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index 8f4265c9..aa1d6747 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -67,6 +67,9 @@ func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error func (service *Service) Send(message string, params *types.Params) error { config := service.config url := fmt.Sprintf(alertEndpointTemplate, config.Host, config.Port) - payload := NewAlertPayload(message, config, params) + payload, err := NewAlertPayload(message, config, params) + if err != nil { + return err + } return service.sendAlert(url, config.ApiKey, payload) } diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 33026300..d0a19110 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -6,115 +6,79 @@ import ( "strconv" "github.com/containrrr/shoutrrr/pkg/format" - "github.com/containrrr/shoutrrr/pkg/services/standard" + "github.com/containrrr/shoutrrr/pkg/types" ) // Config for use within the opsgenie service type Config struct { - ApiKey string `desc:"The OpsGenie API key"` - Host string `desc:"The OpsGenie API host. Use 'api.eu.opsgenie.com' for EU instances" default:"api.opsgenie.com"` - Port uint16 `desc:"The OpsGenie API port." default:"443"` - standard.EnumlessConfig - Alias string `desc:"Client-defined identifier of the alert" optional:"true"` - Description string `desc:"Description field of the alert" optional:"true"` - Responders string `desc:"Teams, users, escalations and schedules that the alert will be routed to send notifications" optional:"true"` - VisibleTo string `desc:"Teams and users that the alert will become visible to without sending any notification" optional:"true"` - Actions string `desc:"Custom actions that will be available for the alert" optional:"true"` - Tags string `desc:"Tags of the alert" optional:"true"` - Details string `desc:"Map of key-value pairs to use as custom properties of the alert" optional:"true"` - Entity string `desc:"Entity field of the alert that is generally used to specify which domain the Source field of the alert" optional:"true"` - Source string `desc:"Source field of the alert" optional:"true"` - Priority string `desc:"Priority level of the alert. Possible values are P1, P2, P3, P4 and P5" optional:"true"` - Note string `desc:"Additional note that will be added while creating the alert" optional:"true"` - User string `desc:"Display name of the request owner" optional:"true"` + ApiKey string `desc:"The OpsGenie API key"` + Host string `desc:"The OpsGenie API host. Use 'api.eu.opsgenie.com' for EU instances" default:"api.opsgenie.com"` + Port uint16 `desc:"The OpsGenie API port." default:"443"` + Alias string `key:"alias" desc:"Client-defined identifier of the alert" optional:"true"` + Description string `key:"description" desc:"Description field of the alert" optional:"true"` + Responders []Entity `key:"responders" desc:"Teams, users, escalations and schedules that the alert will be routed to send notifications" optional:"true"` + VisibleTo []Entity `key:"visibleTo" desc:"Teams and users that the alert will become visible to without sending any notification" optional:"true"` + Actions []string `key:"actions" desc:"Custom actions that will be available for the alert" optional:"true"` + Tags []string `key:"tags" desc:"Tags of the alert" optional:"true"` + Details string `key:"details" desc:"Map of key-value pairs to use as custom properties of the alert" optional:"true"` + Entity string `key:"entity" desc:"Entity field of the alert that is generally used to specify which domain the Source field of the alert" optional:"true"` + Source string `key:"source" desc:"Source field of the alert" optional:"true"` + Priority string `key:"priority" desc:"Priority level of the alert. Possible values are P1, P2, P3, P4 and P5" optional:"true"` + Note string `key:"note" desc:"Additional note that will be added while creating the alert" optional:"true"` + User string `key:"user" desc:"Display name of the request owner" optional:"true"` } -// QueryFields returns the fields that are part of the Query of the service URL -func (config *Config) QueryFields() []string { - return []string{ - "alias", - "responders", - "description", - "visibleTo", - "actions", - "tags", - "details", - "entity", - "source", - "priority", - "note", - "user", - } +func (config Config) Enums() map[string]types.EnumFormatter { + return map[string]types.EnumFormatter{} } -// Set updates the value of a Query field -func (config *Config) Set(key string, value string) error { - switch key { - case "alias": - config.Alias = value - case "description": - config.Description = value - case "responders": - config.Responders = value - case "visibleTo": - config.VisibleTo = value - case "actions": - config.Actions = value - case "tags": - config.Tags = value - case "details": - config.Details = value - case "entity": - config.Entity = value - case "source": - config.Source = value - case "priority": - config.Priority = value - case "note": - config.Note = value - case "user": - config.User = value - default: - return fmt.Errorf("invalid query key \"%s\"", key) +// Public version of GetURL that creates a new PropKeyResolver when accessed from outside the package +func (config *Config) GetURL() *url.URL { + resolver := format.NewPropKeyResolver(config) + return config.getURL(&resolver) +} + +// Private version of GetURL that can use an instance of PropKeyResolver instead of rebuilding it's model from reflection +func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL { + host := "" + if config.Port > 0 { + host = fmt.Sprintf("%s:%d", config.Host, config.Port) + } else { + host = config.Host } - return nil -} + result := &url.URL{ + Host: host, + Path: fmt.Sprintf("/%s", config.ApiKey), + Scheme: Scheme, + RawQuery: format.BuildQuery(resolver), + } -// Get returns the values of a Query field -func (config *Config) Get(key string) (string, error) { - switch key { - case "alias": - return config.Alias, nil - case "description": - return config.Description, nil - case "responders": - return config.Responders, nil - case "visibleTo": - return config.VisibleTo, nil - case "actions": - return config.Actions, nil - case "tags": - return config.Tags, nil - case "details": - return config.Details, nil - case "entity": - return config.Entity, nil - case "source": - return config.Source, nil - case "priority": - return config.Priority, nil - case "note": - return config.Note, nil - case "user": - return config.User, nil + // Add OpsGenie specific data types + q := result.Query() + if len(config.Responders) > 0 { + // TODO: Error handling + responders, _ := serializeEntities(config.Responders) + q.Set("responders", responders) } + if len(config.VisibleTo) > 0 { + // TODO: Error handling + visibleTo, _ := serializeEntities(config.VisibleTo) + q.Set("visibleTo", visibleTo) + } + result.RawQuery = q.Encode() - return "", fmt.Errorf("invalid query key \"%s\"", key) + return result } // SetURL updates a ServiceConfig from a URL representation of it's field values func (config *Config) SetURL(url *url.URL) error { + resolver := format.NewPropKeyResolver(config) + return config.setURL(&resolver, url) +} + +// Private version of SetURL that can use an instance of PropKeyResolver instead of rebuilding it's model from reflection +func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) error { config.Host = url.Hostname() config.ApiKey = url.Path[1:] @@ -127,7 +91,18 @@ func (config *Config) SetURL(url *url.URL) error { } for key, vals := range url.Query() { - if err := config.Set(key, vals[0]); err != nil { + var err error + + switch key { + case "responders": + config.Responders, err = deserializeEntities(vals[0]) + case "visibleTo": + config.VisibleTo, err = deserializeEntities(vals[0]) + default: + err = resolver.Set(key, vals[0]) + } + + if err != nil { return err } } @@ -135,16 +110,6 @@ func (config *Config) SetURL(url *url.URL) error { return nil } -func (config *Config) GetURL() *url.URL { - return &url.URL{ - Host: fmt.Sprintf("%s:%d", config.Host, config.Port), - Path: fmt.Sprintf("/%s", config.ApiKey), - Scheme: Scheme, - ForceQuery: true, - RawQuery: format.BuildQuery(config), - } -} - const ( // Scheme is the identifying part of this service's configuration URL Scheme = "opsgenie" diff --git a/pkg/services/opsgenie/opsgenie_entity.go b/pkg/services/opsgenie/opsgenie_entity.go new file mode 100644 index 00000000..5fd06fd1 --- /dev/null +++ b/pkg/services/opsgenie/opsgenie_entity.go @@ -0,0 +1,88 @@ +package opsgenie + +import ( + "fmt" + "regexp" + "strings" +) + +// Entity represents either a user or a team +// +// The different variations are: +// +// { "id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c", "type":"team" } +// { "name":"rocket_team", "type":"team" } +// { "id":"bb4d9938-c3c2-455d-aaab-727aa701c0d8", "type":"user" } +// { "username":"trinity@opsgenie.com", "type":"user" } +type Entity struct { + Type string `json:"type"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Username string `json:"username,omitempty"` +} + +func serializeEntities(entities []Entity) (string, error) { + entityStrings := []string{} + + for _, entity := range entities { + identifier := "" + + if entity.ID != "" { + identifier = entity.ID + } else if entity.Name != "" { + identifier = entity.Name + } else if entity.Username != "" { + identifier = entity.Username + } else { + return "", fmt.Errorf("invalid entity, should have either ID, name or username") + } + + entityStr := fmt.Sprintf("%s:%s", entity.Type, identifier) + entityStrings = append(entityStrings, entityStr) + } + + return strings.Join(entityStrings, ","), nil +} + +func deserializeEntities(str string) ([]Entity, error) { + result := []Entity{} + + entityStrings := strings.Split(str, ",") + for _, entityStr := range entityStrings { + elements := strings.Split(entityStr, ":") + + if len(elements) != 2 { + return result, fmt.Errorf("invalid entity, should have two elments separated by colon: %q", entityStr) + } + entityType := elements[0] + identifier := elements[1] + + entity := Entity{ + Type: entityType, + } + + isID, err := isOpsGenieID(identifier) + if err != nil { + return result, fmt.Errorf("invalid entity, cannot parse id/name: %q", identifier) + } + + if isID { + entity.ID = identifier + } else if entityType == "team" { + entity.Name = identifier + } else if entityType == "user" { + entity.Username = identifier + } else { + return result, fmt.Errorf("invalid entity, unexpected entity type: %q", entityType) + } + + result = append(result, entity) + } + + return result, nil +} + +// Detects OpsGenie IDs in the form 4513b7ea-3b91-438f-b7e4-e3e54af9147c +func isOpsGenieID(str string) (bool, error) { + return regexp.MatchString(`^[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}$`, str) +} diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go index 5a0bdc16..a3505542 100644 --- a/pkg/services/opsgenie/opsgenie_json.go +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -2,6 +2,9 @@ package opsgenie import ( "encoding/json" + "fmt" + "strings" + "github.com/containrrr/shoutrrr/pkg/types" ) @@ -25,10 +28,10 @@ type AlertPayload struct { Message string `json:"message"` Alias string `json:"alias,omitempty"` Description string `json:"description,omitempty"` - Responders json.RawMessage `json:"responders,omitempty"` - VisibleTo json.RawMessage `json:"visibleTo,omitempty"` - Actions json.RawMessage `json:"actions,omitempty"` - Tags json.RawMessage `json:"tags,omitempty"` + Responders []Entity `json:"responders,omitempty"` + VisibleTo []Entity `json:"visibleTo,omitempty"` + Actions []string `json:"actions,omitempty"` + Tags []string `json:"tags,omitempty"` Details json.RawMessage `json:"details,omitempty"` Entity string `json:"entity,omitempty"` Source string `json:"source,omitempty"` @@ -37,6 +40,42 @@ type AlertPayload struct { Note string `json:"note,omitempty"` } +// TODO: Refactor all set*Value methods into one +func (j AlertPayload) setEntityValue(variable *[]Entity, key string, params *types.Params) { + paramValue, ok := (*params)[key] + if ok { + entityStrings := strings.Split(paramValue, ",") + for _, entityStr := range entityStrings { + elements := strings.Split(entityStr, ":") + + // TODO: Error handling + entityType := elements[0] + identifier := elements[1] + + entity := Entity{ + Type: entityType, + } + + isID, err := isOpsGenieID(identifier) + if err != nil { + // TODO: Error handling + } + + if isID { + entity.ID = identifier + } else if entityType == "team" { + entity.Name = identifier + } else if entityType == "user" { + entity.Username = identifier + } else { + // TODO: Error handling + } + + *variable = append(*variable, entity) + } + } +} + func (j AlertPayload) setStringValue(variable *string, key string, params *types.Params) { paramValue, ok := (*params)[key] if ok { @@ -44,6 +83,24 @@ func (j AlertPayload) setStringValue(variable *string, key string, params *types } } +func (j AlertPayload) setConfigValue(variable *string, key string, params *types.Params) { + paramValue, ok := (*params)[key] + if ok { + *variable = paramValue + } +} + +// Splits a parameter string at the comma and assigns it to a slice variable +// +// TODO: This is somewhat of a duplication of the code in formatter.go#SetConfigField - is there a better way? +func (j AlertPayload) setSliceValues(variable *[]string, key string, params *types.Params) { + paramValue, ok := (*params)[key] + if ok { + *variable = strings.Split(paramValue, ",") + } +} + +// TODO func (j AlertPayload) setRawMessageValue(variable *json.RawMessage, key string, params *types.Params) { paramValue, ok := (*params)[key] if ok { @@ -51,8 +108,12 @@ func (j AlertPayload) setRawMessageValue(variable *json.RawMessage, key string, } } +func deserializeSlice(str string) []string { + return strings.Split(str, ",") +} + // NewAlertPayload instantiates AlertPayload -func NewAlertPayload(message string, config *Config, params *types.Params) AlertPayload { +func NewAlertPayload(message string, config *Config, params *types.Params) (AlertPayload, error) { if params == nil { params = &types.Params{} } @@ -62,10 +123,10 @@ func NewAlertPayload(message string, config *Config, params *types.Params) Alert // Populate with values from the query string as defaults Alias: config.Alias, Description: config.Description, - Responders: json.RawMessage(config.Responders), - VisibleTo: json.RawMessage(config.VisibleTo), - Actions: json.RawMessage(config.Actions), - Tags: json.RawMessage(config.Tags), + Responders: config.Responders, + VisibleTo: config.VisibleTo, + Actions: config.Actions, + Tags: config.Tags, Details: json.RawMessage(config.Details), Entity: config.Entity, Source: config.Source, @@ -74,19 +135,44 @@ func NewAlertPayload(message string, config *Config, params *types.Params) Alert Note: config.Note, } - // If specified, overwrite the values from the query string - result.setStringValue(&result.Alias, "alias", params) - result.setStringValue(&result.Description, "description", params) - result.setRawMessageValue(&result.Responders, "responders", params) - result.setRawMessageValue(&result.VisibleTo, "visibleTo", params) - result.setRawMessageValue(&result.Actions, "actions", params) - result.setRawMessageValue(&result.Tags, "tags", params) - result.setRawMessageValue(&result.Details, "details", params) - result.setStringValue(&result.Entity, "entity", params) - result.setStringValue(&result.Source, "source", params) - result.setStringValue(&result.Priority, "priority", params) - result.setStringValue(&result.User, "user", params) - result.setStringValue(&result.Note, "note", params) - - return result + for key, value := range *params { + var err error + + switch key { + case "alias": + result.Alias = value + case "description": + result.Description = value + case "responders": + result.Responders, err = deserializeEntities(value) + case "visibleTo": + result.VisibleTo, err = deserializeEntities(value) + case "actions": + result.Actions = deserializeSlice(value) + case "tags": + result.Tags = deserializeSlice(value) + case "details": + // TODO + result.Details = json.RawMessage(value) + case "entity": + result.Entity = value + case "source": + result.Source = value + case "priority": + result.Priority = value + case "user": + result.User = value + case "note": + result.Note = value + default: + return result, fmt.Errorf("unknown config key: %q", key) + } + + if err != nil { + return result, err + } + + } + + return result, nil } diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index ef09f05d..37f320ac 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -29,13 +29,19 @@ func TestOpsGenie(t *testing.T) { var _ = Describe("the OpsGenie service", func() { var ( - mockServer *httptest.Server - mockQuery map[string]string - service *Service + // a simulated http server to mock out OpsGenie itself + mockServer *httptest.Server + // the host of our mock server + mockHost string + // function to check if the http request received by the mock server is as expected checkRequest func(body string, header http.Header) + // the shoutrrr OpsGenie service + service *Service + // just a mock logger + mockLogger *log.Logger ) - JustBeforeEach(func() { + BeforeEach(func() { // Initialize a mock http server httpHandler := func(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) @@ -49,140 +55,125 @@ var _ = Describe("the OpsGenie service", func() { // Our mock server doesn't have a valid cert http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - // Building a mock URL. - // It'll look something like: opsgenie://127.0.0.1:63457/eb243592-faa2-4ba2-a551q-1afdf565c889 + // Determine the host of our mock http server mockServerURL, err := url.Parse(mockServer.URL) Expect(err).To(BeNil()) - mockURL, err := url.Parse(fmt.Sprintf("opsgenie://%s/%s", mockServerURL.Host, mockAPIKey)) - tmpQuery := mockURL.Query() - for key, value := range mockQuery { - tmpQuery.Add(key, value) - } - mockURL.RawQuery = tmpQuery.Encode() - Expect(err).To(BeNil()) + mockHost = mockServerURL.Host // Initialize a mock logger var buf bytes.Buffer - logger := log.New(&buf, "", 0) - - // Initialize the OpsGenie service - service = &Service{} - err = service.Initialize(mockURL, logger) - Expect(err).To(BeNil()) + mockLogger = log.New(&buf, "", 0) }) - JustAfterEach(func() { + AfterEach(func() { mockServer.Close() }) - It("should send an alert", func() { - checkRequest = func(body string, header http.Header) { - Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) - Expect(header["Content-Type"][0]).To(Equal("application/json")) - Expect(body).To(Equal(`{"message":"hello world"}`)) - } + Context("without query parameters", func() { + BeforeEach(func() { + // Initialize service + serviceURL, err := url.Parse(fmt.Sprintf("opsgenie://%s/%s", mockHost, mockAPIKey)) + Expect(err).To(BeNil()) - err := service.Send("hello world", &types.Params{}) - Expect(err).To(BeNil()) - }) + service = &Service{} + err = service.Initialize(serviceURL, mockLogger) + Expect(err).To(BeNil()) + }) - When("provided nil params", func() { - It("should send an alert without additional fields", func() { - checkRequest = func(body string, header http.Header) { - Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) - Expect(header["Content-Type"][0]).To(Equal("application/json")) - Expect(body).To(Equal(`{"message":"hello world"}`)) - } + When("sending a simple alert", func() { + It("should send a request to our mock OpsGenie server", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"message":"hello world"}`)) + } - err := service.Send("hello world", nil) - Expect(err).To(BeNil()) + err := service.Send("hello world", &types.Params{}) + Expect(err).To(BeNil()) + }) }) - }) - When("provided parameters", func() { - It("should send an alert with all fields populated from parameters", func() { - checkRequest = func(body string, header http.Header) { - Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) - Expect(header["Content-Type"][0]).To(Equal("application/json")) - Expect(body).To(Equal(`{"` + - `message":"An example alert message",` + - `"alias":"Life is too short for no alias",` + - `"description":"Every alert needs a description",` + - `"responders":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}],` + - `"visibleTo":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}],` + - `"actions":["action1","action2"],` + - `"tags":["tag1","tag2"],` + - `"details":{"key1":"value1","key2":"value2"},` + - `"entity":"An example entity",` + - `"source":"The source",` + - `"priority":"P1",` + - `"user":"Dracula",` + - `"note":"Here is a note"` + - `}`)) - } + When("sending an alert with runtime parameters", func() { + It("should send a request to our mock OpsGenie server with all fields populated from runtime parameters", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"` + + `message":"An example alert message",` + + `"alias":"Life is too short for no alias",` + + `"description":"Every alert needs a description",` + + `"responders":[{"type":"team","id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c"},{"type":"team","name":"NOC"},{"type":"user","username":"Donald"},{"type":"user","id":"696f0759-3b0f-4a15-b8c8-19d3dfca33f2"}],` + + `"visibleTo":[{"type":"team","name":"rocket"}],` + + `"actions":["action1","action2"],` + + `"tags":["tag1","tag2"],` + + `"details":{"key1":"value1","key2":"value2"},` + + `"entity":"An example entity",` + + `"source":"The source",` + + `"priority":"P1",` + + `"user":"Dracula",` + + `"note":"Here is a note"` + + `}`)) + } - err := service.Send("An example alert message", &types.Params{ - "alias": "Life is too short for no alias", - "description": "Every alert needs a description", - "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, - "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, - "actions": `["action1", "action2"]`, - "tags": `["tag1", "tag2"]`, - "details": `{"key1": "value1", "key2": "value2"}`, - "entity": "An example entity", - "source": "The source", - "priority": "P1", - "user": "Dracula", - "note": "Here is a note", + err := service.Send("An example alert message", &types.Params{ + "alias": "Life is too short for no alias", + "description": "Every alert needs a description", + "responders": "team:4513b7ea-3b91-438f-b7e4-e3e54af9147c,team:NOC,user:Donald,user:696f0759-3b0f-4a15-b8c8-19d3dfca33f2", + "visibleTo": "team:rocket", + "actions": "action1,action2", + "tags": "tag1,tag2", + "details": `{"key1": "value1", "key2": "value2"}`, + "entity": "An example entity", + "source": "The source", + "priority": "P1", + "user": "Dracula", + "note": "Here is a note", + }) + Expect(err).To(BeNil()) }) - Expect(err).To(BeNil()) }) }) - When("provided query fields", func() { + Context("with query parameters", func() { BeforeEach(func() { - mockQuery = map[string]string{} - mockQuery["alias"] = "query-alias" - mockQuery["description"] = "query-description" - mockQuery["responders"] = `[{"name": "query_team", "type": "team"}]` - mockQuery["visibleTo"] = `[{"username": "query_user", "type": "user"}]` - mockQuery["actions"] = `["queryAction1", "queryAction2"]` - mockQuery["tags"] = `["queryTag1", "queryTag2"]` - mockQuery["details"] = `{"queryKey1": "queryValue1", "queryKey2": "queryValue2"}` - mockQuery["entity"] = "query-entity" - mockQuery["source"] = "query-source" - mockQuery["priority"] = "P2" - mockQuery["user"] = "query-user" - mockQuery["note"] = "query-note" + // Initialize service + serviceURL, err := url.Parse(fmt.Sprintf(`opsgenie://%s/%s?alias=query-alias&description=query-description&responders=team:query_team&visibleTo=user:query_user&actions=queryAction1,queryAction2&tags=queryTag1,queryTag2&details={"queryKey1": "queryValue1", "queryKey2": "queryValue2"}&entity=query-entity&source=query-source&priority=P2&user=query-user¬e=query-note`, mockHost, mockAPIKey)) + Expect(err).To(BeNil()) + + service = &Service{} + err = service.Initialize(serviceURL, mockLogger) + Expect(err).To(BeNil()) }) - It("should send an alert with all fields populated from query fields", func() { - checkRequest = func(body string, header http.Header) { - Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) - Expect(header["Content-Type"][0]).To(Equal("application/json")) - Expect(body).To(Equal(`{"` + - `message":"An example alert message",` + - `"alias":"query-alias",` + - `"description":"query-description",` + - `"responders":[{"name":"query_team","type":"team"}],` + - `"visibleTo":[{"username":"query_user","type":"user"}],` + - `"actions":["queryAction1","queryAction2"],` + - `"tags":["queryTag1","queryTag2"],` + - `"details":{"queryKey1":"queryValue1","queryKey2":"queryValue2"},` + - `"entity":"query-entity",` + - `"source":"query-source",` + - `"priority":"P2",` + - `"user":"query-user",` + - `"note":"query-note"` + - `}`)) - } + When("sending a simple alert", func() { + It("should send a request to our mock OpsGenie server with all fields populated from query parameters", func() { + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{` + + `"message":"An example alert message",` + + `"alias":"query-alias",` + + `"description":"query-description",` + + `"responders":[{"type":"team","name":"query_team"}],` + + `"visibleTo":[{"type":"user","username":"query_user"}],` + + `"actions":["queryAction1","queryAction2"],` + + `"tags":["queryTag1","queryTag2"],` + + `"details":{"queryKey1":"queryValue1","queryKey2":"queryValue2"},` + + `"entity":"query-entity",` + + `"source":"query-source",` + + `"priority":"P2",` + + `"user":"query-user",` + + `"note":"query-note"` + + `}`)) + } - err := service.Send("An example alert message", &types.Params{}) - Expect(err).To(BeNil()) + err := service.Send("An example alert message", &types.Params{}) + Expect(err).To(BeNil()) + }) }) - When("provided query fields and parameters", func() { - It("should send an alert with all fields populated from parameters, overwriting the query fields", func() { + When("sending an alert with runtime parameters", func() { + It("should send a request to our mock OpsGenie server with all fields populated from runtime parameters, overwriting the query parameters", func() { checkRequest = func(body string, header http.Header) { Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) Expect(header["Content-Type"][0]).To(Equal("application/json")) @@ -190,8 +181,8 @@ var _ = Describe("the OpsGenie service", func() { `message":"An example alert message",` + `"alias":"Life is too short for no alias",` + `"description":"Every alert needs a description",` + - `"responders":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}],` + - `"visibleTo":[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}],` + + `"responders":[{"type":"team","id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c"},{"type":"team","name":"NOC"},{"type":"user","username":"Donald"},{"type":"user","id":"696f0759-3b0f-4a15-b8c8-19d3dfca33f2"}],` + + `"visibleTo":[{"type":"team","name":"rocket"}],` + `"actions":["action1","action2"],` + `"tags":["tag1","tag2"],` + `"details":{"key1":"value1","key2":"value2"},` + @@ -206,10 +197,10 @@ var _ = Describe("the OpsGenie service", func() { err := service.Send("An example alert message", &types.Params{ "alias": "Life is too short for no alias", "description": "Every alert needs a description", - "responders": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"NOC","type":"team"}]`, - "visibleTo": `[{"id":"4513b7ea-3b91-438f-b7e4-e3e54af9147c","type":"team"},{"name":"rocket_team","type":"team"}]`, - "actions": `["action1", "action2"]`, - "tags": `["tag1", "tag2"]`, + "responders": "team:4513b7ea-3b91-438f-b7e4-e3e54af9147c,team:NOC,user:Donald,user:696f0759-3b0f-4a15-b8c8-19d3dfca33f2", + "visibleTo": "team:rocket", + "actions": "action1,action2", + "tags": "tag1,tag2", "details": `{"key1": "value1", "key2": "value2"}`, "entity": "An example entity", "source": "The source", @@ -224,7 +215,7 @@ var _ = Describe("the OpsGenie service", func() { }) var _ = Describe("the OpsGenie Config struct", func() { - When("provided with a simple URL", func() { + When("generating a config from a simple URL", func() { It("should populate the config with host and apikey", func() { url, err := url.Parse(fmt.Sprintf("opsgenie://%s/%s", mockHost, mockAPIKey)) Expect(err).To(BeNil()) @@ -239,7 +230,7 @@ var _ = Describe("the OpsGenie Config struct", func() { }) }) - When("provided with an URL with port", func() { + When("generating a config from a url with port", func() { It("should populate the port field", func() { url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s", mockHost, mockAPIKey)) Expect(err).To(BeNil()) @@ -252,9 +243,9 @@ var _ = Describe("the OpsGenie Config struct", func() { }) }) - When("provided with an URL and query parameters", func() { + When("generating a config from a url with query parameters", func() { It("should populate the relevant fields with the query parameter values", func() { - queryParams := `alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&actions=["An+action"]&tags=["tag1","tag2"]&details=these+are+details&entity=An+example+entity&source=The+source&priority=P1&user=Dracula¬e=Here+is+a+note` + queryParams := `alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&actions=An+action&tags=tag1,tag2&details=these+are+details&entity=An+example+entity&source=The+source&priority=P1&user=Dracula¬e=Here+is+a+note&responders=user:Test,team:NOC&visibleTo=user:A+User` url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s?%s", mockHost, mockAPIKey, queryParams)) Expect(err).To(BeNil()) @@ -264,11 +255,15 @@ var _ = Describe("the OpsGenie Config struct", func() { Expect(config.Alias).To(Equal("Life is too short for no alias")) Expect(config.Description).To(Equal("Every alert needs a description")) - //TODO - //Responders json.RawMessage `json:"responders,omitempty"` - //VisibleTo json.RawMessage `json:"visibleTo,omitempty"` - Expect(config.Actions).To(Equal(`["An action"]`)) - Expect(config.Tags).To(Equal(`["tag1","tag2"]`)) + Expect(config.Responders).To(Equal([]Entity{ + {Type: "user", Username: "Test"}, + {Type: "team", Name: "NOC"}, + })) + Expect(config.VisibleTo).To(Equal([]Entity{ + {Type: "user", Username: "A User"}, + })) + Expect(config.Actions).To(Equal([]string{"An action"})) + Expect(config.Tags).To(Equal([]string{"tag1", "tag2"})) Expect(config.Details).To(Equal("these are details")) Expect(config.Entity).To(Equal("An example entity")) Expect(config.Source).To(Equal("The source")) @@ -279,15 +274,61 @@ var _ = Describe("the OpsGenie Config struct", func() { }) }) - When("provided with an URL and an invalid query parameter", func() { - It("should return an error", func() { - queryParams := `invalid=value` - url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s?%s", mockHost, mockAPIKey, queryParams)) + When("generating a url from a simple config", func() { + It("should generate a url", func() { + config := Config{ + Host: "api.opsgenie.com", + ApiKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", + } - config := Config{} - err = config.SetURL(url) + url := config.GetURL() + + Expect(url.String()).To(Equal("opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889")) + }) + }) + + When("generating a url from a config with a port", func() { + It("should generate a url with port", func() { + config := Config{ + Host: "api.opsgenie.com", + ApiKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", + Port: 12345, + } + + url := config.GetURL() + + Expect(url.String()).To(Equal("opsgenie://api.opsgenie.com:12345/eb243592-faa2-4ba2-a551q-1afdf565c889")) + }) + }) + + When("generating a url from a config with all optional config fields", func() { + It("should generate a url with query parameters", func() { + config := Config{ + Host: "api.opsgenie.com", + ApiKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", + Alias: "Life is too short for no alias", + Description: "Every alert needs a description", + Responders: []Entity{ + {Type: "user", Username: "Test"}, + {Type: "team", Name: "NOC"}, + }, + VisibleTo: []Entity{ + {Type: "user", Username: "A User"}, + }, + Actions: []string{"action1", "action2"}, + Tags: []string{"tag1", "tag2"}, + Details: "these are details", + Entity: "An example entity", + Source: "The source", + Priority: "P1", + User: "Dracula", + Note: "Here is a note", + } - Expect(err).NotTo(BeNil()) + url := config.GetURL() + fmt.Println(url.String()) + //&responders=user:Test,team:NOC&visibleTo=user:A+User + Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1,action2&alias=Life is too short for no alias&description=Every alert needs a description&details=these are details&entity=An example entity¬e=Here is a note&priority=P1&source=The source&tags=tag1,tag2&user=Dracula`)) }) }) }) From 5cb1ad378a4e8b94073cc51ae77c09781f6c0582 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 26 Jan 2021 21:18:03 +0000 Subject: [PATCH 17/32] Use 'key:value,key2:value2' format for details and overall code cleanup --- cli/cmd/send/send.go | 2 +- pkg/format/formatter.go | 42 ++++++++- pkg/services/opsgenie/opsgenie.go | 3 +- pkg/services/opsgenie/opsgenie_config.go | 59 ++++++------ pkg/services/opsgenie/opsgenie_json.go | 113 +++++++---------------- pkg/services/opsgenie/opsgenie_test.go | 20 ++-- 6 files changed, 116 insertions(+), 123 deletions(-) diff --git a/cli/cmd/send/send.go b/cli/cmd/send/send.go index da791a36..efa2181c 100644 --- a/cli/cmd/send/send.go +++ b/cli/cmd/send/send.go @@ -9,8 +9,8 @@ import ( cli "github.com/containrrr/shoutrrr/cli/cmd" u "github.com/containrrr/shoutrrr/internal/util" - "github.com/containrrr/shoutrrr/pkg/types" "github.com/containrrr/shoutrrr/pkg/router" + "github.com/containrrr/shoutrrr/pkg/types" "github.com/containrrr/shoutrrr/pkg/util" ) diff --git a/pkg/format/formatter.go b/pkg/format/formatter.go index 7b58a852..06976ef9 100644 --- a/pkg/format/formatter.go +++ b/pkg/format/formatter.go @@ -324,7 +324,7 @@ func SetConfigField(config reflect.Value, field FieldInfo, inputValue string) (v configField.SetBool(value) return true, nil - } else if fieldKind >= reflect.Slice { + } else if fieldKind == reflect.Slice { elemKind := field.Type.Elem().Kind() if elemKind != reflect.String { return false, errors.New("field format is not supported") @@ -334,6 +334,30 @@ func SetConfigField(config reflect.Value, field FieldInfo, inputValue string) (v configField.Set(reflect.ValueOf(values)) return true, nil + } else if fieldKind == reflect.Map { + keyKind := field.Type.Key().Kind() + elemKind := field.Type.Elem().Kind() + if elemKind != reflect.String || keyKind != reflect.String { + return false, errors.New("field format is not supported") + } + + newMap := make(map[string]string) + + pairs := strings.Split(inputValue, ",") + for _, pair := range pairs { + elems := strings.Split(pair, ":") + if len(elems) != 2 { + return false, errors.New("field format is not supported") + } + key := elems[0] + value := elems[1] + + newMap[key] = value + } + + configField.Set(reflect.ValueOf(newMap)) + return true, nil + } return false, nil @@ -354,7 +378,7 @@ func GetConfigFieldString(config reflect.Value, field FieldInfo) (value string, return strconv.FormatInt(configField.Int(), 10), nil } else if fieldKind == reflect.Bool { return PrintBool(configField.Bool()), nil - } else if fieldKind >= reflect.Slice { + } else if fieldKind == reflect.Slice { sliceLen := configField.Len() sliceValue := configField.Slice(0, sliceLen) if field.Type.Elem().Kind() != reflect.String { @@ -362,6 +386,20 @@ func GetConfigFieldString(config reflect.Value, field FieldInfo) (value string, } slice := sliceValue.Interface().([]string) return strings.Join(slice, ","), nil + } else if fieldKind == reflect.Map { + keyKind := field.Type.Key().Kind() + elemKind := field.Type.Elem().Kind() + if elemKind != reflect.String || keyKind != reflect.String { + return "", errors.New("field format is not supported") + } + + kvPairs := []string{} + for _, key := range configField.MapKeys() { + value := configField.MapIndex(key).Interface() + + kvPairs = append(kvPairs, fmt.Sprintf("%s:%s", key, value)) + } + return strings.Join(kvPairs, ","), nil } return "", fmt.Errorf("field kind %x is not supported", fieldKind) diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index aa1d6747..d1f623e8 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -58,8 +58,7 @@ func (service *Service) sendAlert(url string, apiKey string, payload AlertPayloa func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error { service.Logger.SetLogger(logger) service.config = &Config{} - err := service.config.SetURL(configURL) - return err + return service.config.SetURL(configURL) } // Send a notification message to OpsGenie diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index d0a19110..86a036ac 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -11,21 +11,21 @@ import ( // Config for use within the opsgenie service type Config struct { - ApiKey string `desc:"The OpsGenie API key"` - Host string `desc:"The OpsGenie API host. Use 'api.eu.opsgenie.com' for EU instances" default:"api.opsgenie.com"` - Port uint16 `desc:"The OpsGenie API port." default:"443"` - Alias string `key:"alias" desc:"Client-defined identifier of the alert" optional:"true"` - Description string `key:"description" desc:"Description field of the alert" optional:"true"` - Responders []Entity `key:"responders" desc:"Teams, users, escalations and schedules that the alert will be routed to send notifications" optional:"true"` - VisibleTo []Entity `key:"visibleTo" desc:"Teams and users that the alert will become visible to without sending any notification" optional:"true"` - Actions []string `key:"actions" desc:"Custom actions that will be available for the alert" optional:"true"` - Tags []string `key:"tags" desc:"Tags of the alert" optional:"true"` - Details string `key:"details" desc:"Map of key-value pairs to use as custom properties of the alert" optional:"true"` - Entity string `key:"entity" desc:"Entity field of the alert that is generally used to specify which domain the Source field of the alert" optional:"true"` - Source string `key:"source" desc:"Source field of the alert" optional:"true"` - Priority string `key:"priority" desc:"Priority level of the alert. Possible values are P1, P2, P3, P4 and P5" optional:"true"` - Note string `key:"note" desc:"Additional note that will be added while creating the alert" optional:"true"` - User string `key:"user" desc:"Display name of the request owner" optional:"true"` + ApiKey string `desc:"The OpsGenie API key"` + Host string `desc:"The OpsGenie API host. Use 'api.eu.opsgenie.com' for EU instances" default:"api.opsgenie.com"` + Port uint16 `desc:"The OpsGenie API port." default:"443"` + Alias string `key:"alias" desc:"Client-defined identifier of the alert" optional:"true"` + Description string `key:"description" desc:"Description field of the alert" optional:"true"` + Responders []Entity `key:"responders" desc:"Teams, users, escalations and schedules that the alert will be routed to send notifications" optional:"true"` + VisibleTo []Entity `key:"visibleTo" desc:"Teams and users that the alert will become visible to without sending any notification" optional:"true"` + Actions []string `key:"actions" desc:"Custom actions that will be available for the alert" optional:"true"` + Tags []string `key:"tags" desc:"Tags of the alert" optional:"true"` + Details map[string]string `key:"details" desc:"Map of key-value pairs to use as custom properties of the alert" optional:"true"` + Entity string `key:"entity" desc:"Entity field of the alert that is generally used to specify which domain the Source field of the alert" optional:"true"` + Source string `key:"source" desc:"Source field of the alert" optional:"true"` + Priority string `key:"priority" desc:"Priority level of the alert. Possible values are P1, P2, P3, P4 and P5" optional:"true"` + Note string `key:"note" desc:"Additional note that will be added while creating the alert" optional:"true"` + User string `key:"user" desc:"Display name of the request owner" optional:"true"` } func (config Config) Enums() map[string]types.EnumFormatter { @@ -47,26 +47,31 @@ func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL { host = config.Host } - result := &url.URL{ - Host: host, - Path: fmt.Sprintf("/%s", config.ApiKey), - Scheme: Scheme, - RawQuery: format.BuildQuery(resolver), + // Serialize Shoutrrr standard data types + rawQuery := format.BuildQuery(resolver) + + // Serialize OpsGenie specific data types + separator := "&" + if rawQuery == "" { + separator = "" } - // Add OpsGenie specific data types - q := result.Query() if len(config.Responders) > 0 { - // TODO: Error handling responders, _ := serializeEntities(config.Responders) - q.Set("responders", responders) + rawQuery = rawQuery + separator + "responders=" + responders + separator = "&" } if len(config.VisibleTo) > 0 { - // TODO: Error handling visibleTo, _ := serializeEntities(config.VisibleTo) - q.Set("visibleTo", visibleTo) + rawQuery = rawQuery + separator + "visibleTo=" + visibleTo + } + + result := &url.URL{ + Host: host, + Path: fmt.Sprintf("/%s", config.ApiKey), + Scheme: Scheme, + RawQuery: rawQuery, } - result.RawQuery = q.Encode() return result } diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go index a3505542..13c750c1 100644 --- a/pkg/services/opsgenie/opsgenie_json.go +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -1,7 +1,6 @@ package opsgenie import ( - "encoding/json" "fmt" "strings" @@ -25,91 +24,43 @@ import ( // "details": `{"key1": "value1", "key2": "value2"}`, // }) type AlertPayload struct { - Message string `json:"message"` - Alias string `json:"alias,omitempty"` - Description string `json:"description,omitempty"` - Responders []Entity `json:"responders,omitempty"` - VisibleTo []Entity `json:"visibleTo,omitempty"` - Actions []string `json:"actions,omitempty"` - Tags []string `json:"tags,omitempty"` - Details json.RawMessage `json:"details,omitempty"` - Entity string `json:"entity,omitempty"` - Source string `json:"source,omitempty"` - Priority string `json:"priority,omitempty"` - User string `json:"user,omitempty"` - Note string `json:"note,omitempty"` + Message string `json:"message"` + Alias string `json:"alias,omitempty"` + Description string `json:"description,omitempty"` + Responders []Entity `json:"responders,omitempty"` + VisibleTo []Entity `json:"visibleTo,omitempty"` + Actions []string `json:"actions,omitempty"` + Tags []string `json:"tags,omitempty"` + Details map[string]string `json:"details,omitempty"` + Entity string `json:"entity,omitempty"` + Source string `json:"source,omitempty"` + Priority string `json:"priority,omitempty"` + User string `json:"user,omitempty"` + Note string `json:"note,omitempty"` } -// TODO: Refactor all set*Value methods into one -func (j AlertPayload) setEntityValue(variable *[]Entity, key string, params *types.Params) { - paramValue, ok := (*params)[key] - if ok { - entityStrings := strings.Split(paramValue, ",") - for _, entityStr := range entityStrings { - elements := strings.Split(entityStr, ":") - - // TODO: Error handling - entityType := elements[0] - identifier := elements[1] - - entity := Entity{ - Type: entityType, - } - - isID, err := isOpsGenieID(identifier) - if err != nil { - // TODO: Error handling - } - - if isID { - entity.ID = identifier - } else if entityType == "team" { - entity.Name = identifier - } else if entityType == "user" { - entity.Username = identifier - } else { - // TODO: Error handling - } - - *variable = append(*variable, entity) - } - } -} - -func (j AlertPayload) setStringValue(variable *string, key string, params *types.Params) { - paramValue, ok := (*params)[key] - if ok { - *variable = paramValue - } +// TODO: Duplicated code, see: formatter.go +func deserializeSlice(str string) []string { + return strings.Split(str, ",") } -func (j AlertPayload) setConfigValue(variable *string, key string, params *types.Params) { - paramValue, ok := (*params)[key] - if ok { - *variable = paramValue - } -} +// TODO: Duplicated code, see: formatter.go +func deserializeMap(str string) (map[string]string, error) { + result := make(map[string]string) -// Splits a parameter string at the comma and assigns it to a slice variable -// -// TODO: This is somewhat of a duplication of the code in formatter.go#SetConfigField - is there a better way? -func (j AlertPayload) setSliceValues(variable *[]string, key string, params *types.Params) { - paramValue, ok := (*params)[key] - if ok { - *variable = strings.Split(paramValue, ",") - } -} + pairs := strings.Split(str, ",") + for _, pair := range pairs { + elems := strings.Split(pair, ":") + if len(elems) != 2 { + return result, fmt.Errorf("field format is not supported") + } + key := elems[0] + value := elems[1] -// TODO -func (j AlertPayload) setRawMessageValue(variable *json.RawMessage, key string, params *types.Params) { - paramValue, ok := (*params)[key] - if ok { - *variable = json.RawMessage(paramValue) + result[key] = value } -} -func deserializeSlice(str string) []string { - return strings.Split(str, ",") + return result, nil } // NewAlertPayload instantiates AlertPayload @@ -127,7 +78,7 @@ func NewAlertPayload(message string, config *Config, params *types.Params) (Aler VisibleTo: config.VisibleTo, Actions: config.Actions, Tags: config.Tags, - Details: json.RawMessage(config.Details), + Details: config.Details, Entity: config.Entity, Source: config.Source, Priority: config.Priority, @@ -135,6 +86,7 @@ func NewAlertPayload(message string, config *Config, params *types.Params) (Aler Note: config.Note, } + // Populate with values from runtime parameters for key, value := range *params { var err error @@ -152,8 +104,7 @@ func NewAlertPayload(message string, config *Config, params *types.Params) (Aler case "tags": result.Tags = deserializeSlice(value) case "details": - // TODO - result.Details = json.RawMessage(value) + result.Details, err = deserializeMap(value) case "entity": result.Entity = value case "source": diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index 37f320ac..2069e1b1 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -122,7 +122,7 @@ var _ = Describe("the OpsGenie service", func() { "visibleTo": "team:rocket", "actions": "action1,action2", "tags": "tag1,tag2", - "details": `{"key1": "value1", "key2": "value2"}`, + "details": "key1:value1,key2:value2", "entity": "An example entity", "source": "The source", "priority": "P1", @@ -137,7 +137,7 @@ var _ = Describe("the OpsGenie service", func() { Context("with query parameters", func() { BeforeEach(func() { // Initialize service - serviceURL, err := url.Parse(fmt.Sprintf(`opsgenie://%s/%s?alias=query-alias&description=query-description&responders=team:query_team&visibleTo=user:query_user&actions=queryAction1,queryAction2&tags=queryTag1,queryTag2&details={"queryKey1": "queryValue1", "queryKey2": "queryValue2"}&entity=query-entity&source=query-source&priority=P2&user=query-user¬e=query-note`, mockHost, mockAPIKey)) + serviceURL, err := url.Parse(fmt.Sprintf(`opsgenie://%s/%s?alias=query-alias&description=query-description&responders=team:query_team&visibleTo=user:query_user&actions=queryAction1,queryAction2&tags=queryTag1,queryTag2&details=queryKey1:queryValue1,queryKey2:queryValue2&entity=query-entity&source=query-source&priority=P2&user=query-user¬e=query-note`, mockHost, mockAPIKey)) Expect(err).To(BeNil()) service = &Service{} @@ -201,7 +201,7 @@ var _ = Describe("the OpsGenie service", func() { "visibleTo": "team:rocket", "actions": "action1,action2", "tags": "tag1,tag2", - "details": `{"key1": "value1", "key2": "value2"}`, + "details": "key1:value1,key2:value2", "entity": "An example entity", "source": "The source", "priority": "P1", @@ -244,8 +244,8 @@ var _ = Describe("the OpsGenie Config struct", func() { }) When("generating a config from a url with query parameters", func() { - It("should populate the relevant fields with the query parameter values", func() { - queryParams := `alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&actions=An+action&tags=tag1,tag2&details=these+are+details&entity=An+example+entity&source=The+source&priority=P1&user=Dracula¬e=Here+is+a+note&responders=user:Test,team:NOC&visibleTo=user:A+User` + It("should populate the config fields with the query parameter values", func() { + queryParams := `alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&actions=An+action&tags=tag1,tag2&details=key:value,key2:value2&entity=An+example+entity&source=The+source&priority=P1&user=Dracula¬e=Here+is+a+note&responders=user:Test,team:NOC&visibleTo=user:A+User` url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s?%s", mockHost, mockAPIKey, queryParams)) Expect(err).To(BeNil()) @@ -264,7 +264,7 @@ var _ = Describe("the OpsGenie Config struct", func() { })) Expect(config.Actions).To(Equal([]string{"An action"})) Expect(config.Tags).To(Equal([]string{"tag1", "tag2"})) - Expect(config.Details).To(Equal("these are details")) + Expect(config.Details).To(Equal(map[string]string{"key": "value", "key2": "value2"})) Expect(config.Entity).To(Equal("An example entity")) Expect(config.Source).To(Equal("The source")) Expect(config.Priority).To(Equal("P1")) @@ -311,13 +311,14 @@ var _ = Describe("the OpsGenie Config struct", func() { Responders: []Entity{ {Type: "user", Username: "Test"}, {Type: "team", Name: "NOC"}, + {Type: "team", ID: "4513b7ea-3b91-438f-b7e4-e3e54af9147c"}, }, VisibleTo: []Entity{ {Type: "user", Username: "A User"}, }, Actions: []string{"action1", "action2"}, Tags: []string{"tag1", "tag2"}, - Details: "these are details", + Details: map[string]string{"key": "value"}, Entity: "An example entity", Source: "The source", Priority: "P1", @@ -326,9 +327,8 @@ var _ = Describe("the OpsGenie Config struct", func() { } url := config.GetURL() - fmt.Println(url.String()) - //&responders=user:Test,team:NOC&visibleTo=user:A+User - Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1,action2&alias=Life is too short for no alias&description=Every alert needs a description&details=these are details&entity=An example entity¬e=Here is a note&priority=P1&source=The source&tags=tag1,tag2&user=Dracula`)) + // TODO: An URL can not use space https://stackoverflow.com/questions/5442658/spaces-in-urls + Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1,action2&alias=Life is too short for no alias&description=Every alert needs a description&details=key:value&entity=An example entity¬e=Here is a note&priority=P1&source=The source&tags=tag1,tag2&user=Dracula&responders=user:Test,team:NOC,team:4513b7ea-3b91-438f-b7e4-e3e54af9147c&visibleTo=user:A User`)) }) }) }) From 584deee257bfda987fbb94c8650b153f1c8a04de Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 2 Feb 2021 21:19:42 +0000 Subject: [PATCH 18/32] Remove comment about spaces in URL --- pkg/services/opsgenie/opsgenie_json.go | 112 ++++++++----------------- pkg/services/opsgenie/opsgenie_test.go | 68 +++++++++++++++ 2 files changed, 102 insertions(+), 78 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go index 13c750c1..8e865d83 100644 --- a/pkg/services/opsgenie/opsgenie_json.go +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -1,9 +1,7 @@ package opsgenie import ( - "fmt" - "strings" - + "github.com/containrrr/shoutrrr/pkg/format" "github.com/containrrr/shoutrrr/pkg/types" ) @@ -39,91 +37,49 @@ type AlertPayload struct { Note string `json:"note,omitempty"` } -// TODO: Duplicated code, see: formatter.go -func deserializeSlice(str string) []string { - return strings.Split(str, ",") -} - -// TODO: Duplicated code, see: formatter.go -func deserializeMap(str string) (map[string]string, error) { - result := make(map[string]string) - - pairs := strings.Split(str, ",") - for _, pair := range pairs { - elems := strings.Split(pair, ":") - if len(elems) != 2 { - return result, fmt.Errorf("field format is not supported") - } - key := elems[0] - value := elems[1] - - result[key] = value - } - - return result, nil -} - -// NewAlertPayload instantiates AlertPayload func NewAlertPayload(message string, config *Config, params *types.Params) (AlertPayload, error) { if params == nil { params = &types.Params{} } - result := AlertPayload{ - Message: message, - // Populate with values from the query string as defaults - Alias: config.Alias, - Description: config.Description, - Responders: config.Responders, - VisibleTo: config.VisibleTo, - Actions: config.Actions, - Tags: config.Tags, - Details: config.Details, - Entity: config.Entity, - Source: config.Source, - Priority: config.Priority, - User: config.User, - Note: config.Note, - } - - // Populate with values from runtime parameters - for key, value := range *params { - var err error + // Defensive copy + payloadFields := *config - switch key { - case "alias": - result.Alias = value - case "description": - result.Description = value - case "responders": - result.Responders, err = deserializeEntities(value) - case "visibleTo": - result.VisibleTo, err = deserializeEntities(value) - case "actions": - result.Actions = deserializeSlice(value) - case "tags": - result.Tags = deserializeSlice(value) - case "details": - result.Details, err = deserializeMap(value) - case "entity": - result.Entity = value - case "source": - result.Source = value - case "priority": - result.Priority = value - case "user": - result.User = value - case "note": - result.Note = value - default: - return result, fmt.Errorf("unknown config key: %q", key) + pkr := format.NewPropKeyResolver(&payloadFields) + if value, found := (*params)["responders"]; found { + responders, err := deserializeEntities(value) + if err != nil { + return AlertPayload{}, err } - + payloadFields.Responders = responders + delete(*params, "responders") + } + if value, found := (*params)["visibleTo"]; found { + visibleTo, err := deserializeEntities(value) if err != nil { - return result, err + return AlertPayload{}, err } - + payloadFields.VisibleTo = visibleTo + delete(*params, "visibleTo") + } + if err := pkr.UpdateConfigFromParams(&payloadFields, params); err != nil { + return AlertPayload{}, err } + result := AlertPayload{ + Message: message, + Alias: payloadFields.Alias, + Description: payloadFields.Description, + Responders: payloadFields.Responders, + VisibleTo: payloadFields.VisibleTo, + Actions: payloadFields.Actions, + Tags: payloadFields.Tags, + Details: payloadFields.Details, + Entity: payloadFields.Entity, + Source: payloadFields.Source, + Priority: payloadFields.Priority, + User: payloadFields.User, + Note: payloadFields.Note, + } return result, nil } diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index 2069e1b1..b6a6845c 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -211,6 +211,74 @@ var _ = Describe("the OpsGenie service", func() { Expect(err).To(BeNil()) }) }) + + When("sending two alerts", func() { + It("should not mix-up the runtime parameters and the query parameters", func() { + // Internally the opsgenie service copies runtime parameters into the config struct + // before generating the alert payload. This test ensures that none of the parameters + // from alert 1 remain in the config struct when sending alert 2 + // In short: This tests if we clone the config struct + + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{"` + + `message":"1",` + + `"alias":"1",` + + `"description":"1",` + + `"responders":[{"type":"team","name":"1"}],` + + `"visibleTo":[{"type":"team","name":"1"}],` + + `"actions":["action1","action2"],` + + `"tags":["tag1","tag2"],` + + `"details":{"key1":"value1","key2":"value2"},` + + `"entity":"1",` + + `"source":"1",` + + `"priority":"P1",` + + `"user":"1",` + + `"note":"1"` + + `}`)) + } + + err := service.Send("1", &types.Params{ + "alias": "1", + "description": "1", + "responders": "team:1", + "visibleTo": "team:1", + "actions": "action1,action2", + "tags": "tag1,tag2", + "details": "key1:value1,key2:value2", + "entity": "1", + "source": "1", + "priority": "P1", + "user": "1", + "note": "1", + }) + Expect(err).To(BeNil()) + + checkRequest = func(body string, header http.Header) { + Expect(header["Authorization"][0]).To(Equal("GenieKey " + mockAPIKey)) + Expect(header["Content-Type"][0]).To(Equal("application/json")) + Expect(body).To(Equal(`{` + + `"message":"2",` + + `"alias":"query-alias",` + + `"description":"query-description",` + + `"responders":[{"type":"team","name":"query_team"}],` + + `"visibleTo":[{"type":"user","username":"query_user"}],` + + `"actions":["queryAction1","queryAction2"],` + + `"tags":["queryTag1","queryTag2"],` + + `"details":{"queryKey1":"queryValue1","queryKey2":"queryValue2"},` + + `"entity":"query-entity",` + + `"source":"query-source",` + + `"priority":"P2",` + + `"user":"query-user",` + + `"note":"query-note"` + + `}`)) + } + + err = service.Send("2", nil) + Expect(err).To(BeNil()) + }) + }) }) }) From b16821154a71aa6efa91ca618b49707414ac53a2 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 2 Feb 2021 21:26:35 +0000 Subject: [PATCH 19/32] Remove comment about spaces; Add test instead --- pkg/services/opsgenie/opsgenie_test.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index b6a6845c..fe761bfd 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -342,6 +342,22 @@ var _ = Describe("the OpsGenie Config struct", func() { }) }) + When("generating a config from a url with differently escaped spaces", func() { + It("should parse the escaped spaces correctly", func() { + // Use: '%20', '+' and a normal space + queryParams := `alias=Life is+too%20short+for+no+alias` + url, err := url.Parse(fmt.Sprintf("opsgenie://%s:12345/%s?%s", mockHost, mockAPIKey, queryParams)) + Expect(err).To(BeNil()) + + config := Config{} + err = config.SetURL(url) + Expect(err).To(BeNil()) + + Expect(config.Alias).To(Equal("Life is too short for no alias")) + + }) + }) + When("generating a url from a simple config", func() { It("should generate a url", func() { config := Config{ @@ -395,7 +411,6 @@ var _ = Describe("the OpsGenie Config struct", func() { } url := config.GetURL() - // TODO: An URL can not use space https://stackoverflow.com/questions/5442658/spaces-in-urls Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1,action2&alias=Life is too short for no alias&description=Every alert needs a description&details=key:value&entity=An example entity¬e=Here is a note&priority=P1&source=The source&tags=tag1,tag2&user=Dracula&responders=user:Test,team:NOC,team:4513b7ea-3b91-438f-b7e4-e3e54af9147c&visibleTo=user:A User`)) }) }) From 59819e7187a578b3a60871a8721bb86ff5fc894d Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 11:14:22 +0000 Subject: [PATCH 20/32] Fix IFTTT test by removing obsolete values; Add another test for values --- pkg/services/ifttt/ifttt_test.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/services/ifttt/ifttt_test.go b/pkg/services/ifttt/ifttt_test.go index f91df427..03d6bc85 100644 --- a/pkg/services/ifttt/ifttt_test.go +++ b/pkg/services/ifttt/ifttt_test.go @@ -102,7 +102,7 @@ var _ = Describe("the ifttt package", func() { When("serializing a config to URL", func() { When("given multiple events", func() { It("should return an URL with all the events comma-separated", func() { - expectedURL := "ifttt://dummyID/?events=foo%2Cbar%2Cbaz&messagevalue=0&value1=&value2=&value3=" + expectedURL := "ifttt://dummyID/?events=foo%2Cbar%2Cbaz&messagevalue=0" config := Config{ Events: []string{"foo", "bar", "baz"}, WebHookID: "dummyID", @@ -112,6 +112,20 @@ var _ = Describe("the ifttt package", func() { Expect(resultURL).To(Equal(expectedURL)) }) }) + + When("given values", func() { + It("should return an URL with all the values", func() { + expectedURL := "ifttt://dummyID/?messagevalue=0&value1=v1&value2=v2&value3=v3" + config := Config{ + WebHookID: "dummyID", + Value1: "v1", + Value2: "v2", + Value3: "v3", + } + resultURL := config.GetURL().String() + Expect(resultURL).To(Equal(expectedURL)) + }) + }) }) When("sending a message", func() { It("should error if the response code is not 204 no content", func() { From d87e5d431b866e33fdccf8d8e3eb0501e127e4e0 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 11:37:10 +0000 Subject: [PATCH 21/32] Fix teams test by removing obsolete key without value --- pkg/services/teams/teams_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/teams/teams_test.go b/pkg/services/teams/teams_test.go index d1ab0858..fa32141b 100644 --- a/pkg/services/teams/teams_test.go +++ b/pkg/services/teams/teams_test.go @@ -87,7 +87,7 @@ var _ = Describe("the teams plugin", func() { serviceURL, err := service.GetConfigURLFromCustom(customURL) Expect(err).NotTo(HaveOccurred(), "converting") - Expect(serviceURL.String()).To(Equal(testURLBase + "?color=&host=publicservice.info&title=")) + Expect(serviceURL.String()).To(Equal(testURLBase + "?host=publicservice.info")) }) It("should preserve the query params in the generated service URL", func() { service := Service{} From 3145f46c559b1a5d3c04297049eed1ec554a3365 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 11:38:08 +0000 Subject: [PATCH 22/32] Fix OpsGenie test by using URL encoded strings for space, comma, colon --- pkg/services/opsgenie/opsgenie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index fe761bfd..dbed3384 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -411,7 +411,7 @@ var _ = Describe("the OpsGenie Config struct", func() { } url := config.GetURL() - Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1,action2&alias=Life is too short for no alias&description=Every alert needs a description&details=key:value&entity=An example entity¬e=Here is a note&priority=P1&source=The source&tags=tag1,tag2&user=Dracula&responders=user:Test,team:NOC,team:4513b7ea-3b91-438f-b7e4-e3e54af9147c&visibleTo=user:A User`)) + Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1%2Caction2&alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&details=key%3Avalue&entity=An+example+entity¬e=Here+is+a+note&priority=P1&source=The+source&tags=tag1%2Ctag2&user=Dracula&responders=user:Test,team:NOC,team:4513b7ea-3b91-438f-b7e4-e3e54af9147c&visibleTo=user:A User`)) }) }) }) From ec731294914a41afc27d692df3b7da0a8d9580aa Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 11:57:29 +0000 Subject: [PATCH 23/32] Simplify `getURL` by using query.Set/Encode instead of diy-ing it --- pkg/services/opsgenie/opsgenie_config.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 86a036ac..1f3f840b 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -48,29 +48,21 @@ func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL { } // Serialize Shoutrrr standard data types - rawQuery := format.BuildQuery(resolver) - + query, _ := url.ParseQuery(format.BuildQuery(resolver)) // Serialize OpsGenie specific data types - separator := "&" - if rawQuery == "" { - separator = "" - } - if len(config.Responders) > 0 { responders, _ := serializeEntities(config.Responders) - rawQuery = rawQuery + separator + "responders=" + responders - separator = "&" + query.Set("responders", responders) } if len(config.VisibleTo) > 0 { visibleTo, _ := serializeEntities(config.VisibleTo) - rawQuery = rawQuery + separator + "visibleTo=" + visibleTo + query.Set("visibleTo", visibleTo) } - result := &url.URL{ Host: host, Path: fmt.Sprintf("/%s", config.ApiKey), Scheme: Scheme, - RawQuery: rawQuery, + RawQuery: query.Encode(), } return result From cc9d75db25a926ed74c1688596f11022689eb165 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 12:07:57 +0000 Subject: [PATCH 24/32] Fix test after simplifying `getURL`, it encodes commas etc. now --- pkg/services/opsgenie/opsgenie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index dbed3384..bb28254c 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -411,7 +411,7 @@ var _ = Describe("the OpsGenie Config struct", func() { } url := config.GetURL() - Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1%2Caction2&alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&details=key%3Avalue&entity=An+example+entity¬e=Here+is+a+note&priority=P1&source=The+source&tags=tag1%2Ctag2&user=Dracula&responders=user:Test,team:NOC,team:4513b7ea-3b91-438f-b7e4-e3e54af9147c&visibleTo=user:A User`)) + Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1%2Caction2&alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&details=key%3Avalue&entity=An+example+entity¬e=Here+is+a+note&priority=P1&responders=user%3ATest%2Cteam%3ANOC%2Cteam%3A4513b7ea-3b91-438f-b7e4-e3e54af9147c&source=The+source&tags=tag1%2Ctag2&user=Dracula&visibleTo=user%3AA+User`)) }) }) }) From 6390b12eafacc188ca86be2c860c7c62876d662c Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 12:13:40 +0000 Subject: [PATCH 25/32] Move `newAlertPayload` to `Service` struct This avoids having to initialize PropKeyResolver twice (once when initializing and once when generating a playload) --- pkg/services/opsgenie/opsgenie.go | 53 +++++++++++++++++++++++++- pkg/services/opsgenie/opsgenie_json.go | 52 ------------------------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index d1f623e8..b308753c 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -9,6 +9,7 @@ import ( "net/http" "net/url" + "github.com/containrrr/shoutrrr/pkg/format" "github.com/containrrr/shoutrrr/pkg/services/standard" "github.com/containrrr/shoutrrr/pkg/types" ) @@ -21,6 +22,7 @@ const ( type Service struct { standard.Standard config *Config + pkr format.PropKeyResolver } func (service *Service) sendAlert(url string, apiKey string, payload AlertPayload) error { @@ -58,7 +60,8 @@ func (service *Service) sendAlert(url string, apiKey string, payload AlertPayloa func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error { service.Logger.SetLogger(logger) service.config = &Config{} - return service.config.SetURL(configURL) + service.pkr = format.NewPropKeyResolver(service.config) + return service.config.setURL(&service.pkr, configURL) } // Send a notification message to OpsGenie @@ -66,9 +69,55 @@ func (service *Service) Initialize(configURL *url.URL, logger *log.Logger) error func (service *Service) Send(message string, params *types.Params) error { config := service.config url := fmt.Sprintf(alertEndpointTemplate, config.Host, config.Port) - payload, err := NewAlertPayload(message, config, params) + payload, err := service.newAlertPayload(message, params) if err != nil { return err } return service.sendAlert(url, config.ApiKey, payload) } + +func (service *Service) newAlertPayload(message string, params *types.Params) (AlertPayload, error) { + if params == nil { + params = &types.Params{} + } + + // Defensive copy + payloadFields := *service.config + + if value, found := (*params)["responders"]; found { + responders, err := deserializeEntities(value) + if err != nil { + return AlertPayload{}, err + } + payloadFields.Responders = responders + delete(*params, "responders") + } + if value, found := (*params)["visibleTo"]; found { + visibleTo, err := deserializeEntities(value) + if err != nil { + return AlertPayload{}, err + } + payloadFields.VisibleTo = visibleTo + delete(*params, "visibleTo") + } + if err := service.pkr.UpdateConfigFromParams(&payloadFields, params); err != nil { + return AlertPayload{}, err + } + + result := AlertPayload{ + Message: message, + Alias: payloadFields.Alias, + Description: payloadFields.Description, + Responders: payloadFields.Responders, + VisibleTo: payloadFields.VisibleTo, + Actions: payloadFields.Actions, + Tags: payloadFields.Tags, + Details: payloadFields.Details, + Entity: payloadFields.Entity, + Source: payloadFields.Source, + Priority: payloadFields.Priority, + User: payloadFields.User, + Note: payloadFields.Note, + } + return result, nil +} diff --git a/pkg/services/opsgenie/opsgenie_json.go b/pkg/services/opsgenie/opsgenie_json.go index 8e865d83..3d5e6c6d 100644 --- a/pkg/services/opsgenie/opsgenie_json.go +++ b/pkg/services/opsgenie/opsgenie_json.go @@ -1,10 +1,5 @@ package opsgenie -import ( - "github.com/containrrr/shoutrrr/pkg/format" - "github.com/containrrr/shoutrrr/pkg/types" -) - // AlertPayload represents the payload being sent to the OpsGenie API // // See: https://docs.opsgenie.com/docs/alert-api#create-alert @@ -36,50 +31,3 @@ type AlertPayload struct { User string `json:"user,omitempty"` Note string `json:"note,omitempty"` } - -func NewAlertPayload(message string, config *Config, params *types.Params) (AlertPayload, error) { - if params == nil { - params = &types.Params{} - } - - // Defensive copy - payloadFields := *config - - pkr := format.NewPropKeyResolver(&payloadFields) - if value, found := (*params)["responders"]; found { - responders, err := deserializeEntities(value) - if err != nil { - return AlertPayload{}, err - } - payloadFields.Responders = responders - delete(*params, "responders") - } - if value, found := (*params)["visibleTo"]; found { - visibleTo, err := deserializeEntities(value) - if err != nil { - return AlertPayload{}, err - } - payloadFields.VisibleTo = visibleTo - delete(*params, "visibleTo") - } - if err := pkr.UpdateConfigFromParams(&payloadFields, params); err != nil { - return AlertPayload{}, err - } - - result := AlertPayload{ - Message: message, - Alias: payloadFields.Alias, - Description: payloadFields.Description, - Responders: payloadFields.Responders, - VisibleTo: payloadFields.VisibleTo, - Actions: payloadFields.Actions, - Tags: payloadFields.Tags, - Details: payloadFields.Details, - Entity: payloadFields.Entity, - Source: payloadFields.Source, - Priority: payloadFields.Priority, - User: payloadFields.User, - Note: payloadFields.Note, - } - return result, nil -} From 8f3aac415427323fab165e6e3d8ec3779c3383cc Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 12:36:10 +0000 Subject: [PATCH 26/32] Preparation for implementing an interface for de-serializing structs --- pkg/services/opsgenie/opsgenie_entity.go | 88 ++++++++++++++---------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie_entity.go b/pkg/services/opsgenie/opsgenie_entity.go index 5fd06fd1..fa6c27f8 100644 --- a/pkg/services/opsgenie/opsgenie_entity.go +++ b/pkg/services/opsgenie/opsgenie_entity.go @@ -21,23 +21,58 @@ type Entity struct { Username string `json:"username,omitempty"` } +// SetFromProp deserializes an entity +func (e *Entity) SetFromProp(propValue string) error { + elements := strings.Split(propValue, ":") + + if len(elements) != 2 { + return fmt.Errorf("invalid entity, should have two elments separated by colon: %q", propValue) + } + e.Type = elements[0] + identifier := elements[1] + isID, err := isOpsGenieID(identifier) + if err != nil { + return fmt.Errorf("invalid entity, cannot parse id/name: %q", identifier) + } + + if isID { + e.ID = identifier + } else if e.Type == "team" { + e.Name = identifier + } else if e.Type == "user" { + e.Username = identifier + } else { + return fmt.Errorf("invalid entity, unexpected entity type: %q", e.Type) + } + + return nil +} + +// GetPropValue serializes an entity +func (e *Entity) GetPropValue() (string, error) { + identifier := "" + + if e.ID != "" { + identifier = e.ID + } else if e.Name != "" { + identifier = e.Name + } else if e.Username != "" { + identifier = e.Username + } else { + return "", fmt.Errorf("invalid entity, should have either ID, name or username") + } + + return fmt.Sprintf("%s:%s", e.Type, identifier), nil +} + func serializeEntities(entities []Entity) (string, error) { entityStrings := []string{} for _, entity := range entities { - identifier := "" - - if entity.ID != "" { - identifier = entity.ID - } else if entity.Name != "" { - identifier = entity.Name - } else if entity.Username != "" { - identifier = entity.Username - } else { - return "", fmt.Errorf("invalid entity, should have either ID, name or username") + entityStr, err := entity.GetPropValue() + if err != nil { + return "", err } - - entityStr := fmt.Sprintf("%s:%s", entity.Type, identifier) entityStrings = append(entityStrings, entityStr) } @@ -49,33 +84,10 @@ func deserializeEntities(str string) ([]Entity, error) { entityStrings := strings.Split(str, ",") for _, entityStr := range entityStrings { - elements := strings.Split(entityStr, ":") - - if len(elements) != 2 { - return result, fmt.Errorf("invalid entity, should have two elments separated by colon: %q", entityStr) + entity := Entity{} + if err := entity.SetFromProp(entityStr); err != nil { + return result, err } - entityType := elements[0] - identifier := elements[1] - - entity := Entity{ - Type: entityType, - } - - isID, err := isOpsGenieID(identifier) - if err != nil { - return result, fmt.Errorf("invalid entity, cannot parse id/name: %q", identifier) - } - - if isID { - entity.ID = identifier - } else if entityType == "team" { - entity.Name = identifier - } else if entityType == "user" { - entity.Username = identifier - } else { - return result, fmt.Errorf("invalid entity, unexpected entity type: %q", entityType) - } - result = append(result, entity) } From 330514791a79e43456f8d46d9e74535a338b5003 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Thu, 4 Feb 2021 12:42:07 +0000 Subject: [PATCH 27/32] Fix linting issues --- pkg/services/opsgenie/opsgenie.go | 2 +- pkg/services/opsgenie/opsgenie_config.go | 9 +++++---- pkg/services/opsgenie/opsgenie_test.go | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index b308753c..2ab4a097 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -73,7 +73,7 @@ func (service *Service) Send(message string, params *types.Params) error { if err != nil { return err } - return service.sendAlert(url, config.ApiKey, payload) + return service.sendAlert(url, config.APIKey, payload) } func (service *Service) newAlertPayload(message string, params *types.Params) (AlertPayload, error) { diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 1f3f840b..501efbc5 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -11,7 +11,7 @@ import ( // Config for use within the opsgenie service type Config struct { - ApiKey string `desc:"The OpsGenie API key"` + APIKey string `desc:"The OpsGenie API key"` Host string `desc:"The OpsGenie API host. Use 'api.eu.opsgenie.com' for EU instances" default:"api.opsgenie.com"` Port uint16 `desc:"The OpsGenie API port." default:"443"` Alias string `key:"alias" desc:"Client-defined identifier of the alert" optional:"true"` @@ -28,11 +28,12 @@ type Config struct { User string `key:"user" desc:"Display name of the request owner" optional:"true"` } +// Enums returns an empty map because the OpsGenie service doesn't use Enums func (config Config) Enums() map[string]types.EnumFormatter { return map[string]types.EnumFormatter{} } -// Public version of GetURL that creates a new PropKeyResolver when accessed from outside the package +// GetURL is the public version of getURL that creates a new PropKeyResolver when accessed from outside the package func (config *Config) GetURL() *url.URL { resolver := format.NewPropKeyResolver(config) return config.getURL(&resolver) @@ -60,7 +61,7 @@ func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL { } result := &url.URL{ Host: host, - Path: fmt.Sprintf("/%s", config.ApiKey), + Path: fmt.Sprintf("/%s", config.APIKey), Scheme: Scheme, RawQuery: query.Encode(), } @@ -77,7 +78,7 @@ func (config *Config) SetURL(url *url.URL) error { // Private version of SetURL that can use an instance of PropKeyResolver instead of rebuilding it's model from reflection func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) error { config.Host = url.Hostname() - config.ApiKey = url.Path[1:] + config.APIKey = url.Path[1:] if url.Port() != "" { port, err := strconv.ParseUint(url.Port(), 10, 16) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index bb28254c..f4d06202 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -292,7 +292,7 @@ var _ = Describe("the OpsGenie Config struct", func() { err = config.SetURL(url) Expect(err).To(BeNil()) - Expect(config.ApiKey).To(Equal(mockAPIKey)) + Expect(config.APIKey).To(Equal(mockAPIKey)) Expect(config.Host).To(Equal(mockHost)) Expect(config.Port).To(Equal(uint16(0))) }) @@ -362,7 +362,7 @@ var _ = Describe("the OpsGenie Config struct", func() { It("should generate a url", func() { config := Config{ Host: "api.opsgenie.com", - ApiKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", + APIKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", } url := config.GetURL() @@ -375,7 +375,7 @@ var _ = Describe("the OpsGenie Config struct", func() { It("should generate a url with port", func() { config := Config{ Host: "api.opsgenie.com", - ApiKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", + APIKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", Port: 12345, } @@ -389,7 +389,7 @@ var _ = Describe("the OpsGenie Config struct", func() { It("should generate a url with query parameters", func() { config := Config{ Host: "api.opsgenie.com", - ApiKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", + APIKey: "eb243592-faa2-4ba2-a551q-1afdf565c889", Alias: "Life is too short for no alias", Description: "Every alert needs a description", Responders: []Entity{ From 7bd4ba06685194f5d6cc502288690f6096a5b763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Sun, 7 Feb 2021 18:21:36 +0100 Subject: [PATCH 28/32] feat: add support for struct and map fields --- pkg/format/format.go | 20 +-- pkg/format/format_test.go | 273 ++++++++++++++++++++++++++++++++++++++ pkg/format/formatter.go | 204 ++++++++++++++++++++++------ pkg/types/config_prop.go | 6 + 4 files changed, 443 insertions(+), 60 deletions(-) create mode 100644 pkg/format/format_test.go create mode 100644 pkg/types/config_prop.go diff --git a/pkg/format/format.go b/pkg/format/format.go index 7acbf7ce..557495a2 100644 --- a/pkg/format/format.go +++ b/pkg/format/format.go @@ -5,28 +5,12 @@ import ( "strings" ) -// NotifyFormat describes the format used in the notification body -type NotifyFormat int - -const ( - // Markdown is the default notification format - Markdown NotifyFormat = 0 -) - // ParseBool returns true for "1","true","yes" or false for "0","false","no" or defaultValue for any other value func ParseBool(value string, defaultValue bool) (parsedValue bool, ok bool) { switch strings.ToLower(value) { - case "true": - fallthrough - case "1": - fallthrough - case "yes": + case "true", "1", "yes": return true, true - case "false": - fallthrough - case "0": - fallthrough - case "no": + case "false", "0", "no": return false, true default: return defaultValue, false diff --git a/pkg/format/format_test.go b/pkg/format/format_test.go new file mode 100644 index 00000000..b0e53b26 --- /dev/null +++ b/pkg/format/format_test.go @@ -0,0 +1,273 @@ +package format + +import ( + "errors" + "github.com/containrrr/shoutrrr/pkg/types" + "reflect" + + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var ( + // logger *log.Logger + f = formatter{ + EnumFormatters: map[string]types.EnumFormatter{ + "TestEnum": testEnum, + }, + MaxDepth: 2, + } + ts *testStruct +) + +func TestFormat(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Shoutrrr Discord Suite") +} + +var _ = Describe("the format package", func() { + BeforeSuite(func() { + // logger = log.New(GinkgoWriter, "Test", log.LstdFlags) + }) + + Describe("SetConfigField", func() { + var ( + tv reflect.Value + ) + tt := reflect.TypeOf(testStruct{}) + fields := f.getStructFieldInfo(tt) + + fieldMap := make(map[string]FieldInfo, len(fields)) + for _, fi := range fields { + fieldMap[fi.Name] = fi + } + When("updating a struct", func() { + + BeforeEach(func() { + tsPtr := reflect.New(tt) + tv = tsPtr.Elem() + ts = tsPtr.Interface().(*testStruct) + }) + + When("setting an integer value", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["Signed"], "3") + Expect(valid).To(BeTrue()) + Expect(err).NotTo(HaveOccurred()) + + Expect(ts.Signed).To(Equal(3)) + }) + }) + When("the value is invalid", func() { + It("should return an error", func() { + ts.Signed = 2 + valid, err := SetConfigField(tv, fieldMap["Signed"], "z7") + Expect(valid).To(BeFalse()) + Expect(err).To(HaveOccurred()) + + Expect(ts.Signed).To(Equal(2)) + }) + }) + }) + + When("setting an unsigned integer value", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["Unsigned"], "6") + Expect(valid).To(BeTrue()) + Expect(err).NotTo(HaveOccurred()) + + Expect(ts.Unsigned).To(Equal(uint(6))) + }) + }) + When("the value is invalid", func() { + It("should return an error", func() { + ts.Unsigned = 2 + valid, err := SetConfigField(tv, fieldMap["Unsigned"], "-3") + + Expect(ts.Unsigned).To(Equal(uint(2))) + Expect(valid).To(BeFalse()) + Expect(err).To(HaveOccurred()) + }) + }) + }) + + When("setting a string slice value", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["StrSlice"], "meawannowalkalitabitalleh,meawannofeelalitabitstrongah") + Expect(valid).To(BeTrue()) + Expect(err).NotTo(HaveOccurred()) + + Expect(ts.StrSlice).To(HaveLen(2)) + }) + }) + }) + + When("setting a string array value", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["StrArray"], "meawannowalkalitabitalleh,meawannofeelalitabitstrongah,meawannothinkalitabitsmartah") + Expect(valid).To(BeTrue()) + Expect(err).NotTo(HaveOccurred()) + }) + }) + When("the value has too many elements", func() { + It("should return an error", func() { + valid, err := SetConfigField(tv, fieldMap["StrArray"], "one,two,three,four?") + Expect(valid).To(BeFalse()) + Expect(err).To(HaveOccurred()) + }) + }) + When("the value has too few elements", func() { + It("should return an error", func() { + valid, err := SetConfigField(tv, fieldMap["StrArray"], "one,two") + Expect(valid).To(BeFalse()) + Expect(err).To(HaveOccurred()) + }) + }) + }) + + When("setting a struct value", func() { + When("it implements ConfigProp", func() { + It("should return an error", func() { + valid, err := SetConfigField(tv, fieldMap["Sub"], "@awol") + Expect(err).To(HaveOccurred()) + Expect(valid).NotTo(BeTrue()) + }) + }) + When("it implements ConfigProp", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["SubProp"], "@awol") + Expect(err).NotTo(HaveOccurred()) + Expect(valid).To(BeTrue()) + + Expect(ts.SubProp.Value).To(Equal("awol")) + }) + }) + When("the value is invalid", func() { + It("should return an error", func() { + valid, err := SetConfigField(tv, fieldMap["SubProp"], "missing initial at symbol") + Expect(err).To(HaveOccurred()) + Expect(valid).NotTo(BeTrue()) + }) + }) + }) + }) + + When("setting a struct slice value", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["SubPropSlice"], "@alice,@merton") + Expect(err).NotTo(HaveOccurred()) + Expect(valid).To(BeTrue()) + + Expect(ts.SubPropSlice).To(HaveLen(2)) + }) + }) + }) + + When("setting a struct pointer slice value", func() { + When("the value is valid", func() { + It("should set it", func() { + valid, err := SetConfigField(tv, fieldMap["SubPropPtrSlice"], "@the,@best") + Expect(err).NotTo(HaveOccurred()) + Expect(valid).To(BeTrue()) + + Expect(ts.SubPropPtrSlice).To(HaveLen(2)) + }) + }) + }) + }) + + When("formatting stuct values", func() { + BeforeEach(func() { + tsPtr := reflect.New(tt) + tv = tsPtr.Elem() + }) + When("setting and formatting", func() { + It("should format signed integers identical to input", func() { + testSetAndFormat(tv, fieldMap["Signed"], "-45", "-45") + }) + It("should format unsigned integers identical to input", func() { + testSetAndFormat(tv, fieldMap["Unsigned"], "5", "5") + }) + It("should format structs identical to input", func() { + testSetAndFormat(tv, fieldMap["SubProp"], "@whoa", "@whoa") + }) + It("should format enums identical to input", func() { + testSetAndFormat(tv, fieldMap["TestEnum"], "Foo", "Foo") + }) + It("should format string slices identical to input", func() { + testSetAndFormat(tv, fieldMap["StrSlice"], "one,two,three,four", "[ one, two, three, four ]") + }) + It("should format string arrays identical to input", func() { + testSetAndFormat(tv, fieldMap["StrArray"], "one,two,three", "[ one, two, three ]") + }) + It("should format prop struct slices identical to input", func() { + testSetAndFormat(tv, fieldMap["SubPropSlice"], "@be,@the,@best", "[ @be, @the, @best ]") + }) + It("should format prop struct slices identical to input", func() { + testSetAndFormat(tv, fieldMap["SubPropPtrSlice"], "@diet,@glue", "[ @diet, @glue ]") + }) + It("should format prop struct slices identical to input", func() { + testSetAndFormat(tv, fieldMap["StrMap"], "one:1,two:2", "{ one: 1, two: 2 }") + }) + }) + }) + }) +}) + +func testSetAndFormat(tv reflect.Value, field FieldInfo, value string, prettyFormat string) { + _, _ = SetConfigField(tv, field, value) + fieldValue := tv.FieldByName(field.Name) + + // Used for de-/serializing configuration + formatted, err := GetConfigFieldString(tv, field) + Expect(err).NotTo(HaveOccurred()) + Expect(formatted).To(Equal(value)) + + // Used for pretty printing output, coloring etc. + formatted, _ = f.getStructFieldValueString(fieldValue, field, 0) + Expect(formatted).To(Equal(prettyFormat)) +} + +type testStruct struct { + Signed int + Unsigned uint + Str string + StrSlice []string + StrArray [3]string + Sub subStruct + TestEnum int + SubProp subPropStruct + SubSlice []subStruct + SubPropSlice []subPropStruct + SubPropPtrSlice []*subPropStruct + StrMap map[string]string +} + +type subStruct struct { + Value string +} + +type subPropStruct struct { + Value string +} + +func (s *subPropStruct) SetFromProp(propValue string) error { + if len(propValue) < 1 || propValue[0] != '@' { + return errors.New("invalid value") + } + s.Value = propValue[1:] + return nil +} +func (s *subPropStruct) GetPropValue() (string, error) { + return "@" + s.Value, nil +} + +var testEnum = CreateEnumFormatter([]string{"None", "Foo", "Bar"}) diff --git a/pkg/format/formatter.go b/pkg/format/formatter.go index 7cd2d1d2..7e7170a8 100644 --- a/pkg/format/formatter.go +++ b/pkg/format/formatter.go @@ -81,25 +81,9 @@ func (fmtr *formatter) formatStructMap(structType reflect.Type, structItem inter valueLen := 0 preLen := 16 - isEnum := field.EnumFormatter != nil - if values.IsValid() { - // Add some space to print the value preLen = 40 - if isEnum { - fieldVal := values.Field(i) - kind := fieldVal.Kind() - if kind == reflect.Int { - valueStr := field.EnumFormatter.Print(int(fieldVal.Int())) - value = ColorizeEnum(valueStr) - valueLen = len(valueStr) - } else { - err := fmt.Errorf("incorrect enum type '%s' for field '%s'", kind, field.Name) - fmtr.Errors = append(fmtr.Errors, err) - } - } else if nextDepth < fmtr.MaxDepth { - value, valueLen = fmtr.getFieldValueString(values.FieldByName(field.Name), field.Base, nextDepth) - } + value, valueLen = fmtr.getStructFieldValueString(values.Field(i), field, nextDepth) } else { // Since no values was supplied, let's substitute the value with the type typeName := field.Type.String() @@ -120,10 +104,10 @@ func (fmtr *formatter) formatStructMap(structType reflect.Type, structItem inter } if len(field.DefaultValue) > 0 { - value += fmt.Sprintf(" ", ColorizeValue(field.DefaultValue, isEnum)) + value += fmt.Sprintf(" ", ColorizeValue(field.DefaultValue, field.EnumFormatter != nil)) } - if isEnum { + if field.EnumFormatter != nil { value += fmt.Sprintf(" [%s]", strings.Join(field.EnumFormatter.Names(), ", ")) } @@ -137,6 +121,23 @@ func (fmtr *formatter) formatStructMap(structType reflect.Type, structItem inter return valueMap, maxKeyLen } +func (fmtr *formatter) getStructFieldValueString(fieldVal reflect.Value, field FieldInfo, nextDepth uint8) (value string, valueLen int) { + if field.EnumFormatter != nil { + kind := fieldVal.Kind() + if kind == reflect.Int { + valueStr := field.EnumFormatter.Print(int(fieldVal.Int())) + return ColorizeEnum(valueStr), len(valueStr) + } else { + err := fmt.Errorf("incorrect enum type '%s' for field '%s'", kind, field.Name) + fmtr.Errors = append(fmtr.Errors, err) + return "", 0 + } + } else if nextDepth >= fmtr.MaxDepth { + return + } + return fmtr.getFieldValueString(fieldVal, field.Base, nextDepth) +} + // FieldInfo is the meta data about a config field type FieldInfo struct { Name string @@ -261,7 +262,7 @@ func (fmtr *formatter) getFieldValueString(field reflect.Value, base int, depth items := make([]string, fieldLen) totalLen := 4 var itemLen int - for i := 0; i < fieldLen; i++ { + for i := range items { items[i], itemLen = fmtr.getFieldValueString(field.Index(i), base, nextDepth) totalLen += itemLen } @@ -273,32 +274,29 @@ func (fmtr *formatter) getFieldValueString(field reflect.Value, base int, depth } if kind == reflect.Map { - items := make([]string, field.Len()) + sb := strings.Builder{} + sb.WriteString("{ ") iter := field.MapRange() - index := 0 // initial value for totalLen is surrounding curlies and spaces, and separating commas totalLen := 4 + (field.Len() - 1) - for iter.Next() { + for i := 0; iter.Next(); i++ { key, keyLen := fmtr.getFieldValueString(iter.Key(), base, nextDepth) value, valueLen := fmtr.getFieldValueString(iter.Value(), base, nextDepth) - items[index] = fmt.Sprintf("%s: %s", key, value) + if sb.Len() > 2 { + sb.WriteString(", ") + } + sb.WriteString(fmt.Sprintf("%s: %s", key, value)) totalLen += keyLen + valueLen + 2 } + sb.WriteString(" }") - return fmt.Sprintf("{ %s }", strings.Join(items, ", ")), totalLen + return sb.String(), totalLen } - if kind == reflect.Struct { - structMap, _ := fmtr.formatStructMap(field.Type(), field, depth+1) - structFieldCount := len(structMap) - items := make([]string, structFieldCount) - index := 0 - totalLen := 4 + (structFieldCount - 1) - for key, value := range structMap { - items[index] = fmt.Sprintf("%s: %s", key, value) - index++ - totalLen += len(key) + 2 + len(value) - } - return fmt.Sprintf("< %s >", strings.Join(items, ", ")), totalLen + if kind == reflect.Struct || kind == reflect.Ptr { + formatted, err := GetConfigPropString(field) + if err == nil { + return formatted, len(formatted) + } } strVal := kind.String() return fmt.Sprintf("", strVal), len(strVal) + 5 @@ -346,15 +344,75 @@ func SetConfigField(config reflect.Value, field FieldInfo, inputValue string) (v configField.SetBool(value) return true, nil + } else if fieldKind == reflect.Map { + keyKind := field.Type.Key().Kind() + elemKind := field.Type.Elem().Kind() + if elemKind != reflect.String || keyKind != reflect.String { + return false, errors.New("field format is not supported") + } + + newMap := make(map[string]string) + + pairs := strings.Split(inputValue, ",") + for _, pair := range pairs { + elems := strings.Split(pair, ":") + if len(elems) != 2 { + return false, errors.New("field format is not supported") + } + key := elems[0] + value := elems[1] + + newMap[key] = value + } + + configField.Set(reflect.ValueOf(newMap)) + return true, nil + } else if fieldKind == reflect.Struct { + valuePtr, err := GetConfigPropFromString(field.Type, inputValue) + if err != nil { + return false, err + } + configField.Set(valuePtr.Elem()) + return true, nil } else if fieldKind >= reflect.Slice || fieldKind == reflect.Array { elemType := field.Type.Elem() + elemValType := elemType elemKind := elemType.Kind() - if elemKind != reflect.String { + + if elemKind == reflect.Ptr { + // When updating a pointer slice, use the value type kind + elemValType = elemType.Elem() + elemKind = elemValType.Kind() + } + + if elemKind != reflect.Struct && elemKind != reflect.String { return false, errors.New("field format is not supported") } values := strings.Split(inputValue, ",") - value := reflect.ValueOf(values) + + var value reflect.Value + if elemKind == reflect.Struct { + propValues := reflect.MakeSlice(reflect.SliceOf(elemType), 0, len(values)) + for _, v := range values { + propPtr, err := GetConfigPropFromString(elemValType, v) + if err != nil { + return false, err + } + propVal := propPtr + + // If not a pointer slice, dereference the value + if elemType.Kind() != reflect.Ptr { + propVal = propPtr.Elem() + } + propValues = reflect.Append(propValues, propVal) + } + value = propValues + } else { + // Use the split string parts as the target value + value = reflect.ValueOf(values) + } + if fieldKind == reflect.Array { arrayLen := field.Type.Len() if len(values) != arrayLen { @@ -376,10 +434,44 @@ func SetConfigField(config reflect.Value, field FieldInfo, inputValue string) (v } +func GetConfigPropFromString(structType reflect.Type, value string) (reflect.Value, error) { + valuePtr := reflect.New(structType) + configProp, ok := valuePtr.Interface().(types.ConfigProp) + if !ok { + return reflect.Value{}, errors.New("struct field cannot be used as a prop") + } + + if err := configProp.SetFromProp(value); err != nil { + return reflect.Value{}, err + } + + return valuePtr, nil +} + +func GetConfigPropString(propPtr reflect.Value) (string, error) { + + if propPtr.Kind() != reflect.Ptr { + propVal := propPtr + propPtr = reflect.New(propVal.Type()) + propPtr.Elem().Set(propVal) + } + + configProp, ok := propPtr.Interface().(types.ConfigProp) + if !ok { + return "", errors.New("struct field cannot be used as a prop") + } + + return configProp.GetPropValue() +} + // GetConfigFieldString serializes the config field value to a string representation func GetConfigFieldString(config reflect.Value, field FieldInfo) (value string, err error) { configField := config.FieldByName(field.Name) fieldKind := field.Type.Kind() + if fieldKind == reflect.Ptr { + configField = configField.Elem() + fieldKind = field.Type.Elem().Kind() + } if fieldKind == reflect.String { return configField.String(), nil @@ -395,14 +487,42 @@ func GetConfigFieldString(config reflect.Value, field FieldInfo) (value string, return strconv.FormatInt(configField.Int(), field.Base), nil } else if fieldKind == reflect.Bool { return PrintBool(configField.Bool()), nil - } else if fieldKind >= reflect.Slice { + } else if fieldKind == reflect.Map { + keyKind := field.Type.Key().Kind() + elemKind := field.Type.Elem().Kind() + if elemKind != reflect.String || keyKind != reflect.String { + return "", errors.New("field format is not supported") + } + + kvPairs := []string{} + for _, key := range configField.MapKeys() { + value := configField.MapIndex(key).Interface() + + kvPairs = append(kvPairs, fmt.Sprintf("%s:%s", key, value)) + } + return strings.Join(kvPairs, ","), nil + } else if fieldKind == reflect.Slice || fieldKind == reflect.Array { sliceLen := configField.Len() sliceValue := configField.Slice(0, sliceLen) - if field.Type.Elem().Kind() != reflect.String { + elemKind := field.Type.Elem().Kind() + var slice []string + if elemKind == reflect.Struct || elemKind == reflect.Ptr { + slice = make([]string, sliceLen) + for i := range slice { + strVal, err := GetConfigPropString(configField.Index(i)) + if err != nil { + return "", err + } + slice[i] = strVal + } + } else if elemKind == reflect.String { + slice = sliceValue.Interface().([]string) + } else { return "", errors.New("field format is not supported") } - slice := sliceValue.Interface().([]string) return strings.Join(slice, ","), nil + } else if fieldKind == reflect.Struct { + return GetConfigPropString(configField) } return "", fmt.Errorf("field kind %x is not supported", fieldKind) diff --git a/pkg/types/config_prop.go b/pkg/types/config_prop.go new file mode 100644 index 00000000..c2720ba5 --- /dev/null +++ b/pkg/types/config_prop.go @@ -0,0 +1,6 @@ +package types + +type ConfigProp interface { + SetFromProp(propValue string) error + GetPropValue() (string, error) +} From 2fc0dbc81c20a927d1fcaee9c72efaefe4bfc7a6 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 16 Feb 2021 11:30:14 +0000 Subject: [PATCH 29/32] Fix: Use default port if no port was specified --- pkg/services/opsgenie/opsgenie_config.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 501efbc5..07571cc5 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -9,6 +9,8 @@ import ( "github.com/containrrr/shoutrrr/pkg/types" ) +const defaultPort = 443 + // Config for use within the opsgenie service type Config struct { APIKey string `desc:"The OpsGenie API key"` @@ -86,6 +88,8 @@ func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) e return err } config.Port = uint16(port) + } else { + config.Port = 443 } for key, vals := range url.Query() { From 26bd837a591dd32ee2c4c627336ec3a0132d05a2 Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 16 Feb 2021 12:19:20 +0000 Subject: [PATCH 30/32] Remove custom serialization logic; use formatters functionality instead --- pkg/services/opsgenie/opsgenie.go | 16 ------------- pkg/services/opsgenie/opsgenie_config.go | 26 ++------------------- pkg/services/opsgenie/opsgenie_entity.go | 29 ------------------------ 3 files changed, 2 insertions(+), 69 deletions(-) diff --git a/pkg/services/opsgenie/opsgenie.go b/pkg/services/opsgenie/opsgenie.go index 2ab4a097..348fdac3 100644 --- a/pkg/services/opsgenie/opsgenie.go +++ b/pkg/services/opsgenie/opsgenie.go @@ -84,22 +84,6 @@ func (service *Service) newAlertPayload(message string, params *types.Params) (A // Defensive copy payloadFields := *service.config - if value, found := (*params)["responders"]; found { - responders, err := deserializeEntities(value) - if err != nil { - return AlertPayload{}, err - } - payloadFields.Responders = responders - delete(*params, "responders") - } - if value, found := (*params)["visibleTo"]; found { - visibleTo, err := deserializeEntities(value) - if err != nil { - return AlertPayload{}, err - } - payloadFields.VisibleTo = visibleTo - delete(*params, "visibleTo") - } if err := service.pkr.UpdateConfigFromParams(&payloadFields, params); err != nil { return AlertPayload{}, err } diff --git a/pkg/services/opsgenie/opsgenie_config.go b/pkg/services/opsgenie/opsgenie_config.go index 07571cc5..39fdb56f 100644 --- a/pkg/services/opsgenie/opsgenie_config.go +++ b/pkg/services/opsgenie/opsgenie_config.go @@ -50,22 +50,11 @@ func (config *Config) getURL(resolver types.ConfigQueryResolver) *url.URL { host = config.Host } - // Serialize Shoutrrr standard data types - query, _ := url.ParseQuery(format.BuildQuery(resolver)) - // Serialize OpsGenie specific data types - if len(config.Responders) > 0 { - responders, _ := serializeEntities(config.Responders) - query.Set("responders", responders) - } - if len(config.VisibleTo) > 0 { - visibleTo, _ := serializeEntities(config.VisibleTo) - query.Set("visibleTo", visibleTo) - } result := &url.URL{ Host: host, Path: fmt.Sprintf("/%s", config.APIKey), Scheme: Scheme, - RawQuery: query.Encode(), + RawQuery: format.BuildQuery(resolver), } return result @@ -93,18 +82,7 @@ func (config *Config) setURL(resolver types.ConfigQueryResolver, url *url.URL) e } for key, vals := range url.Query() { - var err error - - switch key { - case "responders": - config.Responders, err = deserializeEntities(vals[0]) - case "visibleTo": - config.VisibleTo, err = deserializeEntities(vals[0]) - default: - err = resolver.Set(key, vals[0]) - } - - if err != nil { + if err := resolver.Set(key, vals[0]); err != nil { return err } } diff --git a/pkg/services/opsgenie/opsgenie_entity.go b/pkg/services/opsgenie/opsgenie_entity.go index fa6c27f8..9ff8f3e8 100644 --- a/pkg/services/opsgenie/opsgenie_entity.go +++ b/pkg/services/opsgenie/opsgenie_entity.go @@ -65,35 +65,6 @@ func (e *Entity) GetPropValue() (string, error) { return fmt.Sprintf("%s:%s", e.Type, identifier), nil } -func serializeEntities(entities []Entity) (string, error) { - entityStrings := []string{} - - for _, entity := range entities { - entityStr, err := entity.GetPropValue() - if err != nil { - return "", err - } - entityStrings = append(entityStrings, entityStr) - } - - return strings.Join(entityStrings, ","), nil -} - -func deserializeEntities(str string) ([]Entity, error) { - result := []Entity{} - - entityStrings := strings.Split(str, ",") - for _, entityStr := range entityStrings { - entity := Entity{} - if err := entity.SetFromProp(entityStr); err != nil { - return result, err - } - result = append(result, entity) - } - - return result, nil -} - // Detects OpsGenie IDs in the form 4513b7ea-3b91-438f-b7e4-e3e54af9147c func isOpsGenieID(str string) (bool, error) { return regexp.MatchString(`^[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}$`, str) From 38c1f10209a94d515bfa3f9243ffcb86e07ad54d Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 16 Feb 2021 12:21:01 +0000 Subject: [PATCH 31/32] Fix: Expect default port (443) in test --- pkg/services/opsgenie/opsgenie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index f4d06202..118c5023 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -294,7 +294,7 @@ var _ = Describe("the OpsGenie Config struct", func() { Expect(config.APIKey).To(Equal(mockAPIKey)) Expect(config.Host).To(Equal(mockHost)) - Expect(config.Port).To(Equal(uint16(0))) + Expect(config.Port).To(Equal(uint16(443))) }) }) From f0c460dcc54894a7e60410d32f30b33630ca58ab Mon Sep 17 00:00:00 2001 From: Jonas Pfannschmidt Date: Tue, 16 Feb 2021 12:55:14 +0000 Subject: [PATCH 32/32] Fix test: formatter lowercases keys Note that this does not affect how the keys are send to the service, just how we generate and parse URLs. --- pkg/services/opsgenie/opsgenie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/opsgenie/opsgenie_test.go b/pkg/services/opsgenie/opsgenie_test.go index 118c5023..ae3b26b7 100644 --- a/pkg/services/opsgenie/opsgenie_test.go +++ b/pkg/services/opsgenie/opsgenie_test.go @@ -411,7 +411,7 @@ var _ = Describe("the OpsGenie Config struct", func() { } url := config.GetURL() - Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1%2Caction2&alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&details=key%3Avalue&entity=An+example+entity¬e=Here+is+a+note&priority=P1&responders=user%3ATest%2Cteam%3ANOC%2Cteam%3A4513b7ea-3b91-438f-b7e4-e3e54af9147c&source=The+source&tags=tag1%2Ctag2&user=Dracula&visibleTo=user%3AA+User`)) + Expect(url.String()).To(Equal(`opsgenie://api.opsgenie.com/eb243592-faa2-4ba2-a551q-1afdf565c889?actions=action1%2Caction2&alias=Life+is+too+short+for+no+alias&description=Every+alert+needs+a+description&details=key%3Avalue&entity=An+example+entity¬e=Here+is+a+note&priority=P1&responders=user%3ATest%2Cteam%3ANOC%2Cteam%3A4513b7ea-3b91-438f-b7e4-e3e54af9147c&source=The+source&tags=tag1%2Ctag2&user=Dracula&visibleto=user%3AA+User`)) }) }) })