diff --git a/artifacts/flagger/crd.yaml b/artifacts/flagger/crd.yaml index 2baca216..5bbd94de 100644 --- a/artifacts/flagger/crd.yaml +++ b/artifacts/flagger/crd.yaml @@ -637,6 +637,7 @@ spec: - slack - msteams - discord + - rocket address: description: Hook URL address of this provider type: string diff --git a/charts/flagger/templates/crd.yaml b/charts/flagger/templates/crd.yaml index 05c436e2..5e3e7ebc 100644 --- a/charts/flagger/templates/crd.yaml +++ b/charts/flagger/templates/crd.yaml @@ -638,6 +638,7 @@ spec: - slack - msteams - discord + - rocket address: description: Hook URL address of this provider type: string diff --git a/kustomize/base/flagger/crd.yaml b/kustomize/base/flagger/crd.yaml index 2baca216..5bbd94de 100644 --- a/kustomize/base/flagger/crd.yaml +++ b/kustomize/base/flagger/crd.yaml @@ -637,6 +637,7 @@ spec: - slack - msteams - discord + - rocket address: description: Hook URL address of this provider type: string diff --git a/pkg/notifier/factory.go b/pkg/notifier/factory.go index cf4fa85c..deabe4b8 100644 --- a/pkg/notifier/factory.go +++ b/pkg/notifier/factory.go @@ -22,6 +22,8 @@ func (f Factory) Notifier(provider string) (Interface, error) { return NewSlack(f.URL, f.Username, f.Channel) case provider == "discord": return NewDiscord(f.URL, f.Username, f.Channel) + case provider == "rocket": + return NewRocket(f.URL, f.Username, f.Channel) case provider == "msteams": return NewMSTeams(f.URL) } diff --git a/pkg/notifier/rocket.go b/pkg/notifier/rocket.go new file mode 100644 index 00000000..4bdf549f --- /dev/null +++ b/pkg/notifier/rocket.go @@ -0,0 +1,72 @@ +package notifier + +import ( + "errors" + "fmt" + "net/url" +) + +// Rocket holds the hook URL +type Rocket struct { + URL string + Username string + Channel string +} + +// NewRocket validates the Rocket URL and returns a Rocket object +func NewRocket(hookURL string, username string, channel string) (*Rocket, error) { + _, err := url.ParseRequestURI(hookURL) + if err != nil { + return nil, fmt.Errorf("invalid Rocket hook URL %s", hookURL) + } + + if username == "" { + return nil, errors.New("empty Rocket username") + } + + if channel == "" { + return nil, errors.New("empty Rocket channel") + } + + return &Rocket{ + Channel: channel, + URL: hookURL, + Username: username, + }, nil +} + +// Post Rocket message +func (s *Rocket) Post(workload string, namespace string, message string, fields []Field, severity string) error { + payload := SlackPayload{ + Channel: s.Channel, + Username: s.Username, + IconEmoji: ":rocket:", + } + + color := "#0076D7" + if severity == "error" { + color = "#FF0000" + } + + sfields := make([]SlackField, 0, len(fields)) + for _, f := range fields { + sfields = append(sfields, SlackField{f.Name, f.Value, false}) + } + + a := SlackAttachment{ + Color: color, + AuthorName: fmt.Sprintf("%s.%s", workload, namespace), + Text: message, + MrkdwnIn: []string{"text"}, + Fields: sfields, + } + + payload.Attachments = []SlackAttachment{a} + + err := postMessage(s.URL, payload) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/notifier/rocket_test.go b/pkg/notifier/rocket_test.go new file mode 100644 index 00000000..2d4daab8 --- /dev/null +++ b/pkg/notifier/rocket_test.go @@ -0,0 +1,44 @@ +package notifier + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" +) + +func TestSlack_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) + if err != nil { + t.Fatal(err) + } + var payload = SlackPayload{} + err = json.Unmarshal(b, &payload) + + if payload.Attachments[0].AuthorName != "podinfo.test" { + t.Fatal("wrong author name") + } + + if len(payload.Attachments[0].Fields) != len(fields) { + t.Fatal("wrong facts") + } + })) + defer ts.Close() + + slack, err := NewSlack(ts.URL, "test", "test") + if err != nil { + t.Fatal(err) + } + + err = slack.Post("podinfo", "test", "test", fields, "error") + if err != nil { + t.Fatal(err) + } +} diff --git a/pkg/notifier/slack_test.go b/pkg/notifier/slack_test.go index 2d4daab8..4399f2a6 100644 --- a/pkg/notifier/slack_test.go +++ b/pkg/notifier/slack_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestSlack_Post(t *testing.T) { +func TestRocket_Post(t *testing.T) { fields := []Field{ {Name: "name1", Value: "value1"}, {Name: "name2", Value: "value2"}, @@ -27,17 +27,17 @@ func TestSlack_Post(t *testing.T) { } if len(payload.Attachments[0].Fields) != len(fields) { - t.Fatal("wrong facts") + t.Fatal("wrong field") } })) defer ts.Close() - slack, err := NewSlack(ts.URL, "test", "test") + rocket, err := NewRocket(ts.URL, "test", "test") if err != nil { t.Fatal(err) } - err = slack.Post("podinfo", "test", "test", fields, "error") + err = rocket.Post("podinfo", "test", "test", fields, "error") if err != nil { t.Fatal(err) }