Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,6 @@ func init() {
msteamsConfigCmd,
smtpConfigCmd,
larkConfigCmd,
discordConfigCmd,
)
}
53 changes: 53 additions & 0 deletions cmd/discord.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2016 Skippbox, Ltd.

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 cmd

import (
"github.com/bitnami-labs/kubewatch/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

// discordConfigCmd represents the msteams subcommand
var discordConfigCmd = &cobra.Command{
Use: "discord",
Short: "specific discord configuration",
Long: `specific discord configuration`,
Run: func(cmd *cobra.Command, args []string) {
conf, err := config.New()
if err != nil {
logrus.Fatal(err)
}

webhookURL, err := cmd.Flags().GetString("webhookurl")
if err == nil {
if len(webhookURL) > 0 {
conf.Handler.Discord.WebhookURL = webhookURL
}
} else {
logrus.Fatal(err)
}

if err = conf.Write(); err != nil {
logrus.Fatal(err)
}
},
}

func init() {
discordConfigCmd.Flags().StringP("webhookurl", "w", "", "Specify Discord webhook URL")
}
5 changes: 4 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ import (
"net/http"
"os"

_ "net/http/pprof"

"github.com/bitnami-labs/kubewatch/config"
c "github.com/bitnami-labs/kubewatch/pkg/client"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
_ "net/http/pprof"
)

var cfgFile string
Expand All @@ -46,9 +47,11 @@ supported webhooks:
- slack
- hipchat
- mattermost
- msteams
- flock
- webhook
- lark
- discord
`,

Run: func(cmd *cobra.Command, args []string) {
Expand Down
5 changes: 5 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Handler struct {
MSTeams MSTeams `json:"msteams"`
SMTP SMTP `json:"smtp"`
Lark Lark `json:"lark"`
Discord Discord `json:"discord"`
}

// Resource contains resource configuration
Expand Down Expand Up @@ -197,6 +198,10 @@ type SMTPAuth struct {
Secret string `json:"secret" yaml:"secret,omitempty"`
}

type Discord struct {
WebhookURL string `json:"webhookurl"`
}

// New creates new config object
func New() (*Config, error) {
c := &Config{}
Expand Down
10 changes: 4 additions & 6 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ limitations under the License.

package config

import (
//"io/ioutil"
//"os"
//"testing"
)
// "io/ioutil"
// "os"
// "testing"

var configStr = `
{
Expand Down Expand Up @@ -50,7 +48,7 @@ var configStr = `

//func TestLoadOK(t *testing.T) {
// content := []byte(configStr)
// tmpConfigFile, err := ioutil.TempFile(homeDir(), "kubewatch")
// tmpConfigFile, err := os.CreateTemp(homeDir(), "kubewatch")
// if err != nil {
// t.Fatalf("TestLoad(): %+v", err)
// }
Expand Down
2 changes: 2 additions & 0 deletions config/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ handler:
msteams:
# MSTeams API Webhook URL.
webhookurl: ""
discord:
webhookurl: ""
smtp:
# Destination e-mail address.
to: ""
Expand Down
1 change: 1 addition & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ With each event get from k8s and matched filtering from configuration, it is pas
- `Slack`: which send notification to Slack channel based on information from config
- `Smtp`: which sends notifications to email recipients using a SMTP server obtained from config
- `Lark`: which sends notifications to Lark incoming webhook based on information from config
- `Discord`: which sends notifications to Discord channel based on information from config

More handlers will be added in future.

Expand Down
23 changes: 23 additions & 0 deletions examples/conf/kubewatch.conf.discord.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
### why add query wait=true?
## follow docs: https://discord.com/developers/docs/resources/webhook#execute-webhook

apiVersion: v1
kind: ConfigMap
metadata:
name: kubewatch
data:
.kubewatch.yaml: |
namespace:
handler:
discord:
webhookurl: "<url>?wait=true"
resource:
namespace: false
deployment: false
replicationcontroller: false
replicaset: false
daemonset: false
services: false
pod: true
secret: false
configmap: false
54 changes: 47 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,26 +1,66 @@
module github.com/bitnami-labs/kubewatch

go 1.14
go 1.21

require (
github.com/fatih/structtag v1.2.0
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/magiconair/properties v1.7.4 // indirect
github.com/mkmik/multierror v0.3.0
github.com/pelletier/go-toml v1.0.1 // indirect
github.com/prometheus/client_golang v1.20.3
github.com/segmentio/textio v1.2.0
github.com/sirupsen/logrus v1.6.0
github.com/slack-go/slack v0.6.5
github.com/spf13/cast v1.1.0 // indirect
github.com/spf13/cobra v0.0.1
github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec // indirect
github.com/spf13/viper v1.0.0
github.com/tbruyelle/hipchat-go v0.0.0-20160921153256-749fb9e14beb
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.20.15
k8s.io/apimachinery v0.20.15
k8s.io/client-go v0.20.15
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-logr/logr v0.2.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/go-cmp v0.5.2 // indirect
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gnostic v0.4.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb // indirect
github.com/imdario/mergo v0.3.5 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/magiconair/properties v1.7.4 // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pelletier/go-toml v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.1.0 // indirect
github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
k8s.io/klog/v2 v2.4.0 // indirect
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
3 changes: 3 additions & 0 deletions pkg/client/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/bitnami-labs/kubewatch/pkg/controller"
"github.com/bitnami-labs/kubewatch/pkg/handlers"
"github.com/bitnami-labs/kubewatch/pkg/handlers/cloudevent"
"github.com/bitnami-labs/kubewatch/pkg/handlers/discord"
"github.com/bitnami-labs/kubewatch/pkg/handlers/flock"
"github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat"
"github.com/bitnami-labs/kubewatch/pkg/handlers/lark"
Expand Down Expand Up @@ -81,6 +82,8 @@ func ParseEventHandler(conf *config.Config) handlers.Handler {
eventHandler = new(smtp.SMTP)
case len(conf.Handler.Lark.WebhookURL) > 0:
eventHandler = new(lark.Webhook)
case len(conf.Handler.Discord.WebhookURL) > 0:
eventHandler = new(discord.Discord)
default:
eventHandler = new(handlers.Default)
}
Expand Down
123 changes: 123 additions & 0 deletions pkg/handlers/discord/discord.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
Copyright 2016 Skippbox, Ltd.

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 discord

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

"github.com/bitnami-labs/kubewatch/config"
"github.com/bitnami-labs/kubewatch/pkg/event"
"github.com/bitnami-labs/kubewatch/pkg/handlers"
"github.com/sirupsen/logrus"
)

var dcErrMsg = `
%s

You need to set the MS teams webhook URL,
using --webhookURL, or using environment variables:

export KW_DISCORD_WEBHOOKURL=webhook_url

Command line flags will override environment variables

`
var dcColors = map[string]int{
"Normal": 8311585,
"Warning": 16312092,
"Danger": 13632027,
}

type Discord struct {
DcWebhookURL string
}

type DiscordMsg struct {
Embeds []DiscordEmbed `json:"embeds"`
}

type DiscordEmbed struct {
Color int `json:"color"`
Title string `json:"title"`
}

var _ handlers.Handler = &Discord{}

func (dc *Discord) Init(c *config.Config) error {
webhookURL := c.Handler.Discord.WebhookURL

if webhookURL == "" {
webhookURL = os.Getenv("KW_DISCORD_WEBHOOKURL")
}

if webhookURL == "" {
return fmt.Errorf(dcErrMsg, "Missing Discord webhook URL")
}

dc.DcWebhookURL = webhookURL
return nil
}

func (dc *Discord) Handle(e event.Event) {
msg := &DiscordMsg{}

var embed DiscordEmbed
embed.Color = dcColors[e.Status]
embed.Title = e.Message()

msg.Embeds = append(msg.Embeds, embed)

_, err := sendMessage(dc, msg)
if err != nil {
logrus.Printf("%s\n", err)
return
}

logrus.Printf("Message successfully sent to Discord")
}

func sendMessage(dc *Discord, discordMsg *DiscordMsg) (*http.Response, error) {
buffer := new(bytes.Buffer)
if err := json.NewEncoder(buffer).Encode(discordMsg); err != nil {
return nil, fmt.Errorf("Failed encoding message: %v", err)
}

res, err := http.Post(dc.DcWebhookURL, "application/json", buffer)
if err != nil {
return nil, fmt.Errorf("Failed sending to webhook url %s. Got the error: %v", dc.DcWebhookURL, err)
}

if res.StatusCode != http.StatusOK {
resMessage, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("Failed reading Discord http response: %v", err)
}
return nil, fmt.Errorf("Failed sending to Discord channel. Discord http response: %s, %s",
res.Status, string(resMessage))
}

if err := res.Body.Close(); err != nil {
return nil, err
}

return res, nil
}
Loading