From 251597b378cd0c6af322def1d53e247565420b3d Mon Sep 17 00:00:00 2001
From: Thomas Leclaire
Date: Mon, 29 Dec 2025 17:53:01 +0100
Subject: [PATCH] add some node filters
Signed-off-by: Thomas Leclaire
---
config/config.go | 3 +++
config/config_test.go | 57 ++++++++++++++++++++++++++++++++++++++++++
handler/processNode.go | 8 +++++-
3 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/config/config.go b/config/config.go
index 465fa4d1..a0d475f8 100644
--- a/config/config.go
+++ b/config/config.go
@@ -68,6 +68,9 @@ type Config struct {
// Patterns are compiled from IgnoreLogPatterns after populating
// IgnoreLogPatterns configuration
IgnoreLogPatternsCompiled []*regexp.Regexp
+
+ // IgnoreNodeReasons is an optional list of node reasons for which alerting should be skipped
+ IgnoreNodeReasons []string `yaml:"ignoreNodeReasons"`
}
// App confing struct
diff --git a/config/config_test.go b/config/config_test.go
index d1d1f6fd..600fa52d 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -122,3 +122,60 @@ func TestGetCompiledIgnorePatterns(t *testing.T) {
assert.NotNil(err)
}
+
+func TestIgnoreNodeReasonsLoading(t *testing.T) {
+ assert := assert.New(t)
+
+ defer os.Unsetenv("CONFIG_FILE")
+ defer os.RemoveAll("config.yaml")
+
+ os.Setenv("CONFIG_FILE", "config.yaml")
+
+ n := Config{
+ IgnoreNodeReasons: []string{"NotReady", "KubeletNotReady", "custom-reason"},
+ }
+ yamlData, _ := yaml.Marshal(&n)
+ os.WriteFile("config.yaml", yamlData, 0644)
+
+ cfg, _ := LoadConfig()
+ assert.NotNil(cfg)
+ assert.Equal([]string{"NotReady", "KubeletNotReady", "custom-reason"}, cfg.IgnoreNodeReasons)
+}
+
+func TestIgnoreNodeReasonsEmpty(t *testing.T) {
+ assert := assert.New(t)
+
+ defer os.Unsetenv("CONFIG_FILE")
+ defer os.RemoveAll("config.yaml")
+
+ os.Setenv("CONFIG_FILE", "config.yaml")
+
+ n := Config{
+ IgnoreNodeReasons: []string{},
+ }
+ yamlData, _ := yaml.Marshal(&n)
+ os.WriteFile("config.yaml", yamlData, 0644)
+
+ cfg, _ := LoadConfig()
+ assert.NotNil(cfg)
+ assert.Equal([]string{}, cfg.IgnoreNodeReasons)
+}
+
+func TestIgnoreNodeReasonsSpecialChars(t *testing.T) {
+ assert := assert.New(t)
+
+ defer os.Unsetenv("CONFIG_FILE")
+ defer os.RemoveAll("config.yaml")
+
+ os.Setenv("CONFIG_FILE", "config.yaml")
+
+ n := Config{
+ IgnoreNodeReasons: []string{"reason-1", "reason_2", "reason.with.dot", "reason/with/slash"},
+ }
+ yamlData, _ := yaml.Marshal(&n)
+ os.WriteFile("config.yaml", yamlData, 0644)
+
+ cfg, _ := LoadConfig()
+ assert.NotNil(cfg)
+ assert.Equal([]string{"reason-1", "reason_2", "reason.with.dot", "reason/with/slash"}, cfg.IgnoreNodeReasons)
+}
diff --git a/handler/processNode.go b/handler/processNode.go
index fc014391..dbfaeb23 100644
--- a/handler/processNode.go
+++ b/handler/processNode.go
@@ -2,7 +2,6 @@ package handler
import (
"fmt"
-
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -28,6 +27,13 @@ func (h *handler) ProcessNode(eventType string, obj runtime.Object) {
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)
+ // Skip alert if Reason is in IgnoreNodeReasons
+ for _, ignoreReason := range h.config.IgnoreNodeReasons {
+ if c.Reason == ignoreReason {
+ logrus.Printf("Skipping Notify for node %s due to ignored reason: %s", node.Name, c.Reason)
+ return
+ }
+ }
h.alertManager.Notify(fmt.Sprintf("Node %s is not ready: %s - %s",
node.Name,
c.Reason,