Skip to content
Merged
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
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ RUN sed -i 's/dev/'"${RELEASE_VERSION}"'/g' version/version.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o kwatch .

FROM alpine:latest
RUN apk add --update ca-certificates
RUN apk add --update ca-certificates && \
adduser -D -u 1000 kwatch && \
rm -rf /var/cache/apk/*
COPY --from=builder /build/kwatch /bin/kwatch
USER kwatch
ENTRYPOINT ["/bin/kwatch"]
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ kubectl apply -f https://raw.githubusercontent.com/abahmed/kwatch/v0.10.4/deploy
| `app.logFormatter` | used for setting custom formatter when app prints logs: text, json (default: text) |


### Telemetry (Not Released)

| Parameter | Description |
|:------------------------------|:------------------------------------------- |
| `telemetry.enabled` | If set to true, anonymous telemetry data (cluster ID and version) is sent on first run to help track kwatch usage (default: false) |


### Health Check (Not Released)

| Parameter | Description |
|:------------------------------|:------------------------------------------- |
| `healthCheck.enabled` | If set to true, enables health check endpoints (default: false) |
| `healthCheck.port` | Port for health check endpoints (default: 8060) |

**Endpoints:**
- `GET /healthz` - Returns "OK" (text/plain)
- `GET /health` - Returns `{"status": "ok"}` (application/json)


### Upgrader

| Parameter | Description |
Expand Down
48 changes: 35 additions & 13 deletions alertmanager/dingtalk/dingtalk.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/abahmed/kwatch/config"
"github.com/abahmed/kwatch/constant"
"github.com/abahmed/kwatch/event"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -66,30 +67,51 @@ func (d *DingTalk) Name() string {

// SendEvent sends event to the provider
func (d *DingTalk) SendEvent(e *event.Event) error {

// use custom title if it's provided, otherwise use default
title := d.title
if len(title) == 0 {
title = constant.DefaultTitle
}

msg := e.FormatMarkdown(d.appCfg.ClusterName, "", "")

body := fmt.Sprintf(`{
"msgtype": "markdown",
"markdown": { "title": "%s", "text: "%s" }
}`, title, msg)
payload := struct {
MsgType string `json:"msgtype"`
Markdown struct {
Title string `json:"title"`
Text string `json:"text"`
} `json:"markdown"`
}{
MsgType: "markdown",
}
payload.Markdown.Title = title
payload.Markdown.Text = msg

bodyBytes, err := json.Marshal(payload)
if err != nil {
return err
}

return d.sendAPI(body)
return d.sendAPI(string(bodyBytes))
}

// SendMessage sends text message to the provider
func (d *DingTalk) SendMessage(msg string) error {
body := fmt.Sprintf(`{
"msgtype": "text",
"text": { "content": "%s"}
}`, msg)
return d.sendAPI(body)
payload := struct {
MsgType string `json:"msgtype"`
Text struct {
Content string `json:"content"`
} `json:"text"`
}{
MsgType: "text",
}
payload.Text.Content = msg

bodyBytes, err := json.Marshal(payload)
if err != nil {
return err
}

return d.sendAPI(string(bodyBytes))
}

func (d *DingTalk) sendAPI(msg string) error {
Expand All @@ -111,7 +133,7 @@ func (d *DingTalk) sendAPI(msg string) error {

request.Header.Set("Content-Type", "application/json")

client := &http.Client{}
client := util.GetDefaultClient()
response, err := client.Do(request)
if err != nil {
return err
Expand Down
41 changes: 37 additions & 4 deletions alertmanager/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/sirupsen/logrus"
)

const (
chunkSize = 1024
)

type Discord struct {
id string
token string
Expand Down Expand Up @@ -90,6 +94,11 @@ func (s *Discord) SendEvent(ev *event.Event) error {
Value: ev.Namespace,
Inline: true,
},
{
Name: "Node",
Value: ev.NodeName,
Inline: true,
},
{
Name: "Reason",
Value: ev.Reason,
Expand All @@ -100,10 +109,12 @@ func (s *Discord) SendEvent(ev *event.Event) error {
// add events part if it exists
events := strings.TrimSpace(ev.Events)
if len(events) > 0 {
fields = append(fields, &discordgo.MessageEmbedField{
Name: ":mag: Events",
Value: "```\n" + events + "```",
})
for _, chunk := range chunks(events, chunkSize) {
fields = append(fields, &discordgo.MessageEmbedField{
Name: ":mag: Events",
Value: "```\n" + chunk + "```",
})
}
}

// add logs part if it exists
Expand Down Expand Up @@ -166,3 +177,25 @@ func (s *Discord) SendMessage(msg string) error {
})
return err
}

func chunks(s string, chunkSize int) []string {
if chunkSize >= len(s) {
return []string{s}
}

var chunks []string = make([]string, 0, (len(s)-1)/chunkSize+1)
currentLen := 0
currentStart := 0

for i := range s {
if currentLen == chunkSize {
chunks = append(chunks, s[currentStart:i])
currentLen = 0
currentStart = i
}
currentLen++
}

chunks = append(chunks, s[currentStart:])
return chunks
}
19 changes: 19 additions & 0 deletions alertmanager/discord/discord_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package discord

import (
"strings"
"testing"

"github.com/abahmed/kwatch/config"
Expand Down Expand Up @@ -99,3 +100,21 @@ func TestSendEvent(t *testing.T) {
}
assert.Nil(c.SendEvent(&ev))
}

func TestChunks(t *testing.T) {
assert := assert.New(t)

result := chunks("short", 1024)
assert.Equal([]string{"short"}, result)

longString := strings.Repeat("a", 2000)
result = chunks(longString, 1024)
assert.Equal(2, len(result))
assert.Equal(1024, len(result[0]))
assert.Equal(976, len(result[1]))

exactChunk := strings.Repeat("b", 1024)
result = chunks(exactChunk, 1024)
assert.Equal(1, len(result))
assert.Equal(1024, len(result[0]))
}
9 changes: 5 additions & 4 deletions alertmanager/email/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,13 @@ func (e *Email) buildMessageSubjectAndBody(

subject := fmt.Sprintf("⛑ Kwatch detected a crash in pod %s ", ev.ContainerName)
body := fmt.Sprintf(
"An alert for cluster: *%s* Name: *%s* Container: *%s* "+
"Namespace: *%s* "+
"has been triggered:\\n—\\n "+
"Logs: *%s* \\n "+
"An alert for cluster: *%s* Node: *%s* Name: *%s* "+
"Container: *%s* Namespace: *%s* "+
"has been triggered:\n—\n "+
"Logs: *%s* \n "+
"Events: *%s* ",
e.appCfg.ClusterName,
ev.NodeName,
ev.PodName,
ev.ContainerName,
ev.Namespace,
Expand Down
1 change: 1 addition & 0 deletions alertmanager/email/email_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func TestSendEvent(t *testing.T) {

c.send = mockedSend
ev := event.Event{
NodeName: "test-node",
PodName: "test-pod",
ContainerName: "test-container",
Namespace: "default",
Expand Down
3 changes: 2 additions & 1 deletion alertmanager/feishu/feishu.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/abahmed/kwatch/config"
"github.com/abahmed/kwatch/event"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -57,7 +58,7 @@ func (r *FeiShu) SendEvent(e *event.Event) error {
}

func (r *FeiShu) sendByFeiShuApi(reqBody string) error {
client := &http.Client{}
client := util.GetDefaultClient()
buffer := bytes.NewBuffer([]byte(reqBody))
request, err := http.NewRequest(http.MethodPost, r.webhook, buffer)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion alertmanager/feishu/feishu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func TestBuildRequestBodyFeiShu(t *testing.T) {
c := NewFeiShu(configMap, &config.App{ClusterName: "dev"})
assertions.NotNil(c)
ev := event.Event{
NodeName: "test-node",
PodName: "test-pod",
ContainerName: "test-container",
Namespace: "default",
Expand All @@ -53,7 +54,7 @@ func TestBuildRequestBodyFeiShu(t *testing.T) {
}
formattedMsg := ev.FormatMarkdown(c.appCfg.ClusterName, "", "")

expectMessage := "{\"msg_type\": \"interactive\",\"card\": {\"config\": {\"wide_screen_mode\": true},\"header\": {\"title\": {\"tag\": \"plain_text\",\"content\": \"\"},\"template\": \"blue\"},\"elements\": [{\"tag\":\"markdown\",\"content\":\"There is an issue with container in a pod!\\n**Cluster:** dev\\n**Pod:** test-pod\\n**Container:** test-container\\n**Namespace:** default\\n**Reason:** OOMKILLED\\n**Events:**\\n```\\ntest\\n```\\n**Logs:**\\n```\\ntest\\ntestlogs\\n```\"}]}}"
expectMessage := "{\"msg_type\": \"interactive\",\"card\": {\"config\": {\"wide_screen_mode\": true},\"header\": {\"title\": {\"tag\": \"plain_text\",\"content\": \"\"},\"template\": \"blue\"},\"elements\": [{\"tag\":\"markdown\",\"content\":\"There is an issue with container in a pod!\\n**Cluster:** dev\\n**Pod:** test-pod\\n**Container:** test-container\\n**Namespace:** default\\n**Node:** test-node\\n**Reason:** OOMKILLED\\n**Events:**\\n```\\ntest\\n```\\n**Logs:**\\n```\\ntest\\ntestlogs\\n```\"}]}}"

assertions.Equal(expectMessage, c.buildRequestBodyFeiShu(formattedMsg))
}
Expand Down Expand Up @@ -113,6 +114,7 @@ func TestSendEvent(t *testing.T) {
assertions.NotNil(c)

ev := event.Event{
NodeName: "test-node",
PodName: "test-pod",
ContainerName: "test-container",
Namespace: "default",
Expand Down
3 changes: 2 additions & 1 deletion alertmanager/googlechat/googlechat.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/abahmed/kwatch/config"
"github.com/abahmed/kwatch/event"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -55,7 +56,7 @@ func (r *GoogleChat) SendEvent(e *event.Event) error {
}

func (r *GoogleChat) sendAPI(reqBody string) error {
client := &http.Client{}
client := util.GetDefaultClient()
buffer := bytes.NewBuffer([]byte(reqBody))
request, err := http.NewRequest(http.MethodPost, r.webhook, buffer)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion alertmanager/matrix/matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (m *Matrix) sendAPI(formattedMsg string) error {
}

request.Header.Set("Content-Type", "application/json")
client := &http.Client{}
client := util.GetDefaultClient()
response, err := client.Do(request)
if err != nil {
return err
Expand Down
8 changes: 7 additions & 1 deletion alertmanager/mattermost/mattermost.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/abahmed/kwatch/config"
"github.com/abahmed/kwatch/constant"
"github.com/abahmed/kwatch/event"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -81,7 +82,7 @@ func (m *Mattermost) SendEvent(e *event.Event) error {
}

func (m *Mattermost) sendAPI(content []byte) error {
client := &http.Client{}
client := util.GetDefaultClient()
buffer := bytes.NewBuffer(content)
request, err := http.NewRequest(http.MethodPost, m.webhook, buffer)
if err != nil {
Expand Down Expand Up @@ -162,6 +163,11 @@ func (m *Mattermost) buildMessage(e *event.Event, msg *string) []byte {
Value: e.Namespace,
Short: true,
},
{
Title: "Node",
Value: e.NodeName,
Short: true,
},
{
Title: "Reason",
Value: e.Reason,
Expand Down
4 changes: 3 additions & 1 deletion alertmanager/opsgenie/opsgenie.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/abahmed/kwatch/config"
"github.com/abahmed/kwatch/constant"
"github.com/abahmed/kwatch/event"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -75,7 +76,7 @@ func (m *Opsgenie) SendEvent(e *event.Event) error {

// sendAPI sends http request to Opsgenie API
func (m *Opsgenie) sendAPI(content []byte) error {
client := &http.Client{}
client := util.GetDefaultClient()
buffer := bytes.NewBuffer(content)
request, err := http.NewRequest(http.MethodPost, m.url, buffer)
if err != nil {
Expand Down Expand Up @@ -137,6 +138,7 @@ func (m *Opsgenie) buildMessage(e *event.Event) []byte {
"Name": e.PodName,
"Container": e.ContainerName,
"Namespace": e.Namespace,
"Node": e.NodeName,
"Reason": e.Reason,
"Events": events,
"Logs": logs,
Expand Down
Loading
Loading