Skip to content

Commit c812474

Browse files
committed
Support lark webhook notification
1 parent 32efd08 commit c812474

File tree

12 files changed

+259
-1
lines changed

12 files changed

+259
-1
lines changed

cmd/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,6 @@ func init() {
122122
cloudEventConfigCmd,
123123
msteamsConfigCmd,
124124
smtpConfigCmd,
125+
larkConfigCmd,
125126
)
126127
}

cmd/lark.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2018 Bitnami
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cmd
18+
19+
import (
20+
"github.com/bitnami-labs/kubewatch/config"
21+
"github.com/sirupsen/logrus"
22+
"github.com/spf13/cobra"
23+
)
24+
25+
// larkConfigCmd represents the lark subcommand
26+
var larkConfigCmd = &cobra.Command{
27+
Use: "lark",
28+
Short: "specific lark configuration",
29+
Long: `specific lark configuration`,
30+
Run: func(cmd *cobra.Command, args []string) {
31+
conf, err := config.New()
32+
if err != nil {
33+
logrus.Fatal(err)
34+
}
35+
36+
url, err := cmd.Flags().GetString("webhookurl")
37+
if err == nil {
38+
if len(url) > 0 {
39+
conf.Handler.Lark.WebhookURL = url
40+
}
41+
} else {
42+
logrus.Fatal(err)
43+
}
44+
45+
if err = conf.Write(); err != nil {
46+
logrus.Fatal(err)
47+
}
48+
},
49+
}
50+
51+
func init() {
52+
larkConfigCmd.Flags().StringP("webhookurl", "u", "", "Specify lark webhook url")
53+
}

cmd/root.go

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ supported webhooks:
4848
- mattermost
4949
- flock
5050
- webhook
51+
- lark
5152
`,
5253

5354
Run: func(cmd *cobra.Command, args []string) {

config/config.go

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type Handler struct {
4646
CloudEvent CloudEvent `json:"cloudevent"`
4747
MSTeams MSTeams `json:"msteams"`
4848
SMTP SMTP `json:"smtp"`
49+
Lark Lark `json:"lark"`
4950
}
5051

5152
// Resource contains resource configuration
@@ -139,6 +140,12 @@ type Webhook struct {
139140
TlsSkip bool `json:"tlsskip"`
140141
}
141142

143+
// Lark contains lark configuration
144+
type Lark struct {
145+
// Webhook URL.
146+
WebhookURL string `json:"webhookurl"`
147+
}
148+
142149
// CloudEvent contains CloudEvent configuration
143150
type CloudEvent struct {
144151
Url string `json:"url"`

docs/design.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ necessary filtering.
2828

2929
Handler manages how `kubewatch` handles events.
3030

31-
With each event get from k8s and matched filtering from configuration, it is passed to handler. Currently, `kubewatch` has 7 handlers:
31+
With each event get from k8s and matched filtering from configuration, it is passed to handler. Currently, `kubewatch` has 8 handlers:
3232

3333
- `Default`: which just print the event in JSON format
3434
- `Flock`: which send notification to Flock channel based on information from config
@@ -37,6 +37,7 @@ With each event get from k8s and matched filtering from configuration, it is pas
3737
- `MS Teams`: which send notification to MS Team incoming webhook based on information from config
3838
- `Slack`: which send notification to Slack channel based on information from config
3939
- `Smtp`: which sends notifications to email recipients using a SMTP server obtained from config
40+
- `Lark`: which sends notifications to Lark incoming webhook based on information from config
4041

4142
More handlers will be added in future.
4243

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: kubewatch
5+
data:
6+
.kubewatch.yaml: |
7+
namespace:
8+
handler:
9+
lark:
10+
webhookurl: https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx
11+
resource:
12+
namespace: false
13+
deployment: false
14+
replicationcontroller: false
15+
replicaset: false
16+
daemonset: false
17+
services: false
18+
pod: true
19+
secret: false
20+
configmap: false

helm/kubewatch/templates/configmap.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,8 @@ data:
4040
{{- with .Values.extraHandlers }}
4141
{{- toYaml . | nindent 6 }}
4242
{{- end }}
43+
{{- if .Values.lark.enabled }}
44+
lark: {{- toYaml .Values.lark | nindent 8 }}
45+
{{- end }}
4346
resource: {{- toYaml .Values.resourcesToWatch | nindent 6 }}
4447
namespace: {{ .Values.namespaceToWatch | quote }}

helm/kubewatch/values.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ msteams:
140140
webhook:
141141
enabled: false
142142
url: ""
143+
144+
## @param lark.enabled Enable Lark notifications
145+
## @param lark.url lark webhook URL
146+
## See: https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN
147+
##
148+
lark:
149+
enabled: false
150+
webhookurl: ""
151+
143152
smtp:
144153
## @param smtp.enabled Enable SMTP (email) notifications
145154
##

pkg/client/run.go

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/bitnami-labs/kubewatch/pkg/handlers/cloudevent"
2424
"github.com/bitnami-labs/kubewatch/pkg/handlers/flock"
2525
"github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat"
26+
"github.com/bitnami-labs/kubewatch/pkg/handlers/lark"
2627
"github.com/bitnami-labs/kubewatch/pkg/handlers/mattermost"
2728
"github.com/bitnami-labs/kubewatch/pkg/handlers/msteam"
2829
"github.com/bitnami-labs/kubewatch/pkg/handlers/slack"
@@ -62,6 +63,8 @@ func ParseEventHandler(conf *config.Config) handlers.Handler {
6263
eventHandler = new(msteam.MSTeams)
6364
case len(conf.Handler.SMTP.Smarthost) > 0 || len(conf.Handler.SMTP.To) > 0:
6465
eventHandler = new(smtp.SMTP)
66+
case len(conf.Handler.Lark.WebhookURL) > 0:
67+
eventHandler = new(lark.Webhook)
6568
default:
6669
eventHandler = new(handlers.Default)
6770
}

pkg/handlers/handler.go

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/bitnami-labs/kubewatch/pkg/event"
2222
"github.com/bitnami-labs/kubewatch/pkg/handlers/flock"
2323
"github.com/bitnami-labs/kubewatch/pkg/handlers/hipchat"
24+
"github.com/bitnami-labs/kubewatch/pkg/handlers/lark"
2425
"github.com/bitnami-labs/kubewatch/pkg/handlers/mattermost"
2526
"github.com/bitnami-labs/kubewatch/pkg/handlers/msteam"
2627
"github.com/bitnami-labs/kubewatch/pkg/handlers/slack"
@@ -47,6 +48,7 @@ var Map = map[string]interface{}{
4748
"webhook": &webhook.Webhook{},
4849
"ms-teams": &msteam.MSTeams{},
4950
"smtp": &smtp.SMTP{},
51+
"lark": &lark.Webhook{},
5052
}
5153

5254
// Default handler implements Handler interface,

pkg/handlers/lark/webhook.go

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
Copyright 2018 Bitnami
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package lark
18+
19+
import (
20+
"fmt"
21+
"github.com/sirupsen/logrus"
22+
"os"
23+
24+
"bytes"
25+
"encoding/json"
26+
"net/http"
27+
"time"
28+
29+
"github.com/bitnami-labs/kubewatch/config"
30+
"github.com/bitnami-labs/kubewatch/pkg/event"
31+
)
32+
33+
var webhookErrMsg = `
34+
%s
35+
36+
You need to set Lark Webhook url
37+
using "--url/-u", or using environment variables:
38+
39+
export KW_LARK_WEBHOOK_URL=webhook_url
40+
41+
Command line flags will override environment variables
42+
43+
`
44+
45+
// Webhook handler implements handler.Handler interface,
46+
// Notify event to Webhook channel
47+
type Webhook struct {
48+
Url string
49+
}
50+
51+
// TextMessage for messages
52+
type TextMessage struct {
53+
MsgType string `json:"msg_type"`
54+
Content *TextContent `json:"content"`
55+
}
56+
57+
type TextContent struct {
58+
Text string `json:"text"`
59+
}
60+
61+
// Init prepares Webhook configuration
62+
func (m *Webhook) Init(c *config.Config) error {
63+
url := c.Handler.Lark.WebhookURL
64+
if url == "" {
65+
url = os.Getenv("KW_LARK_WEBHOOK_URL")
66+
}
67+
m.Url = url
68+
return checkMissingWebhookVars(m)
69+
}
70+
71+
// Handle handles an event.
72+
func (m *Webhook) Handle(e event.Event) {
73+
webhookMessage := prepareWebhookMessage(e, m)
74+
75+
err := postMessage(m.Url, webhookMessage)
76+
if err != nil {
77+
logrus.Printf("%s\n", err)
78+
return
79+
}
80+
logrus.Printf("Message successfully sent to lark webhook: %s at %s ", m.Url, time.Now())
81+
}
82+
83+
func checkMissingWebhookVars(s *Webhook) error {
84+
if s.Url == "" {
85+
return fmt.Errorf(webhookErrMsg, "Missing Webhook url")
86+
}
87+
return nil
88+
}
89+
90+
func prepareWebhookMessage(e event.Event, m *Webhook) *TextMessage {
91+
return &TextMessage{
92+
MsgType: "text",
93+
Content: &TextContent{Text: e.Message()},
94+
}
95+
}
96+
97+
func postMessage(url string, textMessage *TextMessage) error {
98+
message, err := json.Marshal(textMessage)
99+
if err != nil {
100+
return err
101+
}
102+
req, err := http.NewRequest("POST", url, bytes.NewBuffer(message))
103+
if err != nil {
104+
return err
105+
}
106+
req.Header.Add("Content-Type", "application/json")
107+
108+
client := &http.Client{}
109+
_, err = client.Do(req)
110+
if err != nil {
111+
return err
112+
}
113+
return nil
114+
}

pkg/handlers/lark/webhook_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2018 Bitnami
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package lark
18+
19+
import (
20+
"fmt"
21+
"github.com/bitnami-labs/kubewatch/config"
22+
"reflect"
23+
"testing"
24+
)
25+
26+
func TestWebhookInit(t *testing.T) {
27+
s := &Webhook{}
28+
expectedError := fmt.Errorf(webhookErrMsg, "Missing Webhook url")
29+
30+
var Tests = []struct {
31+
lark config.Lark
32+
err error
33+
}{
34+
{config.Lark{WebhookURL: "foo"}, nil},
35+
{config.Lark{}, expectedError},
36+
}
37+
for _, tt := range Tests {
38+
c := &config.Config{}
39+
c.Handler.Lark = tt.lark
40+
if err := s.Init(c); !reflect.DeepEqual(err, tt.err) {
41+
t.Fatalf("Init(): %v", err)
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)