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
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
with:
go-version: '1.26'
- name: Build
run: go build
run: go build -o kwatch ./cmd/kwatch
- name: Test
run: go test -race --coverprofile=coverage.txt --covermode=atomic ./...
- name: Upload coverage to Codecov
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
*.dll
*.so
*.dylib
kwatch

# Test binary, built with `go test -c`
*.test
coverage.txt

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
_output/

# Dependency directories (remove the comment below to include it)
# vendor/
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ COPY go.mod go.sum /build/
RUN go mod download

COPY . /build/
RUN sed -i 's/dev/'"${RELEASE_VERSION}"'/g' version/version.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o kwatch .
RUN sed -i 's/dev/'"${RELEASE_VERSION}"'/g' internal/version/version.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o kwatch ./cmd/kwatch

FROM alpine:latest
RUN apk add --update ca-certificates && \
Expand Down
101 changes: 101 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Makefile for kwatch
# Following Kubernetes community conventions

.PHONY: build test test-short lint vet clean verify-fmt verify-unit verify-all help

# Binary names
BINARY_NAME := kwatch
CMD_DIR := cmd/kwatch

# Go parameters
GOCMD := go
GOBUILD := CGO_ENABLED=0 $(GOCMD) build
GOTEST := $(GOCMD) test
GOVET := $(GOCMD) vet
GOFMT := $(GOCMD) fmt

# Build parameters
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
BUILD_TIME := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -ldflags "-X github.com/abahmed/kwatch/internal/version.version=$(VERSION) -X github.com/abahmed/kwatch/internal/version.gitCommitID=$(shell git rev-parse --short HEAD 2>/dev/null || echo "none") -X github.com/abahmed/kwatch/internal/version.buildDate=$(BUILD_TIME)"

# Output directory
OUTPUT_DIR := _output

# Default target
help:
@echo "kwatch Makefile"
@echo ""
@echo "Usage:"
@echo " make build Build the binary"
@echo " make test Run all tests"
@echo " make test-short Run short tests only"
@echo " make vet Run go vet"
@echo " make lint Run linting (requires golangci-lint)"
@echo " make verify-fmt Verify code formatting"
@echo " make verify-unit Run unit tests"
@echo " make verify-all Run all verification scripts"
@echo " make clean Clean build artifacts"
@echo ""

# Build the binary
build:
@echo "Building $(BINARY_NAME)..."
@mkdir -p $(OUTPUT_DIR)
$(GOBUILD) $(LDFLAGS) -o $(OUTPUT_DIR)/$(BINARY_NAME) ./$(CMD_DIR)

# Run tests
test:
@echo "Running tests..."
$(GOTEST) -v ./...

# Run short tests
test-short:
@echo "Running short tests..."
$(GOTEST) -short ./...

# Run go vet
vet:
@echo "Running go vet..."
$(GOVET) ./...

# Run linting
lint:
@echo "Running golangci-lint..."
@which golangci-lint > /dev/null || (echo "golangci-lint not found. Install: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest" && exit 1)
golangci-lint run ./...

# Verify code formatting
verify-fmt:
@echo "Verifying code formatting..."
@diff=$$(gofmt -l .); \
if [ -n "$$diff" ]; then \
echo "The following files are not formatted correctly:"; \
echo "$$diff"; \
exit 1; \
fi
@echo "All files are properly formatted."

# Run unit tests
verify-unit:
@echo "Running unit tests..."
$(GOTEST) -short ./...

# Run all verification scripts
verify-all: verify-fmt vet verify-unit

# Clean build artifacts
clean:
@echo "Cleaning..."
@rm -rf $(OUTPUT_DIR)
@rm -f coverage.out coverage.txt
@echo "Clean complete."

# Docker build
docker-build:
@echo "Building Docker image..."
docker build -t kwatch:$(VERSION) .

# Docker build with latest tag
docker-build-latest:
docker build -t kwatch:latest -t kwatch:$(VERSION) .
81 changes: 81 additions & 0 deletions cmd/kwatch/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"context"
"fmt"
"os"
"os/signal"
"syscall"

"github.com/abahmed/kwatch/internal/client"
"github.com/abahmed/kwatch/internal/config"
"github.com/abahmed/kwatch/internal/constant"
"github.com/abahmed/kwatch/internal/controller"
"github.com/abahmed/kwatch/internal/handler"
"github.com/abahmed/kwatch/internal/health"
"github.com/abahmed/kwatch/internal/k8s"
"github.com/abahmed/kwatch/internal/pvc"
"github.com/abahmed/kwatch/internal/startup"
"github.com/abahmed/kwatch/internal/storage/memory"
"github.com/abahmed/kwatch/internal/upgrader"
"github.com/abahmed/kwatch/internal/version"
"k8s.io/klog/v2"
)

func main() {
cfg, err := config.LoadConfig()
if err != nil {
klog.ErrorS(err, "failed to load config")
os.Exit(1)
}

klog.InfoS(fmt.Sprintf(constant.WelcomeMsg, version.Short()))

k8sClient := client.Create(&cfg.App)

sm := startup.NewStartupManager(
k8sClient,
k8s.GetNamespace(),
cfg.Alert,
&cfg.App,
)
sm.HandleStartup(context.Background())

healthServer := health.NewHealthServer(cfg.HealthCheck)
healthServer.Start(context.Background())

up := upgrader.NewUpgrader(&cfg.Upgrader, sm.GetAlertManager(), sm.GetStateManager())
go up.CheckUpdates()

pvcMonitor := pvc.NewPvcMonitor(k8sClient, &cfg.PvcMonitor, sm.GetAlertManager())
go pvcMonitor.Start()

h := handler.NewHandler(
k8sClient,
cfg,
memory.NewMemory(),
sm.GetAlertManager(),
)

ctrl, cleanup := controller.New(k8sClient, cfg, h)
defer cleanup()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func() {
if err := ctrl.Run(ctx, 1); err != nil {
klog.ErrorS(err, "controller error")
os.Exit(1)
}
}()

sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh

klog.InfoS("shutting down gracefully...")
cancel()
healthServer.Stop(context.Background())
os.Exit(0)
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ go 1.26.1
require (
github.com/bwmarrin/discordgo v0.29.0
github.com/google/go-github/v41 v41.0.1-0.20211227215900-a899e0fadbec
github.com/sirupsen/logrus v1.9.4
github.com/slack-go/slack v0.20.0
github.com/stretchr/testify v1.11.1
gopkg.in/mail.v2 v2.3.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.35.3
k8s.io/apimachinery v0.35.3
k8s.io/client-go v0.35.3
k8s.io/klog/v2 v2.140.0
)

require (
Expand Down Expand Up @@ -62,7 +62,6 @@ require (
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.140.0 // indirect
k8s.io/kube-openapi v0.0.0-20260319004828-5883c5ee87b9 // indirect
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/slack-go/slack v0.20.0 h1:gbDdbee8+Z2o+DWx05Spq3GzbrLLleiRwHUKs+hZLSU=
github.com/slack-go/slack v0.20.0/go.mod h1:K81UmCivcYd/5Jmz8vLBfuyoZ3B4rQC2GHVXHteXiAE=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
Expand Down
57 changes: 27 additions & 30 deletions alertmanager/alertmanager.go → internal/alert/alert.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package alertmanager
package alert

import (
"reflect"
"strings"

"github.com/abahmed/kwatch/alertmanager/dingtalk"
"github.com/abahmed/kwatch/alertmanager/discord"
"github.com/abahmed/kwatch/alertmanager/email"
"github.com/abahmed/kwatch/alertmanager/feishu"
"github.com/abahmed/kwatch/alertmanager/googlechat"
"github.com/abahmed/kwatch/alertmanager/matrix"
"github.com/abahmed/kwatch/alertmanager/mattermost"
"github.com/abahmed/kwatch/alertmanager/opsgenie"
"github.com/abahmed/kwatch/alertmanager/pagerduty"
"github.com/abahmed/kwatch/alertmanager/rocketchat"
"github.com/abahmed/kwatch/alertmanager/slack"
"github.com/abahmed/kwatch/alertmanager/teams"
"github.com/abahmed/kwatch/alertmanager/telegram"
"github.com/abahmed/kwatch/alertmanager/webhook"
"github.com/abahmed/kwatch/alertmanager/zenduty"
"github.com/abahmed/kwatch/config"
"github.com/abahmed/kwatch/event"
"github.com/sirupsen/logrus"
"github.com/abahmed/kwatch/internal/alert/dingtalk"
"github.com/abahmed/kwatch/internal/alert/discord"
"github.com/abahmed/kwatch/internal/alert/email"
"github.com/abahmed/kwatch/internal/alert/feishu"
"github.com/abahmed/kwatch/internal/alert/googlechat"
"github.com/abahmed/kwatch/internal/alert/matrix"
"github.com/abahmed/kwatch/internal/alert/mattermost"
"github.com/abahmed/kwatch/internal/alert/opsgenie"
"github.com/abahmed/kwatch/internal/alert/pagerduty"
"github.com/abahmed/kwatch/internal/alert/rocketchat"
"github.com/abahmed/kwatch/internal/alert/slack"
"github.com/abahmed/kwatch/internal/alert/teams"
"github.com/abahmed/kwatch/internal/alert/telegram"
"github.com/abahmed/kwatch/internal/alert/webhook"
"github.com/abahmed/kwatch/internal/alert/zenduty"
"github.com/abahmed/kwatch/internal/config"
"github.com/abahmed/kwatch/internal/event"
"k8s.io/klog/v2"
)

type AlertManager struct {
Expand Down Expand Up @@ -83,29 +83,26 @@ func (a *AlertManager) Init(

// Notify sends string msg to all providers
func (a *AlertManager) Notify(msg string) {
logrus.Infof("sending message: %s", msg)
klog.InfoS("sending message", "msg", msg)

for _, prv := range a.providers {
if err := prv.SendMessage(msg); err != nil {
logrus.Errorf(
"failed to send msg with %s: %s",
prv.Name(),
err.Error())
klog.ErrorS(err,
"failed to send msg",
"provider", prv.Name())
}
}
}

// NotifyEvent sends event to all providers
func (a *AlertManager) NotifyEvent(event event.Event) {
logrus.Infof("sending event: %+v", event)
klog.InfoS("sending event", "event", event)

for _, prv := range a.providers {
if err := prv.SendEvent(&event); err != nil {
logrus.Errorf(
"failed to send event with %s: %s",
prv.Name(),
err.Error(),
)
klog.ErrorS(err,
"failed to send event",
"provider", prv.Name())
}
}
}
Loading
Loading