mirror of
https://github.com/fluxcd/flagger.git
synced 2026-04-15 06:57:34 +00:00
Add support for Google Chat alerts (#953)
Add gchat alerting support Signed-off-by: fpinna <fplkid@gmail.com>
This commit is contained in:
@@ -16,7 +16,7 @@ Flagger implements several deployment strategies (Canary releases, A/B testing,
|
||||
using a service mesh (App Mesh, Istio, Linkerd, Open Service Mesh)
|
||||
or an ingress controller (Contour, Gloo, NGINX, Skipper, Traefik) for traffic routing.
|
||||
For release analysis, Flagger can query Prometheus, Datadog, New Relic or CloudWatch
|
||||
and for alerting it uses Slack, MS Teams, Discord and Rocket.
|
||||
and for alerting it uses Slack, MS Teams, Discord, Rocket and Google Chat.
|
||||
|
||||
Flagger is a [Cloud Native Computing Foundation](https://cncf.io/) project
|
||||
and part of [Flux](https://fluxcd.io) family of GitOps tools.
|
||||
|
||||
@@ -1191,6 +1191,7 @@ spec:
|
||||
- msteams
|
||||
- discord
|
||||
- rocket
|
||||
- gchat
|
||||
channel:
|
||||
description: Alert channel for this provider
|
||||
type: string
|
||||
|
||||
@@ -1191,6 +1191,7 @@ spec:
|
||||
- msteams
|
||||
- discord
|
||||
- rocket
|
||||
- gchat
|
||||
channel:
|
||||
description: Alert channel for this provider
|
||||
type: string
|
||||
|
||||
1
go.sum
1
go.sum
@@ -283,6 +283,7 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
||||
@@ -1191,6 +1191,7 @@ spec:
|
||||
- msteams
|
||||
- discord
|
||||
- rocket
|
||||
- gchat
|
||||
channel:
|
||||
description: Alert channel for this provider
|
||||
type: string
|
||||
|
||||
@@ -52,6 +52,8 @@ func (f Factory) Notifier(provider string) (Interface, error) {
|
||||
n, err = NewRocket(f.URL, f.ProxyURL, f.Username, f.Channel)
|
||||
case "msteams":
|
||||
n, err = NewMSTeams(f.URL, f.ProxyURL)
|
||||
case "gchat":
|
||||
n, err = NewGChat(f.URL, f.ProxyURL)
|
||||
default:
|
||||
err = fmt.Errorf("provider %s not supported", provider)
|
||||
}
|
||||
|
||||
120
pkg/notifier/gchat.go
Normal file
120
pkg/notifier/gchat.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Google Chat holds the incoming webhook URL
|
||||
type GChat struct {
|
||||
URL string
|
||||
ProxyURL string
|
||||
}
|
||||
|
||||
// GChatPayload holds the message
|
||||
type GChatPayload struct {
|
||||
Cards []GChatCards `json:"cards"`
|
||||
}
|
||||
|
||||
// Start - GChatCards holds the canary analysis result
|
||||
type GChatCards struct {
|
||||
Header GChatHeader `json:"header"`
|
||||
Sections []*GChatSections `json:"sections"`
|
||||
}
|
||||
|
||||
type GChatHeader struct {
|
||||
Title string `json:"title"`
|
||||
SubTitle string `json:"subtitle"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
}
|
||||
|
||||
type GChatSections struct {
|
||||
Widgets []GChatWidgets `json:"widgets"`
|
||||
}
|
||||
|
||||
type GChatWidgets struct {
|
||||
TextParagraph GChatText `json:"textParagraph"`
|
||||
}
|
||||
|
||||
type GChatField struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type GChatText struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// NewGChat validates the GChat URL and returns a GChat object
|
||||
func NewGChat(hookURL string, proxyURL string) (*GChat, error) {
|
||||
_, err := url.ParseRequestURI(hookURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid Google Chat webhook URL %s", hookURL)
|
||||
}
|
||||
|
||||
return &GChat{
|
||||
URL: hookURL,
|
||||
ProxyURL: proxyURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Post Google Chat message
|
||||
func (s *GChat) Post(workload string, namespace string, message string, fields []Field, severity string) error {
|
||||
facts := make([]*GChatSections, 0, len(fields))
|
||||
facts = append(facts, &GChatSections{
|
||||
Widgets: []GChatWidgets{
|
||||
{
|
||||
TextParagraph: GChatText{
|
||||
Text: "<font color=#848484><strong>" + message + "</strong></font>",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
for _, f := range fields {
|
||||
facts = append(facts, &GChatSections{
|
||||
Widgets: []GChatWidgets{
|
||||
{
|
||||
TextParagraph: GChatText{
|
||||
Text: f.Name + "<br><font color=#848484><strong>" + f.Value + "</strong></font>",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
payload := GChatPayload{
|
||||
Cards: []GChatCards{
|
||||
{
|
||||
Header: GChatHeader{
|
||||
Title: "Flagger",
|
||||
SubTitle: fmt.Sprintf("%s.%s", workload, namespace),
|
||||
ImageUrl: "https://flagger.app/favicon.png",
|
||||
},
|
||||
Sections: facts,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := postMessage(s.URL, s.ProxyURL, payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("postMessage failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
53
pkg/notifier/gchat_test.go
Normal file
53
pkg/notifier/gchat_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGChat_Post(t *testing.T) {
|
||||
|
||||
fields := []Field{
|
||||
{Name: "name1", Value: "value1"},
|
||||
{Name: "name2", Value: "value2"},
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var payload = GChatPayload{}
|
||||
err = json.Unmarshal(b, &payload)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "podinfo.test", payload.Cards[0].Header.SubTitle)
|
||||
require.Equal(t, len(fields), len(payload.Cards[0].Sections)-1)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
GChat, err := NewGChat(ts.URL, "")
|
||||
require.NoError(t, err)
|
||||
|
||||
err = GChat.Post("podinfo", "test", "test", fields, "info")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
Reference in New Issue
Block a user