Skip to content

Commit

Permalink
feat: add mattermost sink (#303)
Browse files Browse the repository at this point in the history
* feat: add mattermost sink

Signed-off-by: tozastation <tozastation@gmail.com>

* feat: add mattermost sink on README.md

Signed-off-by: tozastation <tozastation@gmail.com>

---------

Signed-off-by: tozastation <tozastation@gmail.com>
Co-authored-by: Alex Jones <alexsimonjones@gmail.com>
  • Loading branch information
tozastation and AlexsJones committed Jan 11, 2024
1 parent a1edb2e commit c6ff954
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 2 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,19 @@ EOF
</details>
<details>
<summary>sink (integrations) </summary>
Optional parameters available for sink.
('type', 'webhook' are required parameters.)
| tool | channel | icon_url | username |
|------------|---------|----------|----------|
| Slack | | | |
| Mattermost | ✔️ | ✔️ | ✔️ |
</details>
## Helm values
For details please see [here](chart/operator/values.yaml)
Expand Down
5 changes: 4 additions & 1 deletion api/v1alpha1/k8sgpt_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ type GCSBackend struct {
}

type WebhookRef struct {
// +kubebuilder:validation:Enum=slack
// +kubebuilder:validation:Enum=slack;mattermost
Type string `json:"type,omitempty"`
Endpoint string `json:"webhook,omitempty"`
Channel string `json:"channel,omitempty"`
UserName string `json:"username,omitempty"`
IconURL string `json:"icon_url,omitempty"`
}

type AISpec struct {
Expand Down
7 changes: 7 additions & 0 deletions chart/operator/templates/k8sgpt-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,16 @@ spec:
type: string
sink:
properties:
channel:
type: string
icon_url:
type: string
type:
enum:
- slack
- mattermost
type: string
username:
type: string
webhook:
type: string
Expand Down
7 changes: 7 additions & 0 deletions config/crd/bases/core.k8sgpt.ai_k8sgpts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,16 @@ spec:
type: string
sink:
properties:
channel:
type: string
icon_url:
type: string
type:
enum:
- slack
- mattermost
type: string
username:
type: string
webhook:
type: string
Expand Down
107 changes: 107 additions & 0 deletions pkg/sinks/mattermost.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package sinks

import (
"bytes"
"encoding/json"
"fmt"
"net/http"

"github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1"
)

var _ ISink = (*MattermostSink)(nil)

type MattermostSink struct {
Endpoint string
K8sGPT string
Client Client
Channel string
UserName string
IconURL string
}

type MattermostMessage struct {
Text string `json:"text"`
Channel string `json:"channel,omitempty"`
UserName string `json:"username,omitempty"`
IconURL string `json:"icon_url,omitempty"`
Attachments []attachment `json:"attachments"`
}

type attachment struct {
Text string `json:"text"`
Color string `json:"color"`
Title string `json:"title"`
}

func buildMattermostMessage(kind, name, details, k8sgptCR, channel, username, iconURL string) MattermostMessage {
return MattermostMessage{
Text: fmt.Sprintf(">*[%s] K8sGPT analysis of the %s %s*", k8sgptCR, kind, name),
Channel: channel,
UserName: username,
IconURL: iconURL,
Attachments: []attachment{
attachment{
Text: details,
Color: "danger",
Title: "Report",
},
},
}
}

func (s *MattermostSink) Configure(config v1alpha1.K8sGPT, c Client) {
s.Endpoint = config.Spec.Sink.Endpoint
// If no value is given, the default value of the webhook is used
if config.Spec.Sink.Channel != "" {
s.Channel = config.Spec.Sink.Channel
}
// If no value is given, the default value of the webhook is used
if config.Spec.Sink.UserName != "" {
s.UserName = config.Spec.Sink.UserName
}
// If no value is given, the default value of the webhook is used
if config.Spec.Sink.IconURL != "" {
s.IconURL = config.Spec.Sink.IconURL
}
s.Client = c
// take the name of the K8sGPT Custom Resource
s.K8sGPT = config.Name
}

func (s *MattermostSink) Emit(results v1alpha1.ResultSpec) error {
details := ""
// If AI is set to False, Details will not have a value, so if it is empty, use the Error text.
if results.Details == "" && len(results.Error) > 0 {
for i, v := range results.Error {
details += fmt.Sprintf("%d. %s\n", i+1, v.Text)
}
} else {
details = results.Details
}
message := buildMattermostMessage(
results.Kind, results.Name, details, s.K8sGPT,
s.Channel, s.UserName, s.IconURL,
)
payload, err := json.Marshal(message)
if err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, s.Endpoint, bytes.NewBuffer(payload))
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/json")
resp, err := s.Client.hclient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to send report: %s", resp.Status)
}

return nil
}
4 changes: 3 additions & 1 deletion pkg/sinks/sinkreporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ func NewSink(sinkType string) ISink {
switch sinkType {
case "slack":
return &SlackSink{}
//Introduce more Sink Providers
//Introduce more Sink Providers
case "mattermost":
return &MattermostSink{}
default:
return &SlackSink{}
}
Expand Down

0 comments on commit c6ff954

Please sign in to comment.