From e8d940c0783084413243df569bad080962739be7 Mon Sep 17 00:00:00 2001 From: Sven Speckmaier Date: Thu, 2 Jan 2020 18:58:19 +0100 Subject: [PATCH 1/5] initial slack webhook --- handler.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 1 + 2 files changed, 60 insertions(+) diff --git a/handler.go b/handler.go index 5d5c2bc..156af64 100644 --- a/handler.go +++ b/handler.go @@ -69,3 +69,62 @@ func grafanaParserFunc(r *http.Request) (string, error) { return message, nil } + +/************* +SLACK PARSER +*************/ +type SlackMessage struct { + Channel string `json:"channel"` + IconEmoji string `json:"icon_emoji"` + Username string `json:"username"` + Text string `json:"text"` + Attachments []SlackAttachment `json:"attachments"` +} + +type SlackAttachment struct { + Color string `json:"color"` + Title string `json:"title"` + TitleLink string `json:"title_link"` + Text string `json:"text"` +} + +func nonemptyAppendNewline(message string) (string) { + if len(message) == 0 { + return message + } + + return message+"\n" +} + +func slackParserFunc(r *http.Request) (string, error) { + // get alert data from request + body, err := ioutil.ReadAll(r.Body) + if err != nil { + return "", err + } + + // grafana alert struct + alert := SlackMessage{} + + // parse body into the alert struct + err = json.Unmarshal(body, &alert) + if err != nil { + return "", err + } + + // contruct alert message + message := "" + hasText := (alert.Text != "") + if hasText { + message = alert.Text + } + + for _, attachment := range alert.Attachments { + message = nonemptyAppendNewline(message) + message = message + attachment.Title+": "+attachment.TitleLink+"\n" + message = message + attachment.Text + } + + + return message, nil +} diff --git a/main.go b/main.go index ed3b306..f355f90 100644 --- a/main.go +++ b/main.go @@ -148,6 +148,7 @@ func main() { // initialize handler for grafana alerts http.Handle("/grafana", newMessageHandler(messages, grafanaParserFunc)) + http.Handle("/slack", newMessageHandler(messages, slackParserFunc)) // listen for requests http.ListenAndServe(":4321", nil) From 1c012e1f86334cfed72c3ad76862ad27ec963317 Mon Sep 17 00:00:00 2001 From: Sven Speckmaier Date: Thu, 2 Jan 2020 22:45:57 +0100 Subject: [PATCH 2/5] Message stanzas: add From: address(our address) --- main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.go b/main.go index f355f90..06cd8dc 100644 --- a/main.go +++ b/main.go @@ -115,6 +115,7 @@ func main() { reply := MessageBody{ Message: stanza.Message{ To: msg.From.Bare(), + From: address, }, Body: msg.Body, } @@ -139,6 +140,7 @@ func main() { _ = xmppSession.Encode(MessageBody{ Message: stanza.Message{ To: recipient, + From: address, }, Body: m, }) From 8afb5b9e6ef72cd3cd3e18f2de9f1aa0d8314cff Mon Sep 17 00:00:00 2001 From: Sven Speckmaier Date: Thu, 2 Jan 2020 22:49:12 +0100 Subject: [PATCH 3/5] slackParserFunc, parserFunc with Response Slack messages are acknowledged with code 200, message 'ok' code statically answered with 204 and empty message before slackParserFunc - rudimentary slack webhook parser --- handler.go | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/handler.go b/handler.go index 156af64..c6a6a4f 100644 --- a/handler.go +++ b/handler.go @@ -6,8 +6,17 @@ import ( "net/http" ) +type Response struct { + Message string + Code int +} + +func errorResponse() (Response) { + return Response{"", http.StatusInternalServerError} +} + // interface for parser functions (grafana, prometheus, ...) -type parserFunc func(*http.Request) (string, error) +type parserFunc func(*http.Request) (string, error, Response) type messageHandler struct { messages chan<- string // chan to xmpp client @@ -17,13 +26,14 @@ type messageHandler struct { // http request handler func (h *messageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // parse/generate message from http request - m, err := h.parserFunc(r) + m, err, response := h.parserFunc(r) if err != nil { w.WriteHeader(http.StatusInternalServerError) } // send message to xmpp client h.messages <- m - w.WriteHeader(http.StatusNoContent) + w.WriteHeader(response.Code) + w.Write( []byte(response.Message) ) } // returns new handler with a given parser function @@ -37,11 +47,11 @@ func newMessageHandler(m chan<- string, f parserFunc) *messageHandler { /************* GRAFANA PARSER *************/ -func grafanaParserFunc(r *http.Request) (string, error) { +func grafanaParserFunc(r *http.Request) (string, error, Response) { // get alert data from request body, err := ioutil.ReadAll(r.Body) if err != nil { - return "", err + return "", err, errorResponse() } // grafana alert struct @@ -55,7 +65,7 @@ func grafanaParserFunc(r *http.Request) (string, error) { // parse body into the alert struct err = json.Unmarshal(body, &alert) if err != nil { - return "", err + return "", err, errorResponse() } // contruct alert message @@ -67,7 +77,7 @@ func grafanaParserFunc(r *http.Request) (string, error) { message = ":( " + alert.Title + "\n" + alert.Message + "\n" + alert.RuleURL } - return message, nil + return message, nil, Response{"", http.StatusNoContent} } /************* @@ -96,11 +106,11 @@ func nonemptyAppendNewline(message string) (string) { return message+"\n" } -func slackParserFunc(r *http.Request) (string, error) { +func slackParserFunc(r *http.Request) (string, error, Response) { // get alert data from request body, err := ioutil.ReadAll(r.Body) if err != nil { - return "", err + return "", err, errorResponse() } // grafana alert struct @@ -109,7 +119,7 @@ func slackParserFunc(r *http.Request) (string, error) { // parse body into the alert struct err = json.Unmarshal(body, &alert) if err != nil { - return "", err + return "", err, Response{"", http.StatusInternalServerError} } // contruct alert message @@ -121,10 +131,11 @@ func slackParserFunc(r *http.Request) (string, error) { for _, attachment := range alert.Attachments { message = nonemptyAppendNewline(message) - message = message + attachment.Title+": "+attachment.TitleLink+"\n" - message = message + attachment.Text + message += attachment.Title+"\n" + message += attachment.TitleLink+"\n\n" + message += attachment.Text } - return message, nil + return message, nil, Response{"ok", http.StatusOK} } From 8ec6f82ae62e61af8ed6221fc20ca67a2a179f76 Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Sun, 5 Jan 2020 15:09:25 +0100 Subject: [PATCH 4/5] adds example notification body for the slack-handler --- dev/slack-compatible-notification-example.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 dev/slack-compatible-notification-example.json diff --git a/dev/slack-compatible-notification-example.json b/dev/slack-compatible-notification-example.json new file mode 100644 index 0000000..b1f4162 --- /dev/null +++ b/dev/slack-compatible-notification-example.json @@ -0,0 +1,13 @@ +{ + "channel": "#channel", + "icon_emoji": ":heart:", + "username": "Flux Deployer", + "attachments": [ + { + "color": "#4286f4", + "title": "Applied flux changes to cluster", + "title_link": "https://GITURL/USERNAME/kubernetes/commit/COMMITSHA", + "text": "Event: Sync: 0f34755, jabber:deployment/test\nCommits:\n\n* \u003chttps://GITURL/USERNAME/kubernetes/commit/COMMITSHA\u003e: change test to test webhook\n\nResources updated:\n\n* jabber:deployment/test" + } + ] +} From 80240376668f6a2eae3ee639f74678a1dd4df64d Mon Sep 17 00:00:00 2001 From: Thomas Maier Date: Sun, 5 Jan 2020 15:09:36 +0100 Subject: [PATCH 5/5] gofmt --- handler.go | 61 +++++++++++++++++++++++++++--------------------------- main.go | 4 ++-- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/handler.go b/handler.go index c6a6a4f..4be467e 100644 --- a/handler.go +++ b/handler.go @@ -7,12 +7,12 @@ import ( ) type Response struct { - Message string - Code int + Message string + Code int } -func errorResponse() (Response) { - return Response{"", http.StatusInternalServerError} +func errorResponse() Response { + return Response{"", http.StatusInternalServerError} } // interface for parser functions (grafana, prometheus, ...) @@ -33,7 +33,7 @@ func (h *messageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // send message to xmpp client h.messages <- m w.WriteHeader(response.Code) - w.Write( []byte(response.Message) ) + w.Write([]byte(response.Message)) } // returns new handler with a given parser function @@ -84,26 +84,26 @@ func grafanaParserFunc(r *http.Request) (string, error, Response) { SLACK PARSER *************/ type SlackMessage struct { - Channel string `json:"channel"` - IconEmoji string `json:"icon_emoji"` - Username string `json:"username"` - Text string `json:"text"` - Attachments []SlackAttachment `json:"attachments"` + Channel string `json:"channel"` + IconEmoji string `json:"icon_emoji"` + Username string `json:"username"` + Text string `json:"text"` + Attachments []SlackAttachment `json:"attachments"` } type SlackAttachment struct { - Color string `json:"color"` - Title string `json:"title"` - TitleLink string `json:"title_link"` - Text string `json:"text"` + Color string `json:"color"` + Title string `json:"title"` + TitleLink string `json:"title_link"` + Text string `json:"text"` } -func nonemptyAppendNewline(message string) (string) { - if len(message) == 0 { - return message - } +func nonemptyAppendNewline(message string) string { + if len(message) == 0 { + return message + } - return message+"\n" + return message + "\n" } func slackParserFunc(r *http.Request) (string, error, Response) { @@ -123,19 +123,18 @@ func slackParserFunc(r *http.Request) (string, error, Response) { } // contruct alert message - message := "" - hasText := (alert.Text != "") - if hasText { - message = alert.Text - } - - for _, attachment := range alert.Attachments { - message = nonemptyAppendNewline(message) - message += attachment.Title+"\n" - message += attachment.TitleLink+"\n\n" - message += attachment.Text - } + message := "" + hasText := (alert.Text != "") + if hasText { + message = alert.Text + } + for _, attachment := range alert.Attachments { + message = nonemptyAppendNewline(message) + message += attachment.Title + "\n" + message += attachment.TitleLink + "\n\n" + message += attachment.Text + } return message, nil, Response{"ok", http.StatusOK} } diff --git a/main.go b/main.go index 06cd8dc..857cfd4 100644 --- a/main.go +++ b/main.go @@ -114,7 +114,7 @@ func main() { // create reply with identical contents reply := MessageBody{ Message: stanza.Message{ - To: msg.From.Bare(), + To: msg.From.Bare(), From: address, }, Body: msg.Body, @@ -139,7 +139,7 @@ func main() { // try to send message, ignore errors _ = xmppSession.Encode(MessageBody{ Message: stanza.Message{ - To: recipient, + To: recipient, From: address, }, Body: m,