Skip to content

Commit

Permalink
🎉 Support versioning (#12)
Browse files Browse the repository at this point in the history
* support versioning

* update comments

* update alert config
  • Loading branch information
abahmed authored Dec 19, 2021
1 parent 9bf19d6 commit 727bb0c
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 95 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ jobs:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
labels: ${{ steps.meta.outputs.labels }}
build-args: RELEASE_VERSION=${{ steps.meta.outputs.version }}
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM golang:alpine AS builder
ARG RELEASE_VERSION="nothing"
LABEL maintainer="Abdelrahman Ahmed <[email protected]"

RUN apk update && \
Expand All @@ -11,6 +12,7 @@ COPY go.mod go.sum /build/
RUN go mod download

COPY . /build/
RUN sed -i '' -e 's/dev/'"${RELEASE_VERSION}"'/g' constant/constant.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a --installsuffix cgo --ldflags="-s"

FROM alpine:latest
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,23 @@ kubectl apply -f https://raw.githubusercontent.com/abahmed/kwatch/v0.0.4/deploy/

### Configuration

| Parameter | Description |Required |
|:--------------------------|:----------------------------------------- |:-------------- |
| `maxRecentLogLines` | Max tail log lines in messages | No |
| `providers.slack.webhook` | Slack webhook URL | Yes |
| `providers.slack.title` | Customized title in slack message | No |
| `providers.slack.text` | Customized text in slack message | No |
| `providers.discord.webhook` | Discord webhook URL | Yes |
| `providers.discord.title` | Customized title in discord message | No |
| `providers.discord.text` | Customized text in discord message | No |
| `providers.pagerduty.integrationKey` | PagerDuty integration key [more info](https://support.pagerduty.com/docs/services-and-integrations) | Yes |
| Parameter | Description |
|:-------------------------------------|:------------------------------------------- |
| `maxRecentLogLines` | Max tail log lines in messages |
| `providers.slack.webhook` | Slack webhook URL |
| `providers.slack.title` | Customized title in slack message |
| `providers.slack.text` | Customized text in slack message |
| `providers.discord.webhook` | Discord webhook URL |
| `providers.discord.title` | Customized title in discord message |
| `providers.discord.text` | Customized text in discord message |
| `providers.pagerduty.integrationKey` | PagerDuty integration key [more info](https://support.pagerduty.com/docs/services-and-integrations) |


### Cleanup

```shell
kubectl delete -f https://raw.githubusercontent.com/abahmed/kwatch/main/deploy/config.yaml
kubectl delete -f https://raw.githubusercontent.com/abahmed/kwatch/main/deploy/deploy.yaml
kubectl delete -f https://raw.githubusercontent.com/abahmed/kwatch/v0.0.4/deploy/config.yaml
kubectl delete -f https://raw.githubusercontent.com/abahmed/kwatch/v0.0.4/deploy/deploy.yaml
```

## Contributors
Expand Down
2 changes: 1 addition & 1 deletion config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
maxRecentLogLines: 0
providers:
alert:
slack:
webhook: ""
pagerduty:
Expand Down
5 changes: 4 additions & 1 deletion constant/constant.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package constant

// Version is the current versions of kwatch
const Version = "dev"

// WelcomeMsg is used to be sent to all providers when kwatch starts
const WelcomeMsg = ":tada: kwatch just started!"
const WelcomeMsg = ":tada: kwatch@%s just started!"

// NumRequeues indicates number of retries when worker fails to handle item
const NumRequeues = 5
Expand Down
70 changes: 0 additions & 70 deletions controller/controller.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
package controller

import (
"context"
"errors"
"time"

"github.com/abahmed/kwatch/client"
"github.com/abahmed/kwatch/constant"
"github.com/abahmed/kwatch/event"
"github.com/abahmed/kwatch/provider"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
Expand All @@ -32,71 +27,6 @@ type Controller struct {
providers []provider.Provider
}

// Start creates an instance of controller after initialization and runs it
func Start() {
// create kubernetes client
kclient := client.Create()

// create rate limiting queue
queue :=
workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())

indexer, informer := cache.NewIndexerInformer(
&cache.ListWatch{
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
return kclient.CoreV1().
Pods(v1.NamespaceAll).
List(context.TODO(), opts)
},
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
return kclient.CoreV1().
Pods(v1.NamespaceAll).
Watch(context.TODO(), opts)
},
},
&v1.Pod{},
0,
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err == nil {
logrus.Debugf("received create for Pod %s\n", key)
queue.Add(key)
}
},
UpdateFunc: func(old interface{}, new interface{}) {
key, err := cache.MetaNamespaceKeyFunc(new)
if err == nil {
logrus.Debugf("received update for Pod %s\n", key)
queue.Add(key)
}
},
DeleteFunc: func(obj interface{}) {
// IndexerInformer uses a delta queue, therefore for deletes
// we have to use this key function.
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err == nil {
logrus.Debugf("received delete for Pod %s\n", key)
queue.Add(key)
}
},
}, cache.Indexers{})

controller := Controller{
name: "pod-crash",
informer: informer,
indexer: indexer,
queue: queue,
kclient: kclient,
providers: util.GetProviders(),
}

stopCh := make(chan struct{})
defer close(stopCh)

controller.run(constant.NumWorkers, stopCh)
}

// run starts the controller
func (c *Controller) run(workers int, stopCh chan struct{}) {
defer utilruntime.HandleCrash()
Expand Down
81 changes: 81 additions & 0 deletions controller/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package controller

import (
"context"

"github.com/abahmed/kwatch/client"
"github.com/abahmed/kwatch/constant"
"github.com/abahmed/kwatch/util"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)

// Start creates an instance of controller after initialization and runs it
func Start() {
// create kubernetes client
kclient := client.Create()

// create rate limiting queue
queue :=
workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())

indexer, informer := cache.NewIndexerInformer(
&cache.ListWatch{
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
return kclient.CoreV1().
Pods(v1.NamespaceAll).
List(context.TODO(), opts)
},
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
return kclient.CoreV1().
Pods(v1.NamespaceAll).
Watch(context.TODO(), opts)
},
},
&v1.Pod{},
0,
cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err == nil {
logrus.Debugf("received create for Pod %s\n", key)
queue.Add(key)
}
},
UpdateFunc: func(old interface{}, new interface{}) {
key, err := cache.MetaNamespaceKeyFunc(new)
if err == nil {
logrus.Debugf("received update for Pod %s\n", key)
queue.Add(key)
}
},
DeleteFunc: func(obj interface{}) {
// IndexerInformer uses a delta queue, therefore for deletes
// we have to use this key function.
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err == nil {
logrus.Debugf("received delete for Pod %s\n", key)
queue.Add(key)
}
},
}, cache.Indexers{})

controller := Controller{
name: "pod-crash",
informer: informer,
indexer: indexer,
queue: queue,
kclient: kclient,
providers: util.GetProviders(),
}

stopCh := make(chan struct{})
defer close(stopCh)

controller.run(constant.NumWorkers, stopCh)
}
2 changes: 1 addition & 1 deletion deploy/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ metadata:
data:
config.yaml: |
maxRecentLogLines: <optional_number_of_lines>
providers:
alert:
slack:
webhook: <webhook_url>
pagerduty:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/abahmed/kwatch
go 1.17

require (
github.com/bwmarrin/discordgo v0.23.2
github.com/sirupsen/logrus v1.8.1
github.com/slack-go/slack v0.10.0
github.com/spf13/viper v1.9.0
Expand All @@ -12,7 +13,6 @@ require (
)

require (
github.com/bwmarrin/discordgo v0.23.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-logr/logr v0.4.0 // indirect
Expand Down
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"os"
"path/filepath"

Expand All @@ -11,7 +12,7 @@ import (
)

func main() {
logrus.Infof(constant.WelcomeMsg)
logrus.Infof(fmt.Sprintf(constant.WelcomeMsg, constant.Version))

// initialize configuration
configFile := os.Getenv("CONFIG_FILE")
Expand Down
4 changes: 2 additions & 2 deletions provider/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ func (s *discord) SendEvent(ev *event.Event) error {
}

// use custom title if it's provided, otherwise use default
title := viper.GetString("providers.discord.title")
title := viper.GetString("alert.discord.title")
if len(title) == 0 {
title = defaultTitle
}

// use custom text if it's provided, otherwise use default
text := viper.GetString("providers.discord.text")
text := viper.GetString("alert.discord.text")
if len(text) == 0 {
text = defaultText
}
Expand Down
4 changes: 2 additions & 2 deletions provider/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ func (s *slack) SendEvent(ev *event.Event) error {
}

// use custom title if it's provided, otherwise use default
title := viper.GetString("providers.slack.title")
title := viper.GetString("alert.slack.title")
if len(title) == 0 {
title = defaultTitle
}

// use custom text if it's provided, otherwise use default
text := viper.GetString("providers.slack.text")
text := viper.GetString("alert.slack.text")
if len(text) == 0 {
text = defaultText
}
Expand Down
7 changes: 4 additions & 3 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,20 @@ func getPodEvents(c kubernetes.Interface, name, namespace string) (*v1.EventList
})
}

// GetProviders returns slice of provider objects after parsing config
func GetProviders() []provider.Provider {
var providers []provider.Provider

for key, value := range viper.Get("providers").(map[string]interface{}) {
for c, v := range value.(map[string]interface{}) {
if key == "slack" && c == "webhook" && len(strings.TrimSpace(v.(string))) > 0 {
providers = append(providers, provider.NewSlack(viper.GetString("providers.slack.webhook")))
providers = append(providers, provider.NewSlack(viper.GetString("alert.slack.webhook")))
}
if key == "pagerduty" && c == "integrationkey" && len(strings.TrimSpace(v.(string))) > 0 {
providers = append(providers, provider.NewPagerDuty(viper.GetString("providers.pagerduty.integrationKey")))
providers = append(providers, provider.NewPagerDuty(viper.GetString("alert.pagerduty.integrationKey")))
}
if key == "discord" && c == "webhook" && len(strings.TrimSpace(v.(string))) > 0 {
providers = append(providers, provider.NewDiscord(viper.GetString("providers.discord.webhook")))
providers = append(providers, provider.NewDiscord(viper.GetString("alert.discord.webhook")))
}
}
}
Expand Down

0 comments on commit 727bb0c

Please sign in to comment.