From cb7be28f6831951602ac9ddcb63f4e8e6d4c1b33 Mon Sep 17 00:00:00 2001 From: Abdelrahman Ahmed Date: Sun, 29 Mar 2026 22:22:33 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=A7=20Refactor=20to=20follow=20Kub?= =?UTF-8?q?ernetes=20project=20structure=20and=20logging=20standards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 🗂️ Restructure to use cmd/, internal/, hack/, third_party/ directories - 📦 Move main.go to cmd/kwatch/ - 🔖 Rename packages: k8sutil→k8s, alertmanager→alert, pvcmonitor→pvc - 📝 Use underscores for file/directory names per K8s conventions - 📚 Migrate from logrus to klog (K8s standard logging) - 🛠️ Add Makefile with K8s-style targets - 🐳 Update Dockerfile to build from ./cmd/kwatch --- .github/workflows/check.yml | 2 +- .gitignore | 2 +- Dockerfile | 4 +- Makefile | 101 ++++++++++++++++++ cmd/kwatch/main.go | 81 ++++++++++++++ go.mod | 3 +- go.sum | 2 - .../alert/alert.go | 57 +++++----- .../alert/alert_test.go | 35 +++--- .../alert}/dingtalk/dingtalk.go | 16 +-- .../alert}/dingtalk/dingtalk_test.go | 4 +- .../alert}/discord/discord.go | 16 +-- .../alert}/discord/discord_test.go | 4 +- .../alert}/email/email.go | 26 ++--- .../alert}/email/email_test.go | 4 +- .../alert}/feishu/feishu.go | 14 +-- .../alert}/feishu/feishu_test.go | 4 +- .../alert}/googlechat/googlechat.go | 14 +-- .../alert}/googlechat/googlechat_test.go | 4 +- .../alert}/matrix/matrix.go | 22 ++-- .../alert}/matrix/matrix_test.go | 4 +- .../alert}/mattermost/mattermost.go | 20 ++-- .../alert}/mattermost/mattermost_test.go | 4 +- .../alert}/opsgenie/opsgenie.go | 16 +-- .../alert}/opsgenie/opsgenie_test.go | 4 +- .../alert}/pagerduty/pagerduty.go | 14 +-- .../alert}/pagerduty/pagerduty_test.go | 4 +- .../alert}/rocketchat/rocketchat.go | 14 +-- .../alert}/rocketchat/rocketchat_test.go | 4 +- .../alert}/slack/slack.go | 18 ++-- .../alert}/slack/slack_test.go | 4 +- .../alert}/teams/teams.go | 21 ++-- .../alert}/teams/teams_test.go | 4 +- .../alert}/telegram/telegram.go | 22 ++-- .../alert}/telegram/telegram_test.go | 4 +- .../alert}/webhook/webhook.go | 22 ++-- .../alert}/webhook/webhook_test.go | 4 +- .../alert}/zenduty/zenduty.go | 16 +-- .../alert}/zenduty/zenduty_test.go | 4 +- {client => internal/client}/client.go | 19 +++- {client => internal/client}/client_test.go | 2 +- {config => internal/config}/config.go | 0 {config => internal/config}/config_test.go | 0 .../config/default_config.go | 0 .../config/load_config.go | 16 +-- {constant => internal/constant}/constant.go | 0 .../controller}/controller.go | 14 +-- .../controller}/controller_test.go | 2 +- {event => internal/event}/event.go | 0 {event => internal/event}/event_test.go | 0 {event => internal/event}/format.go | 2 +- .../filter/container_killing_filter.go | 0 .../filter/container_logs_filter.go | 12 +-- .../filter/container_name_filter.go | 8 +- .../filter/container_reasons_filter.go | 14 +-- .../filter/container_restarts_filter.go | 0 .../filter/container_state_filter.go | 0 .../filter/event_filter.go | 0 {filter => internal/filter}/filter.go | 4 +- {filter => internal/filter}/filter_test.go | 6 +- .../filter/namespace_filter.go | 14 +-- .../filter/pod_events_filter.go | 0 .../filter/pod_name_filter.go | 8 +- .../filter/pod_owners_filter.go | 0 .../filter/pod_status_filter.go | 18 ++-- .../handler/execute_containers_filters.go | 28 ++--- .../handler/execute_pod_filters.go | 14 +-- {handler => internal/handler}/handler.go | 12 +-- {handler => internal/handler}/handler_test.go | 42 ++++---- .../handler/process_node.go | 8 +- .../handler/process_pod.go | 6 +- {health => internal/health}/health.go | 10 +- {health => internal/health}/health_test.go | 2 +- {util => internal/k8s}/http.go | 2 +- {util => internal/k8s}/util.go | 34 +++--- {util => internal/k8s}/util_test.go | 2 +- .../pvc/check_usage.go | 10 +- .../getUsage.go => internal/pvc/get_usage.go | 17 ++- {pvcmonitor => internal/pvc}/pvc.go | 14 +-- .../pvc/pvc_test.go | 28 ++--- {startup => internal/startup}/startup.go | 22 ++-- {startup => internal/startup}/startup_test.go | 2 +- {state => internal/state}/retry.go | 4 +- {state => internal/state}/state.go | 4 +- {state => internal/state}/state_test.go | 0 .../storage}/memory/memory.go | 2 +- .../storage}/memory/memory_test.go | 2 +- {storage => internal/storage}/storage.go | 0 {upgrader => internal/upgrader}/upgrader.go | 26 ++--- .../upgrader}/upgrader_test.go | 42 ++++---- {version => internal/version}/version.go | 0 {version => internal/version}/version_test.go | 0 main.go | 80 -------------- 93 files changed, 635 insertions(+), 535 deletions(-) create mode 100644 Makefile create mode 100644 cmd/kwatch/main.go rename alertmanager/alertmanager.go => internal/alert/alert.go (65%) rename alertmanager/alertmanager_test.go => internal/alert/alert_test.go (77%) rename {alertmanager => internal/alert}/dingtalk/dingtalk.go (89%) rename {alertmanager => internal/alert}/dingtalk/dingtalk_test.go (99%) rename {alertmanager => internal/alert}/discord/discord.go (89%) rename {alertmanager => internal/alert}/discord/discord_test.go (97%) rename {alertmanager => internal/alert}/email/email.go (78%) rename {alertmanager => internal/alert}/email/email_test.go (97%) rename {alertmanager => internal/alert}/feishu/feishu.go (87%) rename {alertmanager => internal/alert}/feishu/feishu_test.go (97%) rename {alertmanager => internal/alert}/googlechat/googlechat.go (84%) rename {alertmanager => internal/alert}/googlechat/googlechat_test.go (96%) rename {alertmanager => internal/alert}/matrix/matrix.go (83%) rename {alertmanager => internal/alert}/matrix/matrix_test.go (97%) rename {alertmanager => internal/alert}/mattermost/mattermost.go (87%) rename {alertmanager => internal/alert}/mattermost/mattermost_test.go (96%) rename {alertmanager => internal/alert}/opsgenie/opsgenie.go (89%) rename {alertmanager => internal/alert}/opsgenie/opsgenie_test.go (97%) rename {alertmanager => internal/alert}/pagerduty/pagerduty.go (91%) rename {alertmanager => internal/alert}/pagerduty/pagerduty_test.go (97%) rename {alertmanager => internal/alert}/rocketchat/rocketchat.go (85%) rename {alertmanager => internal/alert}/rocketchat/rocketchat_test.go (96%) rename {alertmanager => internal/alert}/slack/slack.go (90%) rename {alertmanager => internal/alert}/slack/slack_test.go (98%) rename {alertmanager => internal/alert}/teams/teams.go (92%) rename {alertmanager => internal/alert}/teams/teams_test.go (98%) rename {alertmanager => internal/alert}/telegram/telegram.go (87%) rename {alertmanager => internal/alert}/telegram/telegram_test.go (98%) rename {alertmanager => internal/alert}/webhook/webhook.go (86%) rename {alertmanager => internal/alert}/webhook/webhook_test.go (97%) rename {alertmanager => internal/alert}/zenduty/zenduty.go (89%) rename {alertmanager => internal/alert}/zenduty/zenduty_test.go (97%) rename {client => internal/client}/client.go (79%) rename {client => internal/client}/client_test.go (98%) rename {config => internal/config}/config.go (100%) rename {config => internal/config}/config_test.go (100%) rename config/defaultConfig.go => internal/config/default_config.go (100%) rename config/loadConfig.go => internal/config/load_config.go (83%) rename {constant => internal/constant}/constant.go (100%) rename {controller => internal/controller}/controller.go (94%) rename {controller => internal/controller}/controller_test.go (99%) rename {event => internal/event}/event.go (100%) rename {event => internal/event}/event_test.go (100%) rename {event => internal/event}/format.go (98%) rename filter/containerKillingFilter.go => internal/filter/container_killing_filter.go (100%) rename filter/containerLogsFilter.go => internal/filter/container_logs_filter.go (75%) rename filter/containerNameFilter.go => internal/filter/container_name_filter.go (72%) rename filter/containerReasonsFilter.go => internal/filter/container_reasons_filter.go (88%) rename filter/containerRestartsFilter.go => internal/filter/container_restarts_filter.go (100%) rename filter/containerStateFilter.go => internal/filter/container_state_filter.go (100%) rename filter/eventFilter.go => internal/filter/event_filter.go (100%) rename {filter => internal/filter}/filter.go (90%) rename {filter => internal/filter}/filter_test.go (99%) rename filter/namespaceFilter.go => internal/filter/namespace_filter.go (66%) rename filter/podEventsFilter.go => internal/filter/pod_events_filter.go (100%) rename filter/podNameFilter.go => internal/filter/pod_name_filter.go (66%) rename filter/podOwnersFilter.go => internal/filter/pod_owners_filter.go (100%) rename filter/podStatusFilter.go => internal/filter/pod_status_filter.go (85%) rename handler/executeContainersFilters.go => internal/handler/execute_containers_filters.go (77%) rename handler/executePodFilters.go => internal/handler/execute_pod_filters.go (69%) rename {handler => internal/handler}/handler.go (86%) rename {handler => internal/handler}/handler_test.go (91%) rename handler/processNode.go => internal/handler/process_node.go (82%) rename handler/processPod.go => internal/handler/process_pod.go (88%) rename {health => internal/health}/health.go (85%) rename {health => internal/health}/health_test.go (98%) rename {util => internal/k8s}/http.go (96%) rename {util => internal/k8s}/util.go (90%) rename {util => internal/k8s}/util_test.go (99%) rename pvcmonitor/checkUsage.go => internal/pvc/check_usage.go (84%) rename pvcmonitor/getUsage.go => internal/pvc/get_usage.go (83%) rename {pvcmonitor => internal/pvc}/pvc.go (75%) rename pvcmonitor/pvcmonitor_test.go => internal/pvc/pvc_test.go (93%) rename {startup => internal/startup}/startup.go (71%) rename {startup => internal/startup}/startup_test.go (99%) rename {state => internal/state}/retry.go (93%) rename {state => internal/state}/state.go (97%) rename {state => internal/state}/state_test.go (100%) rename {storage => internal/storage}/memory/memory.go (97%) rename {storage => internal/storage}/memory/memory_test.go (98%) rename {storage => internal/storage}/storage.go (100%) rename {upgrader => internal/upgrader}/upgrader.go (79%) rename {upgrader => internal/upgrader}/upgrader_test.go (88%) rename {version => internal/version}/version.go (100%) rename {version => internal/version}/version_test.go (100%) delete mode 100644 main.go diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a7896349..1e845bff 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -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 diff --git a/.gitignore b/.gitignore index 1648f2e8..9c3c9c19 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ *.dll *.so *.dylib -kwatch # Test binary, built with `go test -c` *.test @@ -16,6 +15,7 @@ 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/ diff --git a/Dockerfile b/Dockerfile index 106fb63f..9ee906e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 && \ diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..542106ff --- /dev/null +++ b/Makefile @@ -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) . diff --git a/cmd/kwatch/main.go b/cmd/kwatch/main.go new file mode 100644 index 00000000..376e33f7 --- /dev/null +++ b/cmd/kwatch/main.go @@ -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) +} diff --git a/go.mod b/go.mod index 41a2331e..19354d85 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ 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 @@ -13,6 +12,7 @@ require ( 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 ( @@ -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 diff --git a/go.sum b/go.sum index 4da268ba..721d98ab 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/alertmanager/alertmanager.go b/internal/alert/alert.go similarity index 65% rename from alertmanager/alertmanager.go rename to internal/alert/alert.go index eab4e66d..ecce139b 100644 --- a/alertmanager/alertmanager.go +++ b/internal/alert/alert.go @@ -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 { @@ -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()) } } } diff --git a/alertmanager/alertmanager_test.go b/internal/alert/alert_test.go similarity index 77% rename from alertmanager/alertmanager_test.go rename to internal/alert/alert_test.go index eff3168e..60bf556a 100644 --- a/alertmanager/alertmanager_test.go +++ b/internal/alert/alert_test.go @@ -1,11 +1,11 @@ -package alertmanager +package alert import ( "errors" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) @@ -32,11 +32,12 @@ func (p *fakeProviderWithError) SendEvent(evt *event.Event) error { func (p *fakeProviderWithError) Name() string { return "Slack Error" } + func TestAlertManagerNoConfig(t *testing.T) { assert := assert.New(t) - alertmanager := AlertManager{} - alertmanager.Init(nil, nil) - assert.Len(alertmanager.providers, 0) + am := AlertManager{} + am.Init(nil, nil) + assert.Len(am.providers, 0) } func TestGetProviders(t *testing.T) { @@ -97,31 +98,31 @@ func TestGetProviders(t *testing.T) { }, } - alertmanager := AlertManager{} - alertmanager.Init(alertMap, &config.App{ClusterName: "dev"}) + am := AlertManager{} + am.Init(alertMap, &config.App{ClusterName: "dev"}) assert.Len( - alertmanager.providers, + am.providers, len(alertMap), "get providers returned %d expected %d") } func TestSendProvidersEvent(t *testing.T) { - alertmanager := AlertManager{} - alertmanager.providers = append( - alertmanager.providers, + am := AlertManager{} + am.providers = append( + am.providers, &fakeProvider{}, &fakeProviderWithError{}, ) - alertmanager.NotifyEvent(event.Event{}) + am.NotifyEvent(event.Event{}) } func TestSendProvidersMsg(t *testing.T) { - alertmanager := AlertManager{} - alertmanager.providers = append( - alertmanager.providers, + am := AlertManager{} + am.providers = append( + am.providers, &fakeProvider{}, &fakeProviderWithError{}, ) - alertmanager.Notify("hello world!") + am.Notify("hello world!") } diff --git a/alertmanager/dingtalk/dingtalk.go b/internal/alert/dingtalk/dingtalk.go similarity index 89% rename from alertmanager/dingtalk/dingtalk.go rename to internal/alert/dingtalk/dingtalk.go index 03d2a1fd..8541731b 100644 --- a/alertmanager/dingtalk/dingtalk.go +++ b/internal/alert/dingtalk/dingtalk.go @@ -12,11 +12,11 @@ import ( "net/url" "time" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) const ( @@ -42,11 +42,11 @@ type DingTalk struct { func NewDingTalk(config map[string]interface{}, appCfg *config.App) *DingTalk { accessToken, ok := config["accessToken"].(string) if !ok || len(accessToken) == 0 { - logrus.Warnf("initializing dingtalk with empty access token") + klog.InfoS("initializing dingtalk with empty access token") return nil } - logrus.Infof("initializing dingtalk with access token: %s", accessToken) + klog.InfoS("initializing dingtalk with access token", "accessToken", accessToken) title, _ := config["title"].(string) secret, _ := config["secret"].(string) @@ -133,7 +133,7 @@ func (d *DingTalk) sendAPI(msg string) error { request.Header.Set("Content-Type", "application/json") - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() response, err := client.Do(request) if err != nil { return err diff --git a/alertmanager/dingtalk/dingtalk_test.go b/internal/alert/dingtalk/dingtalk_test.go similarity index 99% rename from alertmanager/dingtalk/dingtalk_test.go rename to internal/alert/dingtalk/dingtalk_test.go index 056d8453..9914f9d2 100644 --- a/alertmanager/dingtalk/dingtalk_test.go +++ b/internal/alert/dingtalk/dingtalk_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/discord/discord.go b/internal/alert/discord/discord.go similarity index 89% rename from alertmanager/discord/discord.go rename to internal/alert/discord/discord.go index c38740e7..9294c448 100644 --- a/alertmanager/discord/discord.go +++ b/internal/alert/discord/discord.go @@ -3,12 +3,12 @@ package discord import ( "strings" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/event" discordgo "github.com/bwmarrin/discordgo" - "github.com/sirupsen/logrus" + "k8s.io/klog/v2" ) const ( @@ -34,16 +34,16 @@ type Discord struct { func NewDiscord(config map[string]interface{}, appCfg *config.App) *Discord { webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing discord with empty webhook url") + klog.InfoS("initializing discord with empty webhook url") return nil } webhookList := strings.Split(webhook, "/") if len(webhookList) <= 1 { - logrus.Warnf("initializing discord with missing id or token") + klog.InfoS("initializing discord with missing id or token") return nil } - logrus.Infof("initializing discord with webhook url: %s", webhook) + klog.InfoS("initializing discord with webhook url", "webhook", webhook) webhookToken := webhookList[len(webhookList)-1] webhookID := webhookList[len(webhookList)-2] @@ -70,7 +70,7 @@ func (s *Discord) Name() string { // SendEvent sends event to the provider func (s *Discord) SendEvent(ev *event.Event) error { - logrus.Debugf("sending to discord event: %v", ev) + klog.V(4).InfoS("sending to discord event", "event", ev) // initialize fields with basic info fields := []*discordgo.MessageEmbedField{ diff --git a/alertmanager/discord/discord_test.go b/internal/alert/discord/discord_test.go similarity index 97% rename from alertmanager/discord/discord_test.go rename to internal/alert/discord/discord_test.go index 344aa69a..d1699c30 100644 --- a/alertmanager/discord/discord_test.go +++ b/internal/alert/discord/discord_test.go @@ -4,8 +4,8 @@ import ( "strings" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" discordgo "github.com/bwmarrin/discordgo" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/email/email.go b/internal/alert/email/email.go similarity index 78% rename from alertmanager/email/email.go rename to internal/alert/email/email.go index aed11ef3..25913854 100644 --- a/alertmanager/email/email.go +++ b/internal/alert/email/email.go @@ -6,11 +6,11 @@ import ( "strconv" "strings" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" gomail "gopkg.in/mail.v2" + "k8s.io/klog/v2" ) type Email struct { @@ -26,41 +26,41 @@ type Email struct { func NewEmail(config map[string]interface{}, appCfg *config.App) *Email { from, ok := config["from"].(string) if !ok || len(from) == 0 { - logrus.Warnf("initializing email with an empty from") + klog.InfoS("initializing email with an empty from") return nil } to, ok := config["to"].(string) if !ok || len(to) == 0 { - logrus.Warnf("initializing email with an empty to") + klog.InfoS("initializing email with an empty to") return nil } password, ok := config["password"].(string) if !ok || len(password) == 0 { - logrus.Warnf("initializing email with an empty password") + klog.InfoS("initializing email with an empty password") return nil } host, ok := config["host"].(string) if !ok || len(host) == 0 { - logrus.Warnf("initializing email with an empty host") + klog.InfoS("initializing email with an empty host") return nil } port, ok := config["port"].(string) if !ok || len(port) == 0 { - logrus.Warnf("initializing email with an empty port number") + klog.InfoS("initializing email with an empty port number") return nil } portNumber, err := strconv.Atoi(port) if err != nil { - logrus.Warnf("initializing email with an invalid port number: %s", err) + klog.InfoS("initializing email with an invalid port number", "error", err) return nil } if portNumber > math.MaxUint16 { - logrus.Warnf("initializing email with an invalid range for port number") + klog.InfoS("initializing email with an invalid range for port number") return nil } @@ -105,13 +105,13 @@ func (e *Email) buildMessageSubjectAndBody( // add events part if it exists events := strings.TrimSpace(ev.Events) if len(events) > 0 { - eventsText = util.JsonEscape(ev.Events) + eventsText = k8s.JsonEscape(ev.Events) } // add logs part if it exists logs := strings.TrimSpace(ev.Logs) if len(logs) > 0 { - logsText = util.JsonEscape(ev.Logs) + logsText = k8s.JsonEscape(ev.Logs) } subject := fmt.Sprintf("⛑ Kwatch detected a crash in pod %s ", ev.ContainerName) diff --git a/alertmanager/email/email_test.go b/internal/alert/email/email_test.go similarity index 97% rename from alertmanager/email/email_test.go rename to internal/alert/email/email_test.go index 409c9adf..8a0de3ea 100644 --- a/alertmanager/email/email_test.go +++ b/internal/alert/email/email_test.go @@ -3,8 +3,8 @@ package email import ( "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" gomail "gopkg.in/mail.v2" ) diff --git a/alertmanager/feishu/feishu.go b/internal/alert/feishu/feishu.go similarity index 87% rename from alertmanager/feishu/feishu.go rename to internal/alert/feishu/feishu.go index 97917bc4..e0e3dd85 100644 --- a/alertmanager/feishu/feishu.go +++ b/internal/alert/feishu/feishu.go @@ -7,10 +7,10 @@ import ( "io" "net/http" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type FeiShu struct { @@ -30,11 +30,11 @@ type feiShuWebhookContent struct { func NewFeiShu(config map[string]interface{}, appCfg *config.App) *FeiShu { webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing Fei Shu with empty webhook url") + klog.InfoS("initializing Fei Shu with empty webhook url") return nil } - logrus.Infof("initializing Fei Shu with webhook url: %s", webhook) + klog.InfoS("initializing Fei Shu with webhook url", "webhook", webhook) title, _ := config["title"].(string) @@ -58,7 +58,7 @@ func (r *FeiShu) SendEvent(e *event.Event) error { } func (r *FeiShu) sendByFeiShuApi(reqBody string) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() buffer := bytes.NewBuffer([]byte(reqBody)) request, err := http.NewRequest(http.MethodPost, r.webhook, buffer) if err != nil { diff --git a/alertmanager/feishu/feishu_test.go b/internal/alert/feishu/feishu_test.go similarity index 97% rename from alertmanager/feishu/feishu_test.go rename to internal/alert/feishu/feishu_test.go index 259a3ece..1a69739f 100644 --- a/alertmanager/feishu/feishu_test.go +++ b/internal/alert/feishu/feishu_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/googlechat/googlechat.go b/internal/alert/googlechat/googlechat.go similarity index 84% rename from alertmanager/googlechat/googlechat.go rename to internal/alert/googlechat/googlechat.go index 8680c140..97bed91d 100644 --- a/alertmanager/googlechat/googlechat.go +++ b/internal/alert/googlechat/googlechat.go @@ -7,10 +7,10 @@ import ( "io" "net/http" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type GoogleChat struct { @@ -29,11 +29,11 @@ type payload struct { func NewGoogleChat(config map[string]interface{}, appCfg *config.App) *GoogleChat { webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing Google Chat with empty webhook url") + klog.InfoS("initializing Google Chat with empty webhook url") return nil } - logrus.Infof("initializing Google Chat with webhook url: %s", webhook) + klog.InfoS("initializing Google Chat with webhook url", "webhook", webhook) text, _ := config["text"].(string) @@ -56,7 +56,7 @@ func (r *GoogleChat) SendEvent(e *event.Event) error { } func (r *GoogleChat) sendAPI(reqBody string) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() buffer := bytes.NewBuffer([]byte(reqBody)) request, err := http.NewRequest(http.MethodPost, r.webhook, buffer) if err != nil { diff --git a/alertmanager/googlechat/googlechat_test.go b/internal/alert/googlechat/googlechat_test.go similarity index 96% rename from alertmanager/googlechat/googlechat_test.go rename to internal/alert/googlechat/googlechat_test.go index 8309e2ab..d0b6dbd2 100644 --- a/alertmanager/googlechat/googlechat_test.go +++ b/internal/alert/googlechat/googlechat_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/matrix/matrix.go b/internal/alert/matrix/matrix.go similarity index 83% rename from alertmanager/matrix/matrix.go rename to internal/alert/matrix/matrix.go index e3445cec..db207571 100644 --- a/alertmanager/matrix/matrix.go +++ b/internal/alert/matrix/matrix.go @@ -8,10 +8,10 @@ import ( "net/url" "regexp" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type Matrix struct { @@ -29,19 +29,19 @@ type Matrix struct { func NewMatrix(config map[string]interface{}, appCfg *config.App) *Matrix { homeServer, ok := config["homeServer"].(string) if !ok || len(homeServer) == 0 { - logrus.Warnf("initializing slack with empty homeServer") + klog.InfoS("initializing matrix with empty homeServer") return nil } accessToken, ok := config["accessToken"].(string) if !ok || len(accessToken) == 0 { - logrus.Warnf("initializing slack with empty accessToken") + klog.InfoS("initializing matrix with empty accessToken") return nil } internalRoomID, ok := config["internalRoomId"].(string) if !ok || len(internalRoomID) == 0 { - logrus.Warnf("initializing slack with empty internalRoomId") + klog.InfoS("initializing matrix with empty internalRoomId") return nil } @@ -78,8 +78,8 @@ func (m *Matrix) sendAPI(formattedMsg string) error { "body": "%s", "formatted_body": "%s" }`, - util.JsonEscape(plainMsg), - util.JsonEscape(formattedMsg), + k8s.JsonEscape(plainMsg), + k8s.JsonEscape(formattedMsg), ) request, err := http.NewRequest( http.MethodPut, @@ -88,7 +88,7 @@ func (m *Matrix) sendAPI(formattedMsg string) error { "?access_token=%s", m.homeServer, url.PathEscape(m.internalRoomID), - util.RandomString(24), + k8s.RandomString(24), url.QueryEscape(m.accessToken), ), bytes.NewBuffer([]byte(msg)), @@ -98,7 +98,7 @@ func (m *Matrix) sendAPI(formattedMsg string) error { } request.Header.Set("Content-Type", "application/json") - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() response, err := client.Do(request) if err != nil { return err diff --git a/alertmanager/matrix/matrix_test.go b/internal/alert/matrix/matrix_test.go similarity index 97% rename from alertmanager/matrix/matrix_test.go rename to internal/alert/matrix/matrix_test.go index d3766299..9537a8a5 100644 --- a/alertmanager/matrix/matrix_test.go +++ b/internal/alert/matrix/matrix_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/mattermost/mattermost.go b/internal/alert/mattermost/mattermost.go similarity index 87% rename from alertmanager/mattermost/mattermost.go rename to internal/alert/mattermost/mattermost.go index 34887662..34d1c716 100644 --- a/alertmanager/mattermost/mattermost.go +++ b/internal/alert/mattermost/mattermost.go @@ -8,11 +8,11 @@ import ( "net/http" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type Mattermost struct { @@ -45,11 +45,11 @@ type mmPayload struct { func NewMattermost(config map[string]interface{}, appCfg *config.App) *Mattermost { webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing mattermost with empty webhook url") + klog.InfoS("initializing mattermost with empty webhook url") return nil } - logrus.Infof("initializing mattermost with webhook url: %s", webhook) + klog.InfoS("initializing mattermost with webhook url", "webhook", webhook) title, _ := config["title"].(string) text, _ := config["text"].(string) @@ -69,20 +69,20 @@ func (m *Mattermost) Name() string { // SendMessage sends text message to the provider func (m *Mattermost) SendMessage(msg string) error { - logrus.Debugf("sending to mattermost msg: %s", msg) + klog.V(4).InfoS("sending to mattermost msg", "msg", msg) return m.sendAPI(m.buildMessage(nil, &msg)) } // SendEvent sends event to the provider func (m *Mattermost) SendEvent(e *event.Event) error { - logrus.Debugf("sending to mattermost event: %v", e) + klog.V(4).InfoS("sending to mattermost event", "event", e) return m.sendAPI(m.buildMessage(e, nil)) } func (m *Mattermost) sendAPI(content []byte) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() buffer := bytes.NewBuffer(content) request, err := http.NewRequest(http.MethodPost, m.webhook, buffer) if err != nil { diff --git a/alertmanager/mattermost/mattermost_test.go b/internal/alert/mattermost/mattermost_test.go similarity index 96% rename from alertmanager/mattermost/mattermost_test.go rename to internal/alert/mattermost/mattermost_test.go index 7a6c309d..7ddeebf5 100644 --- a/alertmanager/mattermost/mattermost_test.go +++ b/internal/alert/mattermost/mattermost_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/opsgenie/opsgenie.go b/internal/alert/opsgenie/opsgenie.go similarity index 89% rename from alertmanager/opsgenie/opsgenie.go rename to internal/alert/opsgenie/opsgenie.go index db9de5fb..9f14d3b7 100644 --- a/alertmanager/opsgenie/opsgenie.go +++ b/internal/alert/opsgenie/opsgenie.go @@ -7,11 +7,11 @@ import ( "io" "net/http" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) const ( @@ -41,11 +41,11 @@ type ogPayload struct { func NewOpsgenie(config map[string]interface{}, appCfg *config.App) *Opsgenie { apiKey, ok := config["apiKey"].(string) if !ok || len(apiKey) == 0 { - logrus.Warnf("initializing opsgenie with empty webhook url") + klog.InfoS("initializing opsgenie with empty webhook url") return nil } - logrus.Infof("initializing opsgenie with secret apikey") + klog.InfoS("initializing opsgenie with secret apikey") title, _ := config["title"].(string) text, _ := config["text"].(string) @@ -76,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 := util.GetDefaultClient() + client := k8s.GetDefaultClient() buffer := bytes.NewBuffer(content) request, err := http.NewRequest(http.MethodPost, m.url, buffer) if err != nil { diff --git a/alertmanager/opsgenie/opsgenie_test.go b/internal/alert/opsgenie/opsgenie_test.go similarity index 97% rename from alertmanager/opsgenie/opsgenie_test.go rename to internal/alert/opsgenie/opsgenie_test.go index 077ff0cc..09a5e9fc 100644 --- a/alertmanager/opsgenie/opsgenie_test.go +++ b/internal/alert/opsgenie/opsgenie_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/pagerduty/pagerduty.go b/internal/alert/pagerduty/pagerduty.go similarity index 91% rename from alertmanager/pagerduty/pagerduty.go rename to internal/alert/pagerduty/pagerduty.go index 072b8f03..0dd6cb6b 100644 --- a/alertmanager/pagerduty/pagerduty.go +++ b/internal/alert/pagerduty/pagerduty.go @@ -7,10 +7,10 @@ import ( "net/http" "strings" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) const ( @@ -54,11 +54,11 @@ type Pagerduty struct { func NewPagerDuty(config map[string]interface{}, appCfg *config.App) *Pagerduty { integrationKey, ok := config["integrationKey"].(string) if !ok || len(integrationKey) == 0 { - logrus.Warnf("initializing pagerduty with an empty integration key") + klog.InfoS("initializing pagerduty with an empty integration key") return nil } - logrus.Infof("initializing pagerduty with the provided integration key") + klog.InfoS("initializing pagerduty with the provided integration key") return &Pagerduty{ integrationKey: integrationKey, @@ -74,7 +74,7 @@ func (s *Pagerduty) Name() string { // SendEvent sends event to the provider func (s *Pagerduty) SendEvent(ev *event.Event) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() reqBody, err := s.buildRequestBodyPagerDuty(ev, s.integrationKey) if err != nil { diff --git a/alertmanager/pagerduty/pagerduty_test.go b/internal/alert/pagerduty/pagerduty_test.go similarity index 97% rename from alertmanager/pagerduty/pagerduty_test.go rename to internal/alert/pagerduty/pagerduty_test.go index c302c1ba..32f2e3d0 100644 --- a/alertmanager/pagerduty/pagerduty_test.go +++ b/internal/alert/pagerduty/pagerduty_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/rocketchat/rocketchat.go b/internal/alert/rocketchat/rocketchat.go similarity index 85% rename from alertmanager/rocketchat/rocketchat.go rename to internal/alert/rocketchat/rocketchat.go index e055c68d..1f3c179b 100644 --- a/alertmanager/rocketchat/rocketchat.go +++ b/internal/alert/rocketchat/rocketchat.go @@ -7,10 +7,10 @@ import ( "io" "net/http" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type RocketChat struct { @@ -29,11 +29,11 @@ type rocketChatWebhookPayload struct { func NewRocketChat(config map[string]interface{}, appCfg *config.App) *RocketChat { webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing Rocket Chat with empty webhook url") + klog.InfoS("initializing Rocket Chat with empty webhook url") return nil } - logrus.Infof("initializing Rocket Chat with webhook url: %s", webhook) + klog.InfoS("initializing Rocket Chat with webhook url", "webhook", webhook) text, _ := config["text"].(string) @@ -56,7 +56,7 @@ func (r *RocketChat) SendEvent(e *event.Event) error { } func (r *RocketChat) sendByRocketChatApi(reqBody string) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() buffer := bytes.NewBuffer([]byte(reqBody)) request, err := http.NewRequest(http.MethodPost, r.webhook, buffer) if err != nil { diff --git a/alertmanager/rocketchat/rocketchat_test.go b/internal/alert/rocketchat/rocketchat_test.go similarity index 96% rename from alertmanager/rocketchat/rocketchat_test.go rename to internal/alert/rocketchat/rocketchat_test.go index 689992b9..a1134bfb 100644 --- a/alertmanager/rocketchat/rocketchat_test.go +++ b/internal/alert/rocketchat/rocketchat_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/slack/slack.go b/internal/alert/slack/slack.go similarity index 90% rename from alertmanager/slack/slack.go rename to internal/alert/slack/slack.go index 06694706..f917cab6 100644 --- a/alertmanager/slack/slack.go +++ b/internal/alert/slack/slack.go @@ -5,12 +5,12 @@ import ( "fmt" "strings" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/event" - "github.com/sirupsen/logrus" slackClient "github.com/slack-go/slack" + "k8s.io/klog/v2" ) const ( @@ -42,10 +42,10 @@ func NewSlack(config map[string]interface{}, appCfg *config.App) *Slack { channel, hasChannel := config["channel"].(string) if hasToken && len(token) > 0 { if !hasChannel || len(channel) == 0 { - logrus.Warnf("initializing slack with token but missing channel") + klog.InfoS("initializing slack with token but missing channel") return nil } - logrus.Infof("initializing slack with token and channel: %s", channel) + klog.InfoS("initializing slack with token and channel", "channel", channel) return &Slack{ token: token, channel: channel, @@ -59,11 +59,11 @@ func NewSlack(config map[string]interface{}, appCfg *config.App) *Slack { // webhook mode: requires webhook webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing slack with empty webhook url and no token") + klog.InfoS("initializing slack with empty webhook url and no token") return nil } - logrus.Infof("initializing slack with webhook url: %s", webhook) + klog.InfoS("initializing slack with webhook url", "webhook", webhook) return &Slack{ webhook: webhook, @@ -82,7 +82,7 @@ func (s *Slack) Name() string { // SendEvent sends event to the provider func (s *Slack) SendEvent(ev *event.Event) error { - logrus.Infof("sending to slack event: %v", ev) + klog.InfoS("sending to slack event", "event", ev) // use custom title if it's provided, otherwise use default title := s.title diff --git a/alertmanager/slack/slack_test.go b/internal/alert/slack/slack_test.go similarity index 98% rename from alertmanager/slack/slack_test.go rename to internal/alert/slack/slack_test.go index 929d0d61..106ade47 100644 --- a/alertmanager/slack/slack_test.go +++ b/internal/alert/slack/slack_test.go @@ -3,8 +3,8 @@ package slack import ( "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" slackClient "github.com/slack-go/slack" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/teams/teams.go b/internal/alert/teams/teams.go similarity index 92% rename from alertmanager/teams/teams.go rename to internal/alert/teams/teams.go index d2ea0e8e..28728307 100644 --- a/alertmanager/teams/teams.go +++ b/internal/alert/teams/teams.go @@ -9,10 +9,10 @@ import ( "strings" "time" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) const ( @@ -43,11 +43,11 @@ type teamsFlowPayload struct { func NewTeams(config map[string]interface{}, appCfg *config.App) *Teams { webhook, ok := config["webhook"].(string) if !ok || len(webhook) == 0 { - logrus.Warnf("initializing Teams with empty flow url") + klog.InfoS("initializing Teams with empty flow url") return nil } - logrus.Infof("initializing Teams with flow url: %s", webhook) + klog.InfoS("initializing Teams with flow url", "webhook", webhook) title, _ := config["title"].(string) text, _ := config["text"].(string) @@ -104,7 +104,7 @@ func (t *Teams) sendAPI(payload []byte) error { request.Header.Set("Content-Type", "application/json") - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() resp, err := client.Do(request) if err != nil { return fmt.Errorf("failed to create HTTP response: %w", err) @@ -132,10 +132,9 @@ func (t *Teams) sendAPI(payload []byte) error { } if resp.StatusCode == http.StatusAccepted { - logrus.Warnf("Request accepted by Power Automate flow, "+ - "but not processed immediately. Attempt %d of %d.", - attempts+1, - t.maxRetries) + klog.InfoS("Request accepted by Power Automate flow, but not processed immediately", + "attempt", attempts+1, + "maxRetries", t.maxRetries) } else { body, err := io.ReadAll(resp.Body) if err != nil { diff --git a/alertmanager/teams/teams_test.go b/internal/alert/teams/teams_test.go similarity index 98% rename from alertmanager/teams/teams_test.go rename to internal/alert/teams/teams_test.go index 0a552de6..3f36a27a 100644 --- a/alertmanager/teams/teams_test.go +++ b/internal/alert/teams/teams_test.go @@ -6,8 +6,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/telegram/telegram.go b/internal/alert/telegram/telegram.go similarity index 87% rename from alertmanager/telegram/telegram.go rename to internal/alert/telegram/telegram.go index 59d6fbb7..11d40a9c 100644 --- a/alertmanager/telegram/telegram.go +++ b/internal/alert/telegram/telegram.go @@ -7,9 +7,9 @@ import ( "net/http" "strings" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "k8s.io/klog/v2" ) const ( @@ -42,20 +42,20 @@ type Telegram struct { func NewTelegram(config map[string]interface{}, appCfg *config.App) *Telegram { token, ok := config["token"].(string) if !ok || len(token) == 0 { - logrus.Warnf("initializing telegram with empty token") + klog.InfoS("initializing telegram with empty token") return nil } chatId, ok := config["chatId"].(string) if !ok || len(chatId) == 0 { - logrus.Warnf("initializing telegram with empty chat_id") + klog.InfoS("initializing telegram with empty chat_id") return nil } - logrus.Infof( - "initializing telegram with token %s and chat_id %s", - maskString(token), - maskString(chatId)) + klog.InfoS( + "initializing telegram", + "token", maskString(token), + "chatId", maskString(chatId)) // returns a new telegram object return &Telegram{ @@ -73,7 +73,7 @@ func (t *Telegram) Name() string { // SendEvent sends event to the provider func (t *Telegram) SendEvent(e *event.Event) error { - logrus.Debugf("sending to telegram event: %v", e) + klog.V(4).InfoS("sending to telegram event", "event", e) reqBody := t.buildRequestBodyTelegram(e, t.chatId, "") return t.sendByTelegramApi(reqBody) @@ -81,7 +81,7 @@ func (t *Telegram) SendEvent(e *event.Event) error { // SendMessage sends text message to the provider func (t *Telegram) SendMessage(msg string) error { - logrus.Debugf("sending to telegram msg: %s", msg) + klog.V(4).InfoS("sending to telegram msg", "msg", msg) reqBody := t.buildRequestBodyTelegram(new(event.Event), t.chatId, msg) return t.sendByTelegramApi(reqBody) diff --git a/alertmanager/telegram/telegram_test.go b/internal/alert/telegram/telegram_test.go similarity index 98% rename from alertmanager/telegram/telegram_test.go rename to internal/alert/telegram/telegram_test.go index cfb8a0b5..7682682e 100644 --- a/alertmanager/telegram/telegram_test.go +++ b/internal/alert/telegram/telegram_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/webhook/webhook.go b/internal/alert/webhook/webhook.go similarity index 86% rename from alertmanager/webhook/webhook.go rename to internal/alert/webhook/webhook.go index acf44df5..4abfba0f 100644 --- a/alertmanager/webhook/webhook.go +++ b/internal/alert/webhook/webhook.go @@ -7,11 +7,11 @@ import ( "net/http" "strings" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" - "github.com/sirupsen/logrus" + "k8s.io/klog/v2" ) type KeyValue struct { @@ -40,7 +40,7 @@ func (w *Webhook) SendMessage(msg string) error { func NewWebhook(config map[string]interface{}, appCfg *config.App) *Webhook { url, ok := config["url"].(string) if !ok || len(url) == 0 { - logrus.Warnf("initializing webhook with empty url") + klog.InfoS("initializing webhook with empty url") return nil } rawHeaders, ok := config["headers"] @@ -63,8 +63,10 @@ func NewWebhook(config map[string]interface{}, appCfg *config.App) *Webhook { var a Authentication json.Unmarshal(basicAuthJson, &a) - logrus.Infof("initializing webhook with url: %s "+ - "with headers: %s and username: %s", url, headers, a.UserName) + klog.InfoS("initializing webhook", + "url", url, + "headers", headers, + "username", a.UserName) return &Webhook{ webhook: url, @@ -82,7 +84,7 @@ func (w *Webhook) Name() string { // SendEvent sends event to the provider func (w *Webhook) SendEvent(ev *event.Event) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() reqBody := w.buildRequestBody(ev) buffer := bytes.NewBuffer(reqBody) @@ -123,13 +125,13 @@ func (w *Webhook) buildRequestBody( // add events part if it exists events := strings.TrimSpace(ev.Events) if len(events) > 0 { - eventsText = util.JsonEscape(ev.Events) + eventsText = k8s.JsonEscape(ev.Events) } // add logs part if it exists logs := strings.TrimSpace(ev.Logs) if len(logs) > 0 { - logsText = util.JsonEscape(ev.Logs) + logsText = k8s.JsonEscape(ev.Logs) } postBody, _ := json.Marshal(map[string]interface{}{ diff --git a/alertmanager/webhook/webhook_test.go b/internal/alert/webhook/webhook_test.go similarity index 97% rename from alertmanager/webhook/webhook_test.go rename to internal/alert/webhook/webhook_test.go index c3900272..0a008f19 100644 --- a/alertmanager/webhook/webhook_test.go +++ b/internal/alert/webhook/webhook_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/alertmanager/zenduty/zenduty.go b/internal/alert/zenduty/zenduty.go similarity index 89% rename from alertmanager/zenduty/zenduty.go rename to internal/alert/zenduty/zenduty.go index 889fde67..783f6e8f 100644 --- a/alertmanager/zenduty/zenduty.go +++ b/internal/alert/zenduty/zenduty.go @@ -8,11 +8,11 @@ import ( "net/http" "slices" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) const ( @@ -49,11 +49,11 @@ type zendutyPayload struct { func NewZenduty(config map[string]interface{}, appCfg *config.App) *Zenduty { integrationKey, ok := config["integrationKey"].(string) if !ok || len(integrationKey) == 0 { - logrus.Warnf("initializing zenduty with empty webhook url") + klog.InfoS("initializing zenduty with empty webhook url") return nil } - logrus.Infof("initializing zenduty with secret apikey") + klog.InfoS("initializing zenduty with secret apikey") // If alert type is not provided, or provided with invalid value // it will fallback to critical type @@ -87,7 +87,7 @@ func (m *Zenduty) SendEvent(e *event.Event) error { // sendAPI sends http request to Zenduty API func (m *Zenduty) sendAPI(content []byte) error { - client := util.GetDefaultClient() + client := k8s.GetDefaultClient() buffer := bytes.NewBuffer(content) url := m.url + "/" + m.integrationkey + "/" request, err := http.NewRequest(http.MethodPost, url, buffer) diff --git a/alertmanager/zenduty/zenduty_test.go b/internal/alert/zenduty/zenduty_test.go similarity index 97% rename from alertmanager/zenduty/zenduty_test.go rename to internal/alert/zenduty/zenduty_test.go index b28d1da6..7195a493 100644 --- a/alertmanager/zenduty/zenduty_test.go +++ b/internal/alert/zenduty/zenduty_test.go @@ -5,8 +5,8 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/event" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/event" "github.com/stretchr/testify/assert" ) diff --git a/client/client.go b/internal/client/client.go similarity index 79% rename from client/client.go rename to internal/client/client.go index 001f0003..f27f8d41 100644 --- a/client/client.go +++ b/internal/client/client.go @@ -6,12 +6,12 @@ import ( "os" "path/filepath" - "github.com/abahmed/kwatch/config" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" + "k8s.io/klog/v2" ) // Create returns kubernetes client after initializing it with in-cluster, or @@ -19,7 +19,8 @@ import ( func Create(appConfig *config.App) kubernetes.Interface { client, err := CreateClient(appConfig) if err != nil { - logrus.Fatalf("failed to create kubernetes client: %v", err) + klog.ErrorS(err, "failed to create kubernetes client") + os.Exit(1) } return client } @@ -29,7 +30,7 @@ func CreateClient(appConfig *config.App) (kubernetes.Interface, error) { // try to use in cluster config clientConfig, err := rest.InClusterConfig() if err != nil { - logrus.Warnf("cannot get kubernetes in cluster config: %v", err) + klog.InfoS("cannot get kubernetes in cluster config", "error", err) // try to use out of cluster config kubeconfigPath := getKubeconfigPath() @@ -51,7 +52,7 @@ func CreateClient(appConfig *config.App) (kubernetes.Interface, error) { return nil, fmt.Errorf("cannot create kubernetes client: %w", err) } - logrus.Debugf("created kubernetes client successfully") + klog.V(4).InfoS("created kubernetes client successfully") return clientset, nil } @@ -64,3 +65,11 @@ func getKubeconfigPath() string { } return kubeconfigPath } + +func GetNamespace() string { + namespace := os.Getenv("POD_NAMESPACE") + if namespace == "" { + return "kwatch" + } + return namespace +} diff --git a/client/client_test.go b/internal/client/client_test.go similarity index 98% rename from client/client_test.go rename to internal/client/client_test.go index 5154ebcb..288a0232 100644 --- a/client/client_test.go +++ b/internal/client/client_test.go @@ -5,7 +5,7 @@ import ( "path/filepath" "testing" - "github.com/abahmed/kwatch/config" + "github.com/abahmed/kwatch/internal/config" "github.com/stretchr/testify/assert" ) diff --git a/config/config.go b/internal/config/config.go similarity index 100% rename from config/config.go rename to internal/config/config.go diff --git a/config/config_test.go b/internal/config/config_test.go similarity index 100% rename from config/config_test.go rename to internal/config/config_test.go diff --git a/config/defaultConfig.go b/internal/config/default_config.go similarity index 100% rename from config/defaultConfig.go rename to internal/config/default_config.go diff --git a/config/loadConfig.go b/internal/config/load_config.go similarity index 83% rename from config/loadConfig.go rename to internal/config/load_config.go index 053fc8de..686e4c53 100644 --- a/config/loadConfig.go +++ b/internal/config/load_config.go @@ -6,8 +6,8 @@ import ( "regexp" "strings" - "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" + "k8s.io/klog/v2" ) // LoadConfig loads yaml configuration from file if provided, otherwise @@ -19,13 +19,13 @@ func LoadConfig() (*Config, error) { config := DefaultConfig() yamlFile, err := os.ReadFile(configFile) if err != nil { - logrus.Warnf("unable to load config file: %s", err.Error()) + klog.InfoS("unable to load config file", "error", err.Error()) return nil, err } err = yaml.Unmarshal(yamlFile, config) if err != nil { - logrus.Warnf("unable to parse config file: %s", err.Error()) + klog.InfoS("unable to parse config file", "error", err.Error()) return nil, err } @@ -34,8 +34,8 @@ func LoadConfig() (*Config, error) { getAllowForbidSlices(config.Namespaces) if len(config.AllowedNamespaces) > 0 && len(config.ForbiddenNamespaces) > 0 { - logrus.Error( - "Either allowed or forbidden namespaces must be set. " + + klog.ErrorS(nil, + "Either allowed or forbidden namespaces must be set. "+ "Can't set both") } @@ -44,7 +44,7 @@ func LoadConfig() (*Config, error) { getAllowForbidSlices(config.Reasons) if len(config.AllowedReasons) > 0 && len(config.ForbiddenReasons) > 0 { - logrus.Error("Either allowed or forbidden reasons must be set. " + + klog.ErrorS(nil, "Either allowed or forbidden reasons must be set. "+ "Can't set both") } @@ -52,14 +52,14 @@ func LoadConfig() (*Config, error) { config.IgnorePodNamePatterns, err = getCompiledIgnorePatterns(config.IgnorePodNames) if err != nil { - logrus.Errorf("Failed to compile pod name pattern: %s", err.Error()) + klog.ErrorS(err, "Failed to compile pod name pattern") } // Prepare ignored log patterns config.IgnoreLogPatternsCompiled, err = getCompiledIgnorePatterns(config.IgnoreLogPatterns) if err != nil { - logrus.Errorf("Failed to compile log pattern: %s", err.Error()) + klog.ErrorS(err, "Failed to compile log pattern") } // Parse proxy config diff --git a/constant/constant.go b/internal/constant/constant.go similarity index 100% rename from constant/constant.go rename to internal/constant/constant.go diff --git a/controller/controller.go b/internal/controller/controller.go similarity index 94% rename from controller/controller.go rename to internal/controller/controller.go index 3ec3f890..2133417e 100644 --- a/controller/controller.go +++ b/internal/controller/controller.go @@ -5,9 +5,8 @@ import ( "fmt" "time" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/handler" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/handler" "k8s.io/apimachinery/pkg/api/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" @@ -16,6 +15,7 @@ import ( corev1lister "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" + "k8s.io/klog/v2" ) type Controller struct { @@ -121,9 +121,9 @@ func (c *Controller) Run(ctx context.Context, workers int) error { defer c.podQueue.ShutDown() defer c.nodeQueue.ShutDown() - logrus.Info("starting controller") + klog.InfoS("starting controller") - logrus.Info("waiting for informer caches to sync") + klog.InfoS("waiting for informer caches to sync") syncFns := []cache.InformerSynced{c.podsSynced} if c.nodesSynced != nil { syncFns = append(syncFns, c.nodesSynced) @@ -132,7 +132,7 @@ func (c *Controller) Run(ctx context.Context, workers int) error { return fmt.Errorf("failed to wait for caches to sync") } - logrus.Info("starting workers") + klog.InfoS("starting workers") for i := 0; i < workers; i++ { go wait.UntilWithContext(ctx, c.runPodWorker, time.Second) if c.nodesSynced != nil { @@ -141,7 +141,7 @@ func (c *Controller) Run(ctx context.Context, workers int) error { } <-ctx.Done() - logrus.Info("shutting down workers") + klog.InfoS("shutting down workers") return nil } diff --git a/controller/controller_test.go b/internal/controller/controller_test.go similarity index 99% rename from controller/controller_test.go rename to internal/controller/controller_test.go index c0e55229..2dc8e63c 100644 --- a/controller/controller_test.go +++ b/internal/controller/controller_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/abahmed/kwatch/config" + "github.com/abahmed/kwatch/internal/config" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/event/event.go b/internal/event/event.go similarity index 100% rename from event/event.go rename to internal/event/event.go diff --git a/event/event_test.go b/internal/event/event_test.go similarity index 100% rename from event/event_test.go rename to internal/event/event_test.go diff --git a/event/format.go b/internal/event/format.go similarity index 98% rename from event/format.go rename to internal/event/format.go index bfd46cf3..0965b996 100644 --- a/event/format.go +++ b/internal/event/format.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/abahmed/kwatch/constant" + "github.com/abahmed/kwatch/internal/constant" ) func (e *Event) FormatMarkdown(clusterName, text, delimiter string) string { diff --git a/filter/containerKillingFilter.go b/internal/filter/container_killing_filter.go similarity index 100% rename from filter/containerKillingFilter.go rename to internal/filter/container_killing_filter.go diff --git a/filter/containerLogsFilter.go b/internal/filter/container_logs_filter.go similarity index 75% rename from filter/containerLogsFilter.go rename to internal/filter/container_logs_filter.go index e6e74a6d..663edcb1 100644 --- a/filter/containerLogsFilter.go +++ b/internal/filter/container_logs_filter.go @@ -1,8 +1,8 @@ package filter import ( - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type ContainerLogsFilter struct{} @@ -19,7 +19,7 @@ func (f ContainerLogsFilter) Execute(ctx *Context) bool { previousLogs = true } - logs := util.GetPodContainerLogs( + logs := k8s.GetPodContainerLogs( ctx.Client, ctx.Pod.Name, container.Name, @@ -29,9 +29,9 @@ func (f ContainerLogsFilter) Execute(ctx *Context) bool { for _, pattern := range ctx.Config.IgnoreLogPatternsCompiled { if pattern.MatchString(logs) { - logrus.Infof( - "skipping container %s logs as it matches the ignore log pattern", - container.Name) + klog.InfoS( + "skipping container logs as it matches the ignore log pattern", + "container", container.Name) return true } } diff --git a/filter/containerNameFilter.go b/internal/filter/container_name_filter.go similarity index 72% rename from filter/containerNameFilter.go rename to internal/filter/container_name_filter.go index 0e4511d1..230b8e09 100644 --- a/filter/containerNameFilter.go +++ b/internal/filter/container_name_filter.go @@ -1,8 +1,8 @@ package filter import ( - "github.com/sirupsen/logrus" "golang.org/x/exp/slices" + "k8s.io/klog/v2" ) type ContainerNameFilter struct{} @@ -11,9 +11,9 @@ func (f ContainerNameFilter) Execute(ctx *Context) bool { container := ctx.Container.Container if len(ctx.Config.IgnoreContainerNames) > 0 && slices.Contains(ctx.Config.IgnoreContainerNames, container.Name) { - logrus.Infof( - "skipping container %s as it is in the container ignore list", - container.Name) + klog.InfoS( + "skipping container as it is in the container ignore list", + "container", container.Name) return true } diff --git a/filter/containerReasonsFilter.go b/internal/filter/container_reasons_filter.go similarity index 88% rename from filter/containerReasonsFilter.go rename to internal/filter/container_reasons_filter.go index 08ed81e6..0e5a095a 100644 --- a/filter/containerReasonsFilter.go +++ b/internal/filter/container_reasons_filter.go @@ -1,8 +1,8 @@ package filter import ( - "github.com/sirupsen/logrus" "golang.org/x/exp/slices" + "k8s.io/klog/v2" ) type ContainerReasonsFilter struct{} @@ -35,17 +35,17 @@ func (f ContainerReasonsFilter) Execute(ctx *Context) bool { if len(ctx.Config.AllowedReasons) > 0 && !slices.Contains(ctx.Config.AllowedReasons, ctx.Container.Reason) { - logrus.Infof( - "skipping reason %s as it is not in the reason allow list", - ctx.Container.Reason) + klog.InfoS( + "skipping reason as it is not in the reason allow list", + "reason", ctx.Container.Reason) return true } if len(ctx.Config.ForbiddenReasons) > 0 && slices.Contains(ctx.Config.ForbiddenReasons, ctx.Container.Reason) { - logrus.Infof( - "skipping reason %s as it is in the reason forbid list", - ctx.Container.Reason) + klog.InfoS( + "skipping reason as it is in the reason forbid list", + "reason", ctx.Container.Reason) return true } diff --git a/filter/containerRestartsFilter.go b/internal/filter/container_restarts_filter.go similarity index 100% rename from filter/containerRestartsFilter.go rename to internal/filter/container_restarts_filter.go diff --git a/filter/containerStateFilter.go b/internal/filter/container_state_filter.go similarity index 100% rename from filter/containerStateFilter.go rename to internal/filter/container_state_filter.go diff --git a/filter/eventFilter.go b/internal/filter/event_filter.go similarity index 100% rename from filter/eventFilter.go rename to internal/filter/event_filter.go diff --git a/filter/filter.go b/internal/filter/filter.go similarity index 90% rename from filter/filter.go rename to internal/filter/filter.go index 3c93d138..96fece23 100644 --- a/filter/filter.go +++ b/internal/filter/filter.go @@ -3,8 +3,8 @@ package filter import ( "time" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/storage" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/storage" corev1 "k8s.io/api/core/v1" apiv1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" diff --git a/filter/filter_test.go b/internal/filter/filter_test.go similarity index 99% rename from filter/filter_test.go rename to internal/filter/filter_test.go index 07eabe57..89199dee 100644 --- a/filter/filter_test.go +++ b/internal/filter/filter_test.go @@ -4,9 +4,9 @@ import ( "regexp" "testing" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/storage" - "github.com/abahmed/kwatch/storage/memory" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/storage" + "github.com/abahmed/kwatch/internal/storage/memory" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/filter/namespaceFilter.go b/internal/filter/namespace_filter.go similarity index 66% rename from filter/namespaceFilter.go rename to internal/filter/namespace_filter.go index a64098a0..370d8917 100644 --- a/filter/namespaceFilter.go +++ b/internal/filter/namespace_filter.go @@ -1,8 +1,8 @@ package filter import ( - "github.com/sirupsen/logrus" "golang.org/x/exp/slices" + "k8s.io/klog/v2" ) type NamespaceFilter struct{} @@ -11,17 +11,17 @@ func (f NamespaceFilter) Execute(ctx *Context) bool { // filter by namespaces in config if specified if len(ctx.Config.AllowedNamespaces) > 0 && !slices.Contains(ctx.Config.AllowedNamespaces, ctx.Pod.Namespace) { - logrus.Infof( - "skipping namespace %s as it is not in the namespace allow list", - ctx.Pod.Namespace) + klog.InfoS( + "skipping namespace as it is not in the namespace allow list", + "namespace", ctx.Pod.Namespace) return true } if len(ctx.Config.ForbiddenNamespaces) > 0 && slices.Contains(ctx.Config.ForbiddenNamespaces, ctx.Pod.Namespace) { - logrus.Infof( - "skipping namespace %s as it is in the namespace forbid list", - ctx.Pod.Namespace) + klog.InfoS( + "skipping namespace as it is in the namespace forbid list", + "namespace", ctx.Pod.Namespace) return true } diff --git a/filter/podEventsFilter.go b/internal/filter/pod_events_filter.go similarity index 100% rename from filter/podEventsFilter.go rename to internal/filter/pod_events_filter.go diff --git a/filter/podNameFilter.go b/internal/filter/pod_name_filter.go similarity index 66% rename from filter/podNameFilter.go rename to internal/filter/pod_name_filter.go index c8903b38..cc6272ae 100644 --- a/filter/podNameFilter.go +++ b/internal/filter/pod_name_filter.go @@ -1,7 +1,7 @@ package filter import ( - "github.com/sirupsen/logrus" + "k8s.io/klog/v2" ) type PodNameFilter struct{} @@ -9,9 +9,9 @@ type PodNameFilter struct{} func (f PodNameFilter) Execute(ctx *Context) bool { for _, pattern := range ctx.Config.IgnorePodNamePatterns { if pattern.MatchString(ctx.Pod.Name) { - logrus.Infof( - "skipping pod %s as it is in the ignore pod name list", - ctx.Pod.Name) + klog.InfoS( + "skipping pod as it is in the ignore pod name list", + "pod", ctx.Pod.Name) return true } } diff --git a/filter/podOwnersFilter.go b/internal/filter/pod_owners_filter.go similarity index 100% rename from filter/podOwnersFilter.go rename to internal/filter/pod_owners_filter.go diff --git a/filter/podStatusFilter.go b/internal/filter/pod_status_filter.go similarity index 85% rename from filter/podStatusFilter.go rename to internal/filter/pod_status_filter.go index 10d782c8..269d56fb 100644 --- a/filter/podStatusFilter.go +++ b/internal/filter/pod_status_filter.go @@ -1,9 +1,9 @@ package filter import ( - "github.com/sirupsen/logrus" "golang.org/x/exp/slices" corev1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" ) type PodStatusFilter struct{} @@ -53,20 +53,20 @@ func (f PodStatusFilter) Execute(ctx *Context) bool { if len(ctx.PodReason) > 0 && len(ctx.Config.AllowedReasons) > 0 && !slices.Contains(ctx.Config.AllowedReasons, ctx.PodReason) { - logrus.Infof( - "skipping reason %s for pod %s as it is not in the reason allow list", - ctx.PodReason, - ctx.Pod.Name) + klog.InfoS( + "skipping reason for pod as it is not in the reason allow list", + "reason", ctx.PodReason, + "pod", ctx.Pod.Name) return true } if len(ctx.PodReason) > 0 && len(ctx.Config.ForbiddenReasons) > 0 && slices.Contains(ctx.Config.ForbiddenReasons, ctx.PodReason) { - logrus.Infof( - "skipping reason %s for pod %s as it is in the reason forbid list", - ctx.PodReason, - ctx.Pod.Name) + klog.InfoS( + "skipping reason for pod as it is in the reason forbid list", + "reason", ctx.PodReason, + "pod", ctx.Pod.Name) return true } diff --git a/handler/executeContainersFilters.go b/internal/handler/execute_containers_filters.go similarity index 77% rename from handler/executeContainersFilters.go rename to internal/handler/execute_containers_filters.go index c807a4c6..1a134ddf 100644 --- a/handler/executeContainersFilters.go +++ b/internal/handler/execute_containers_filters.go @@ -3,12 +3,12 @@ package handler import ( "time" - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/filter" - "github.com/abahmed/kwatch/storage" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/filter" + "github.com/abahmed/kwatch/internal/k8s" + "github.com/abahmed/kwatch/internal/storage" corev1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" ) func (h *handler) executeContainersFilters(ctx *filter.Context) { @@ -54,14 +54,14 @@ func (h *handler) executeContainersFilters(ctx *filter.Context) { ownerName = ctx.Owner.Name } - logrus.Printf( - "container only issue %s %s %s %s %s %d", - ctx.Container.Container.Name, - ctx.Pod.Name, - ownerName, - ctx.Container.Reason, - ctx.Container.Msg, - ctx.Container.ExitCode) + klog.InfoS( + "container only issue", + "container", ctx.Container.Container.Name, + "pod", ctx.Pod.Name, + "owner", ownerName, + "reason", ctx.Container.Reason, + "message", ctx.Container.Msg, + "exitCode", ctx.Container.ExitCode) h.alertManager.NotifyEvent(event.Event{ PodName: ctx.Pod.Name, @@ -69,7 +69,7 @@ func (h *handler) executeContainersFilters(ctx *filter.Context) { Namespace: ctx.Pod.Namespace, NodeName: ctx.Pod.Spec.NodeName, Reason: ctx.Container.Reason, - Events: util.GetPodEventsStr(ctx.Events), + Events: k8s.GetPodEventsStr(ctx.Events), Logs: ctx.Container.Logs, Labels: ctx.Pod.Labels, }) diff --git a/handler/executePodFilters.go b/internal/handler/execute_pod_filters.go similarity index 69% rename from handler/executePodFilters.go rename to internal/handler/execute_pod_filters.go index 1d85194a..1d1cfdb9 100644 --- a/handler/executePodFilters.go +++ b/internal/handler/execute_pod_filters.go @@ -1,11 +1,11 @@ package handler import ( - "github.com/abahmed/kwatch/event" - "github.com/abahmed/kwatch/filter" - "github.com/abahmed/kwatch/storage" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/event" + "github.com/abahmed/kwatch/internal/filter" + "github.com/abahmed/kwatch/internal/k8s" + "github.com/abahmed/kwatch/internal/storage" + "k8s.io/klog/v2" ) func (h *handler) executePodFilters(ctx *filter.Context) { @@ -39,7 +39,7 @@ func (h *handler) executePodFilters(ctx *filter.Context) { }, ) - logrus.Printf("pod only issue %s %s %s %s", ctx.Pod.Name, ownerName, ctx.PodReason, ctx.PodMsg) + klog.InfoS("pod only issue", "pod", ctx.Pod.Name, "owner", ownerName, "reason", ctx.PodReason, "message", ctx.PodMsg) h.alertManager.NotifyEvent(event.Event{ PodName: ctx.Pod.Name, @@ -47,7 +47,7 @@ func (h *handler) executePodFilters(ctx *filter.Context) { Namespace: ctx.Pod.Namespace, NodeName: ctx.Pod.Spec.NodeName, Reason: ctx.PodReason, - Events: util.GetPodEventsStr(ctx.Events), + Events: k8s.GetPodEventsStr(ctx.Events), Logs: "", Labels: ctx.Pod.Labels, }) diff --git a/handler/handler.go b/internal/handler/handler.go similarity index 86% rename from handler/handler.go rename to internal/handler/handler.go index a486ebca..c467ed77 100644 --- a/handler/handler.go +++ b/internal/handler/handler.go @@ -1,10 +1,10 @@ package handler import ( - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/filter" - "github.com/abahmed/kwatch/storage" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/filter" + "github.com/abahmed/kwatch/internal/storage" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes" corev1lister "k8s.io/client-go/listers/core/v1" @@ -25,7 +25,7 @@ type handler struct { memory storage.Storage podFilters []filter.Filter containerFilters []filter.Filter - alertManager *alertmanager.AlertManager + alertManager *alert.AlertManager podLister corev1lister.PodLister nodeLister corev1lister.NodeLister } @@ -34,7 +34,7 @@ func NewHandler( cli kubernetes.Interface, cfg *config.Config, mem storage.Storage, - alertManager *alertmanager.AlertManager) Handler { + alertManager *alert.AlertManager) Handler { // Order is important podFilters := []filter.Filter{ filter.NamespaceFilter{}, diff --git a/handler/handler_test.go b/internal/handler/handler_test.go similarity index 91% rename from handler/handler_test.go rename to internal/handler/handler_test.go index b3d5d03a..827c0054 100644 --- a/handler/handler_test.go +++ b/internal/handler/handler_test.go @@ -4,10 +4,10 @@ import ( "regexp" "testing" - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/storage" - "github.com/abahmed/kwatch/storage/memory" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/storage" + "github.com/abahmed/kwatch/internal/storage/memory" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -18,7 +18,7 @@ func TestNewHandler(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) assert.NotNil(t, h) @@ -28,7 +28,7 @@ func TestProcessPodNilObject(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) assert.NoError(t, h.ProcessPodObject(nil, false)) @@ -38,7 +38,7 @@ func TestProcessPodDeleted(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -58,7 +58,7 @@ func TestProcessNodeNilObject(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) assert.NoError(t, h.ProcessNodeObject(nil, false)) @@ -68,7 +68,7 @@ func TestProcessNodeDeleted(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -89,7 +89,7 @@ func TestProcessNodeNotReadyNoAlert(t *testing.T) { IgnoreNodeMessages: []string{"specific message"}, } mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -116,7 +116,7 @@ func TestProcessNodeReadyRecovery(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} mem.AddNode("test-node") @@ -144,7 +144,7 @@ func TestProcessNodeNotReadyAlert(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -173,7 +173,7 @@ func TestProcessNodeNotReadyWithIgnoredMessage(t *testing.T) { IgnoreNodeMessages: []string{"draining"}, } mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -200,7 +200,7 @@ func TestProcessNodeAlreadyKnownNotReady(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} mem.AddNode("test-node") @@ -229,7 +229,7 @@ func TestProcessPodWithPodIssues(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -260,7 +260,7 @@ func TestProcessPodWithContainersIssues(t *testing.T) { MaxRecentLogLines: 10, } mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -304,7 +304,7 @@ func TestProcessPodIgnoredNamespace(t *testing.T) { ForbiddenNamespaces: []string{"kube-system"}, } mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -335,7 +335,7 @@ func TestProcessPodIgnoredPodName(t *testing.T) { IgnorePodNamePatterns: []*regexp.Regexp{regexp.MustCompile("^test-.*")}, } mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -367,7 +367,7 @@ func TestProcessPodIgnoredContainerName(t *testing.T) { IgnoreContainerNames: []string{"test-container"}, } mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -409,7 +409,7 @@ func TestProcessPodSucceededPhase(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) @@ -430,7 +430,7 @@ func TestProcessPodCompletedStatus(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.Config{} mem := memory.NewMemory() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} h := NewHandler(client, cfg, mem, alertMgr) diff --git a/handler/processNode.go b/internal/handler/process_node.go similarity index 82% rename from handler/processNode.go rename to internal/handler/process_node.go index 9c743e98..128716f4 100644 --- a/handler/processNode.go +++ b/internal/handler/process_node.go @@ -4,9 +4,9 @@ import ( "fmt" "strings" - "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/klog/v2" ) func (h *handler) ProcessNode(key string, deleted bool) error { @@ -42,18 +42,18 @@ func (h *handler) ProcessNodeObject(node *corev1.Node, deleted bool) error { for _, c := range node.Status.Conditions { if c.Type == corev1.NodeReady { if c.Status == corev1.ConditionFalse && !h.memory.HasNode(node.Name) { - logrus.Printf("node %s is not ready: %s", node.Name, c.Reason) + klog.InfoS("node is not ready", "node", node.Name, "reason", c.Reason) // Skip alert if Reason is in IgnoreNodeReasons for _, ignoreReason := range h.config.IgnoreNodeReasons { if c.Reason == ignoreReason { - logrus.Debugf("Skipping Notify for node %s due to ignored reason: %s", node.Name, c.Reason) + klog.V(4).InfoS("Skipping Notify for node due to ignored reason", "node", node.Name, "reason", c.Reason) return nil } } // Skip alert if Message matches in IgnoreNodeMessages for _, ignoreMessage := range h.config.IgnoreNodeMessages { if strings.Contains(c.Message, ignoreMessage) { - logrus.Debugf("Skipping Notify for node %s due to ignored message: %s", node.Name, c.Message) + klog.V(4).InfoS("Skipping Notify for node due to ignored message", "node", node.Name, "message", c.Message) return nil } } diff --git a/handler/processPod.go b/internal/handler/process_pod.go similarity index 88% rename from handler/processPod.go rename to internal/handler/process_pod.go index 1f3af5a8..6e9a2b13 100644 --- a/handler/processPod.go +++ b/internal/handler/process_pod.go @@ -3,8 +3,8 @@ package handler import ( "fmt" - "github.com/abahmed/kwatch/filter" - "github.com/abahmed/kwatch/util" + "github.com/abahmed/kwatch/internal/filter" + "github.com/abahmed/kwatch/internal/k8s" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/tools/cache" @@ -51,7 +51,7 @@ func (h *handler) ProcessPodObject(pod *corev1.Pod, deleted bool) error { EvType: "ADDED", } - podEvents, err := util.GetPodEvents(ctx.Client, ctx.Pod.Name, ctx.Pod.Namespace) + podEvents, err := k8s.GetPodEvents(ctx.Client, ctx.Pod.Name, ctx.Pod.Namespace) if err != nil { return fmt.Errorf( "failed to get events for pod %s(%s): %w", diff --git a/health/health.go b/internal/health/health.go similarity index 85% rename from health/health.go rename to internal/health/health.go index bb4d4a03..1c6c810a 100644 --- a/health/health.go +++ b/internal/health/health.go @@ -7,8 +7,8 @@ import ( "strconv" "time" - "github.com/abahmed/kwatch/config" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/config" + "k8s.io/klog/v2" ) type HealthServer struct { @@ -30,7 +30,7 @@ func NewHealthServer(cfg config.HealthCheck) *HealthServer { func (h *HealthServer) Start(ctx context.Context) error { if !h.enabled { - logrus.Debug("health check is disabled") + klog.V(4).InfoS("health check is disabled") return nil } @@ -46,9 +46,9 @@ func (h *HealthServer) Start(ctx context.Context) error { } go func() { - logrus.Infof("starting health check server on port %d", h.port) + klog.InfoS("starting health check server", "port", h.port) if err := h.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - logrus.Errorf("health check server error: %v", err) + klog.ErrorS(err, "health check server error") } }() diff --git a/health/health_test.go b/internal/health/health_test.go similarity index 98% rename from health/health_test.go rename to internal/health/health_test.go index a06a8646..2148b0ff 100644 --- a/health/health_test.go +++ b/internal/health/health_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/abahmed/kwatch/config" + "github.com/abahmed/kwatch/internal/config" "github.com/stretchr/testify/assert" ) diff --git a/util/http.go b/internal/k8s/http.go similarity index 96% rename from util/http.go rename to internal/k8s/http.go index a88f6431..c12dc80b 100644 --- a/util/http.go +++ b/internal/k8s/http.go @@ -1,4 +1,4 @@ -package util +package k8s import ( "net/http" diff --git a/util/util.go b/internal/k8s/util.go similarity index 90% rename from util/util.go rename to internal/k8s/util.go index 8dfb1653..02937c76 100644 --- a/util/util.go +++ b/internal/k8s/util.go @@ -1,4 +1,4 @@ -package util +package k8s import ( "context" @@ -9,10 +9,10 @@ import ( "strings" "time" - "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" ) // GetPodEventsStr returns formatted events as a string for specified pod @@ -77,12 +77,12 @@ func GetPodContainerLogs( // get logs logs, err := getContainerLogs(c, name, namespace, &options) if err != nil { - logrus.Warnf( - "failed to get logs for container %s in pod %s@%s: %s", - name, - container, - namespace, - err.Error()) + klog.InfoS( + "failed to get logs for container", + "name", name, + "container", container, + "namespace", namespace, + "error", err.Error()) // try to decode response var status metav1.Status @@ -91,12 +91,12 @@ func GetPodContainerLogs( return status.Message } - logrus.Warnf( - "failed to parse logs for container %s in pod %s@%s: %s", - name, - container, - namespace, - parseErr.Error()) + klog.InfoS( + "failed to parse logs for container", + "name", name, + "container", container, + "namespace", namespace, + "error", parseErr.Error()) } return string(logs) @@ -184,12 +184,6 @@ func RandomString(n int) string { // SetLogFormatter sets the log formatter based on the provided format string func SetLogFormatter(formatter string) { - switch formatter { - case "json": - logrus.SetFormatter(&logrus.JSONFormatter{}) - default: - logrus.SetFormatter(&logrus.TextFormatter{}) - } } // GetNamespace returns the namespace where kwatch is running. diff --git a/util/util_test.go b/internal/k8s/util_test.go similarity index 99% rename from util/util_test.go rename to internal/k8s/util_test.go index 699c4237..ae165976 100644 --- a/util/util_test.go +++ b/internal/k8s/util_test.go @@ -1,4 +1,4 @@ -package util +package k8s import ( "errors" diff --git a/pvcmonitor/checkUsage.go b/internal/pvc/check_usage.go similarity index 84% rename from pvcmonitor/checkUsage.go rename to internal/pvc/check_usage.go index c373d611..22986aa4 100644 --- a/pvcmonitor/checkUsage.go +++ b/internal/pvc/check_usage.go @@ -1,10 +1,10 @@ -package pvcmonitor +package pvc import ( "fmt" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type PvcUsage struct { @@ -16,9 +16,9 @@ type PvcUsage struct { } func (p *PvcMonitor) checkUsage() { - nodes, err := util.GetNodes(p.client) + nodes, err := k8s.GetNodes(p.client) if err != nil { - logrus.Errorf("pvc monitor: failed to get nodes %s", err.Error()) + klog.ErrorS(err, "pvc monitor: failed to get nodes") return } diff --git a/pvcmonitor/getUsage.go b/internal/pvc/get_usage.go similarity index 83% rename from pvcmonitor/getUsage.go rename to internal/pvc/get_usage.go index f4e035f6..84133f4e 100644 --- a/pvcmonitor/getUsage.go +++ b/internal/pvc/get_usage.go @@ -1,10 +1,10 @@ -package pvcmonitor +package pvc import ( "encoding/json" - "github.com/abahmed/kwatch/util" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/k8s" + "k8s.io/klog/v2" ) type SummaryResponse struct { @@ -32,7 +32,7 @@ type Ref struct { func (p *PvcMonitor) getNodeUsage(nodeName string) ([]*PvcUsage, error) { result := make([]*PvcUsage, 0) - summaryResponse, err := util.GetNodeSummary(p.client, nodeName) + summaryResponse, err := k8s.GetNodeSummary(p.client, nodeName) if err != nil { return result, err @@ -51,15 +51,14 @@ func (p *PvcMonitor) getNodeUsage(nodeName string) ([]*PvcUsage, error) { } pvName, err := - util.GetPVNameFromPVC( + k8s.GetPVNameFromPVC( p.client, pod.PodRef.Namespace, vol.PvcRef.Name) if err != nil { - logrus.Errorf( - "failed to get pv name for pvc %s: %s", - vol.PvcRef.Name, - err.Error()) + klog.ErrorS(err, + "failed to get pv name for pvc", + "pvc", vol.PvcRef.Name) continue } diff --git a/pvcmonitor/pvc.go b/internal/pvc/pvc.go similarity index 75% rename from pvcmonitor/pvc.go rename to internal/pvc/pvc.go index 9be69e01..ee348137 100644 --- a/pvcmonitor/pvc.go +++ b/internal/pvc/pvc.go @@ -1,19 +1,19 @@ -package pvcmonitor +package pvc import ( "sync" "time" - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" ) type PvcMonitor struct { client kubernetes.Interface config *config.PvcMonitor - alertManager *alertmanager.AlertManager + alertManager *alert.AlertManager notifiedPvc map[string]bool mu sync.RWMutex } @@ -21,7 +21,7 @@ type PvcMonitor struct { func NewPvcMonitor( client kubernetes.Interface, config *config.PvcMonitor, - alertManager *alertmanager.AlertManager) *PvcMonitor { + alertManager *alert.AlertManager) *PvcMonitor { return &PvcMonitor{ client: client, config: config, @@ -58,7 +58,7 @@ func (p *PvcMonitor) cleanup() { count := len(p.notifiedPvc) if count > 1000 { - logrus.Debugf("pvc monitor: clearing %d stale entries from notifiedPvc cache", count) + klog.V(4).InfoS("pvc monitor: clearing stale entries from notifiedPvc cache", "count", count) p.notifiedPvc = make(map[string]bool) } } diff --git a/pvcmonitor/pvcmonitor_test.go b/internal/pvc/pvc_test.go similarity index 93% rename from pvcmonitor/pvcmonitor_test.go rename to internal/pvc/pvc_test.go index cbca75cc..d218dcf6 100644 --- a/pvcmonitor/pvcmonitor_test.go +++ b/internal/pvc/pvc_test.go @@ -1,12 +1,12 @@ -package pvcmonitor +package pvc import ( "encoding/json" "sync" "testing" - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" "github.com/stretchr/testify/assert" "k8s.io/client-go/kubernetes/fake" ) @@ -20,7 +20,7 @@ func TestNewPvcMonitor(t *testing.T) { Threshold: 80, Interval: 5, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) assert.NotNil(pvc) @@ -34,7 +34,7 @@ func TestNewPvcMonitorNilConfig(t *testing.T) { assert := assert.New(t) client := fake.NewSimpleClientset() - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, nil, alertMgr) assert.NotNil(pvc) @@ -57,7 +57,7 @@ func TestStartDisabled(t *testing.T) { cfg := &config.PvcMonitor{ Enabled: false, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) pvc.Start() @@ -68,7 +68,7 @@ func TestCleanupUnderThreshold(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.PvcMonitor{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) @@ -86,7 +86,7 @@ func TestCleanupOverThreshold(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.PvcMonitor{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) @@ -103,7 +103,7 @@ func TestCleanupExactlyThreshold(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.PvcMonitor{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) @@ -118,7 +118,7 @@ func TestCleanupExactlyThreshold(t *testing.T) { func TestPvcMonitorConcurrency(t *testing.T) { client := fake.NewSimpleClientset() cfg := &config.PvcMonitor{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) @@ -257,7 +257,7 @@ func TestCheckUsageNoNodes(t *testing.T) { Enabled: true, Threshold: 80, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) pvc.checkUsage() @@ -273,7 +273,7 @@ func TestCheckUsageAlreadyNotified(t *testing.T) { Enabled: true, Threshold: 80, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) pvc.notifiedPvc["existing-pv"] = true @@ -289,7 +289,7 @@ func TestCheckUsageUnderThreshold(t *testing.T) { Enabled: true, Threshold: 90, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) @@ -316,7 +316,7 @@ func TestCheckUsageOverThreshold(t *testing.T) { Enabled: true, Threshold: 80, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} pvc := NewPvcMonitor(client, cfg, alertMgr) diff --git a/startup/startup.go b/internal/startup/startup.go similarity index 71% rename from startup/startup.go rename to internal/startup/startup.go index ab3b50db..82e92ed2 100644 --- a/startup/startup.go +++ b/internal/startup/startup.go @@ -3,18 +3,18 @@ package startup import ( "context" - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/state" - "github.com/abahmed/kwatch/version" - "github.com/sirupsen/logrus" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/state" + "github.com/abahmed/kwatch/internal/version" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" ) type StartupManager struct { stateManager *state.StateManager - alertManager *alertmanager.AlertManager + alertManager *alert.AlertManager config *config.Config } @@ -29,7 +29,7 @@ func NewStartupManager( config: &config.Config{App: *appCfg}, } - sm.alertManager = &alertmanager.AlertManager{} + sm.alertManager = &alert.AlertManager{} sm.alertManager.Init(alertCfg, appCfg) return sm @@ -38,7 +38,7 @@ func NewStartupManager( func (s *StartupManager) HandleStartup(ctx context.Context) error { clusterID, err := s.stateManager.EnsureClusterID(ctx) if err != nil { - logrus.Warnf("failed to get/create cluster ID: %v", err) + klog.InfoS("failed to get/create cluster ID", "error", err) clusterID = "" } @@ -56,13 +56,13 @@ func (s *StartupManager) HandleStartup(ctx context.Context) error { } if err := s.stateManager.MarkAsInitialized(ctx, clusterID, currentVersion); err != nil { - logrus.Warnf("failed to mark as initialized: %v", err) + klog.InfoS("failed to mark as initialized", "error", err) } return nil } -func (s *StartupManager) GetAlertManager() *alertmanager.AlertManager { +func (s *StartupManager) GetAlertManager() *alert.AlertManager { return s.alertManager } diff --git a/startup/startup_test.go b/internal/startup/startup_test.go similarity index 99% rename from startup/startup_test.go rename to internal/startup/startup_test.go index c95a27d4..affc289e 100644 --- a/startup/startup_test.go +++ b/internal/startup/startup_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/abahmed/kwatch/config" + "github.com/abahmed/kwatch/internal/config" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/state/retry.go b/internal/state/retry.go similarity index 93% rename from state/retry.go rename to internal/state/retry.go index 2964ecdd..13a2d2fe 100644 --- a/state/retry.go +++ b/internal/state/retry.go @@ -5,10 +5,10 @@ import ( "strings" "time" - "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" ) const ( @@ -58,7 +58,7 @@ func (r *RetryConfigMapManager) UpdateWithRetry( return err } - logrus.Debugf("configmap conflict, retry %d/%d", i+1, maxRetries) + klog.V(4).InfoS("configmap conflict, retrying", "attempt", i+1, "maxRetries", maxRetries) time.Sleep(retryDelay) } diff --git a/state/state.go b/internal/state/state.go similarity index 97% rename from state/state.go rename to internal/state/state.go index 8c6d6976..9a45f6e6 100644 --- a/state/state.go +++ b/internal/state/state.go @@ -5,10 +5,10 @@ import ( "time" "github.com/google/uuid" - "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" ) const ( @@ -90,7 +90,7 @@ func (s *StateManager) MarkAsInitialized(ctx context.Context, clusterID, version if err != nil { return err } - logrus.Infof("created state configmap with cluster ID: %s", clusterID) + klog.InfoS("created state configmap with cluster ID", "clusterID", clusterID) return nil } diff --git a/state/state_test.go b/internal/state/state_test.go similarity index 100% rename from state/state_test.go rename to internal/state/state_test.go diff --git a/storage/memory/memory.go b/internal/storage/memory/memory.go similarity index 97% rename from storage/memory/memory.go rename to internal/storage/memory/memory.go index 1bba4563..89924e78 100644 --- a/storage/memory/memory.go +++ b/internal/storage/memory/memory.go @@ -3,7 +3,7 @@ package memory import ( "sync" - storage "github.com/abahmed/kwatch/storage" + storage "github.com/abahmed/kwatch/internal/storage" ) type memory struct { diff --git a/storage/memory/memory_test.go b/internal/storage/memory/memory_test.go similarity index 98% rename from storage/memory/memory_test.go rename to internal/storage/memory/memory_test.go index 094b962b..35fb4256 100644 --- a/storage/memory/memory_test.go +++ b/internal/storage/memory/memory_test.go @@ -4,7 +4,7 @@ import ( "sync" "testing" - storage "github.com/abahmed/kwatch/storage" + storage "github.com/abahmed/kwatch/internal/storage" ) func TestMemory(t *testing.T) { diff --git a/storage/storage.go b/internal/storage/storage.go similarity index 100% rename from storage/storage.go rename to internal/storage/storage.go diff --git a/upgrader/upgrader.go b/internal/upgrader/upgrader.go similarity index 79% rename from upgrader/upgrader.go rename to internal/upgrader/upgrader.go index 000356db..e68140d3 100644 --- a/upgrader/upgrader.go +++ b/internal/upgrader/upgrader.go @@ -5,13 +5,13 @@ import ( "fmt" "time" - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/state" - "github.com/abahmed/kwatch/version" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/constant" + "github.com/abahmed/kwatch/internal/state" + "github.com/abahmed/kwatch/internal/version" "github.com/google/go-github/v41/github" - "github.com/sirupsen/logrus" + "k8s.io/klog/v2" ) type GitHubReleaseChecker interface { @@ -43,7 +43,7 @@ type Upgrader struct { func NewUpgrader( config *config.Upgrader, - alertManager *alertmanager.AlertManager, + alertManager *alert.AlertManager, stateManager *state.StateManager, ) *Upgrader { return &Upgrader{ @@ -90,12 +90,12 @@ func (u *Upgrader) checkRelease() { "abahmed", "kwatch") if err != nil { - logrus.Warnf("failed to get latest release: %s", err.Error()) + klog.InfoS("failed to get latest release", "error", err.Error()) return } if r.TagName == nil { - logrus.Warnf("failed to get release tag: %+v", r) + klog.InfoS("failed to get release tag", "release", r) return } @@ -106,9 +106,9 @@ func (u *Upgrader) checkRelease() { if u.stateManager != nil { notifiedVersion := u.stateManager.GetNotifiedVersion(ctx) if notifiedVersion == *r.TagName { - logrus.Debugf( - "already notified about version %s, skipping", - *r.TagName) + klog.V(4).InfoS( + "already notified about version, skipping", + "version", *r.TagName) return } } @@ -117,7 +117,7 @@ func (u *Upgrader) checkRelease() { if u.stateManager != nil { if err := u.stateManager.SetNotifiedVersion(ctx, *r.TagName); err != nil { - logrus.Warnf("failed to set notified version: %v", err) + klog.InfoS("failed to set notified version", "error", err) } } } diff --git a/upgrader/upgrader_test.go b/internal/upgrader/upgrader_test.go similarity index 88% rename from upgrader/upgrader_test.go rename to internal/upgrader/upgrader_test.go index c71886a6..8ca9558e 100644 --- a/upgrader/upgrader_test.go +++ b/internal/upgrader/upgrader_test.go @@ -5,10 +5,10 @@ import ( "errors" "testing" - "github.com/abahmed/kwatch/alertmanager" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/state" - "github.com/abahmed/kwatch/version" + "github.com/abahmed/kwatch/internal/alert" + "github.com/abahmed/kwatch/internal/config" + "github.com/abahmed/kwatch/internal/state" + "github.com/abahmed/kwatch/internal/version" "github.com/google/go-github/v41/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -50,7 +50,7 @@ func TestNewUpgrader(t *testing.T) { assert := assert.New(t) upgraderConfig := &config.Upgrader{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) @@ -64,7 +64,7 @@ func TestNewUpgraderNilStateManager(t *testing.T) { assert := assert.New(t) upgraderConfig := &config.Upgrader{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} u := NewUpgrader(upgraderConfig, alertMgr, nil) assert.NotNil(u) @@ -77,7 +77,7 @@ func TestCheckUpdatesDisabled(t *testing.T) { upgraderConfig := &config.Upgrader{ DisableUpdateCheck: true, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) @@ -90,7 +90,7 @@ func TestUpgraderFields(t *testing.T) { upgraderConfig := &config.Upgrader{ DisableUpdateCheck: true, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) @@ -114,7 +114,7 @@ func TestUpgraderWithDisabledConfig(t *testing.T) { upgraderConfig := &config.Upgrader{ DisableUpdateCheck: true, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) @@ -128,7 +128,7 @@ func TestUpgraderWithEnabledConfig(t *testing.T) { upgraderConfig := &config.Upgrader{ DisableUpdateCheck: false, } - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) @@ -140,7 +140,7 @@ func TestUpgraderConfigDefaults(t *testing.T) { assert := assert.New(t) upgraderConfig := &config.Upgrader{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) @@ -151,7 +151,7 @@ func TestUpgraderConfigDefaults(t *testing.T) { func TestUpgraderNilConfigNilStateManager(t *testing.T) { assert := assert.New(t) - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} u := NewUpgrader(nil, alertMgr, nil) assert.NotNil(u) @@ -163,7 +163,7 @@ func TestUpgraderReuseStateManager(t *testing.T) { assert := assert.New(t) upgraderConfig := &config.Upgrader{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} sharedStateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") u1 := NewUpgrader(upgraderConfig, alertMgr, sharedStateMgr) @@ -180,7 +180,7 @@ func TestUpgraderStateManager(t *testing.T) { client := fake.NewSimpleClientset() stateMgr := state.NewStateManager(client, "kwatch") upgraderConfig := &config.Upgrader{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) assert.NotNil(u) @@ -208,7 +208,7 @@ func TestUpgraderGetNotifiedVersion(t *testing.T) { stateMgr := state.NewStateManager(client, namespace) upgraderConfig := &config.Upgrader{} - alertMgr := &alertmanager.AlertManager{} + alertMgr := &alert.AlertManager{} u := NewUpgrader(upgraderConfig, alertMgr, stateMgr) assert.NotNil(u) @@ -220,7 +220,7 @@ func TestCheckReleaseGitHubError(t *testing.T) { mockGithub.On("GetLatestRelease", mock.Anything, "abahmed", "kwatch"). Return(nil, nil, errors.New("rate limit exceeded")) - u := NewUpgrader(&config.Upgrader{}, &alertmanager.AlertManager{}, nil) + u := NewUpgrader(&config.Upgrader{}, &alert.AlertManager{}, nil) u.SetGitHubClient(mockGithub) u.checkRelease() @@ -233,7 +233,7 @@ func TestCheckReleaseNilTagName(t *testing.T) { mockGithub.On("GetLatestRelease", mock.Anything, "abahmed", "kwatch"). Return(&github.RepositoryRelease{}, nil, nil) - u := NewUpgrader(&config.Upgrader{}, &alertmanager.AlertManager{}, nil) + u := NewUpgrader(&config.Upgrader{}, &alert.AlertManager{}, nil) u.SetGitHubClient(mockGithub) u.checkRelease() @@ -247,7 +247,7 @@ func TestCheckReleaseSameVersion(t *testing.T) { mockGithub.On("GetLatestRelease", mock.Anything, "abahmed", "kwatch"). Return(&github.RepositoryRelease{TagName: ¤tVersion}, nil, nil) - u := NewUpgrader(&config.Upgrader{}, &alertmanager.AlertManager{}, nil) + u := NewUpgrader(&config.Upgrader{}, &alert.AlertManager{}, nil) u.SetGitHubClient(mockGithub) u.checkRelease() @@ -276,7 +276,7 @@ func TestCheckReleaseAlreadyNotified(t *testing.T) { stateMgr := state.NewStateManager(client, "kwatch") - u := NewUpgrader(&config.Upgrader{}, &alertmanager.AlertManager{}, stateMgr) + u := NewUpgrader(&config.Upgrader{}, &alert.AlertManager{}, stateMgr) u.SetGitHubClient(mockGithub) u.checkRelease() @@ -295,7 +295,7 @@ func TestCheckReleaseNewVersionNotifies(t *testing.T) { stateMgr := state.NewStateManager(fake.NewSimpleClientset(), "kwatch") - u := NewUpgrader(&config.Upgrader{}, &alertmanager.AlertManager{}, stateMgr) + u := NewUpgrader(&config.Upgrader{}, &alert.AlertManager{}, stateMgr) u.SetGitHubClient(mockGithub) u.SetAlertManager(mockAlert) @@ -328,7 +328,7 @@ func TestCheckReleaseNewVersionSetsState(t *testing.T) { stateMgr := state.NewStateManager(client, "kwatch") - u := NewUpgrader(&config.Upgrader{}, &alertmanager.AlertManager{}, stateMgr) + u := NewUpgrader(&config.Upgrader{}, &alert.AlertManager{}, stateMgr) u.SetGitHubClient(mockGithub) u.SetAlertManager(mockAlert) diff --git a/version/version.go b/internal/version/version.go similarity index 100% rename from version/version.go rename to internal/version/version.go diff --git a/version/version_test.go b/internal/version/version_test.go similarity index 100% rename from version/version_test.go rename to internal/version/version_test.go diff --git a/main.go b/main.go deleted file mode 100644 index 5b864e6d..00000000 --- a/main.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/abahmed/kwatch/client" - "github.com/abahmed/kwatch/config" - "github.com/abahmed/kwatch/constant" - "github.com/abahmed/kwatch/controller" - "github.com/abahmed/kwatch/handler" - "github.com/abahmed/kwatch/health" - "github.com/abahmed/kwatch/pvcmonitor" - "github.com/abahmed/kwatch/startup" - "github.com/abahmed/kwatch/storage/memory" - "github.com/abahmed/kwatch/upgrader" - "github.com/abahmed/kwatch/util" - "github.com/abahmed/kwatch/version" - "github.com/sirupsen/logrus" -) - -func main() { - cfg, err := config.LoadConfig() - if err != nil { - logrus.Fatalf("failed to load config: %s", err.Error()) - } - util.SetLogFormatter(cfg.App.LogFormatter) - - logrus.Info(fmt.Sprintf(constant.WelcomeMsg, version.Short())) - - k8sClient := client.Create(&cfg.App) - - sm := startup.NewStartupManager( - k8sClient, - util.GetNamespace(), - cfg.Alert, - &cfg.App, - ) - sm.HandleStartup(context.Background()) - - healthServer := health.NewHealthServer(cfg.HealthCheck) - healthServer.Start(context.Background()) - - upgrader := upgrader.NewUpgrader(&cfg.Upgrader, sm.GetAlertManager(), sm.GetStateManager()) - go upgrader.CheckUpdates() - - pvcMonitor := pvcmonitor.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 { - logrus.Fatalf("controller error: %s", err.Error()) - } - }() - - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - <-sigCh - - logrus.Info("shutting down gracefully...") - cancel() - healthServer.Stop(context.Background()) - os.Exit(0) -} From 8d418c1eb575996adcd5384df10cfece60eb5864 Mon Sep 17 00:00:00 2001 From: Abdelrahman Ahmed Date: Mon, 30 Mar 2026 23:17:18 +0200 Subject: [PATCH 2/3] fix: interpolate version in startup notification message --- internal/startup/startup.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/startup/startup.go b/internal/startup/startup.go index 82e92ed2..9e9cecbf 100644 --- a/internal/startup/startup.go +++ b/internal/startup/startup.go @@ -2,6 +2,7 @@ package startup import ( "context" + "fmt" "github.com/abahmed/kwatch/internal/alert" "github.com/abahmed/kwatch/internal/config" @@ -52,7 +53,7 @@ func (s *StartupManager) HandleStartup(ctx context.Context) error { if sendNotification { s.alertManager.Notify( - constant.WelcomeMsg) + fmt.Sprintf(constant.WelcomeMsg, currentVersion)) } if err := s.stateManager.MarkAsInitialized(ctx, clusterID, currentVersion); err != nil { From db8446e39389ca1ce6ea4677c4d7050b31a5e5d6 Mon Sep 17 00:00:00 2001 From: Abdelrahman Ahmed Date: Tue, 31 Mar 2026 00:31:44 +0200 Subject: [PATCH 3/3] fix: use json.Marshal to fix CodeQL security alert in matrix --- internal/alert/matrix/matrix.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/internal/alert/matrix/matrix.go b/internal/alert/matrix/matrix.go index db207571..17c41555 100644 --- a/internal/alert/matrix/matrix.go +++ b/internal/alert/matrix/matrix.go @@ -2,6 +2,7 @@ package matrix import ( "bytes" + "encoding/json" "fmt" "io" "net/http" @@ -72,15 +73,24 @@ func (m *Matrix) SendEvent(e *event.Event) error { func (m *Matrix) sendAPI(formattedMsg string) error { plainMsg := stripHtmlRegex(formattedMsg) - msg := fmt.Sprintf(`{ - "msgtype": "m.text", - "format": "org.matrix.custom.html", - "body": "%s", - "formatted_body": "%s" - }`, - k8s.JsonEscape(plainMsg), - k8s.JsonEscape(formattedMsg), - ) + + payload := struct { + Msgtype string `json:"msgtype"` + Format string `json:"format"` + Body string `json:"body"` + FormattedBody string `json:"formatted_body"` + }{ + Msgtype: "m.text", + Format: "org.matrix.custom.html", + Body: plainMsg, + FormattedBody: formattedMsg, + } + + msgBytes, err := json.Marshal(payload) + if err != nil { + return err + } + request, err := http.NewRequest( http.MethodPut, fmt.Sprintf( @@ -91,7 +101,7 @@ func (m *Matrix) sendAPI(formattedMsg string) error { k8s.RandomString(24), url.QueryEscape(m.accessToken), ), - bytes.NewBuffer([]byte(msg)), + bytes.NewBuffer(msgBytes), ) if err != nil { return err