From 7b2d3e7004e36ca8eceee3833f94c3c3c0335e9c Mon Sep 17 00:00:00 2001 From: Ciprian Hacman Date: Mon, 13 Jul 2026 17:27:20 +0300 Subject: [PATCH] Fix invalid JSON in disk-log-message-filelog.json and enforce config format --- Makefile | 5 +- config/abrt-adaptor.json | 72 +++---- config/disk-log-message-filelog.json | 57 ++--- config/docker-monitor-filelog.json | 36 ++-- config/docker-monitor.json | 68 +++--- config/kernel-monitor-filelog.json | 100 ++++----- config/kernel-monitor.json | 196 +++++++++--------- config/readonly-monitor.json | 42 ++-- config/systemd-monitor.json | 54 ++--- .../windows-containerd-monitor-filelog.json | 56 ++--- config/windows-defender-monitor.json | 39 ++-- config/windows-health-checker-containerd.json | 65 +++--- config/windows-health-checker-docker.json | 65 +++--- config/windows-health-checker-kubelet.json | 65 +++--- config/windows-health-checker-kubeproxy.json | 65 +++--- pkg/systemlogmonitor/config_json_test.go | 83 ++++++++ 16 files changed, 576 insertions(+), 492 deletions(-) create mode 100644 pkg/systemlogmonitor/config_json_test.go diff --git a/Makefile b/Makefile index 89124b37a..ebe470fba 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ # Build the node-problem-detector image. .PHONY: all \ - lint vet fmt version test e2e-test \ + lint vet fmt fmt-configs version test e2e-test \ build-binaries build-container build-tar build \ docker-builder build-in-docker \ push-container push-tar push release clean depup \ @@ -144,6 +144,9 @@ fmt: $(GOLANGCI_LINT) find . -type f -name "*.go" | grep -v "./vendor/*" | xargs gofmt -s -w -l $(GOLANGCI_LINT) run --config .golangci.yml --fix ./... +fmt-configs: + UPDATE_EXPECTED=y go test -run TestShippedConfigs ./pkg/systemlogmonitor + version: @echo $(VERSION) diff --git a/config/abrt-adaptor.json b/config/abrt-adaptor.json index fc9f83cce..4202b254c 100644 --- a/config/abrt-adaptor.json +++ b/config/abrt-adaptor.json @@ -1,38 +1,38 @@ { - "plugin": "journald", - "pluginConfig": { - "source": "abrt-notification" - }, - "logPath": "/var/log/journal", - "lookback": "5m", - "bufferSize": 10, - "source": "abrt-adaptor", - "conditions": [], - "rules": [ - { - "type": "temporary", - "reason": "CCPPCrash", - "pattern": "Process \\d+ \\(\\S+\\) crashed in .*" - }, - { - "type": "temporary", - "reason": "UncaughtException", - "pattern": "Process \\d+ \\(\\S+\\) of user \\d+ encountered an uncaught \\S+ exception" - }, - { - "type": "temporary", - "reason": "XorgCrash", - "pattern": "Display server \\S+ crash in \\S+" - }, - { - "type": "temporary", - "reason": "VMcore", - "pattern": "System encountered a fatal error in \\S+" - }, - { - "type": "temporary", - "reason": "KernelOops", - "pattern": "System encountered a non-fatal error in \\S+" - } - ] + "plugin": "journald", + "pluginConfig": { + "source": "abrt-notification" + }, + "logPath": "/var/log/journal", + "lookback": "5m", + "bufferSize": 10, + "source": "abrt-adaptor", + "conditions": [], + "rules": [ + { + "type": "temporary", + "reason": "CCPPCrash", + "pattern": "Process \\d+ \\(\\S+\\) crashed in .*" + }, + { + "type": "temporary", + "reason": "UncaughtException", + "pattern": "Process \\d+ \\(\\S+\\) of user \\d+ encountered an uncaught \\S+ exception" + }, + { + "type": "temporary", + "reason": "XorgCrash", + "pattern": "Display server \\S+ crash in \\S+" + }, + { + "type": "temporary", + "reason": "VMcore", + "pattern": "System encountered a fatal error in \\S+" + }, + { + "type": "temporary", + "reason": "KernelOops", + "pattern": "System encountered a non-fatal error in \\S+" + } + ] } diff --git a/config/disk-log-message-filelog.json b/config/disk-log-message-filelog.json index 575b168c6..3ec614d92 100644 --- a/config/disk-log-message-filelog.json +++ b/config/disk-log-message-filelog.json @@ -1,28 +1,31 @@ { - "plugin": "filelog", - "pluginConfig": { - "timestamp": "^.{15}", - "message": "(?i)Currently unreadable.*sectors|(?i)Offline uncorrectable sectors", - "timestampFormat": "Jan _2 15:04:05" - }, - "logPath": "/var/log/messages", - "lookback": "10h", - "bufferSize": 1, - "source": "disk-monitor", - "skipList": [ " audit:", " audit[" ], - "conditions": [ - { - "type": "DiskBadBlock", - "reason": "DiskBadBlock", - "message": "Disk no bad block" - }, - ], - "rules": [ - { - "type": "permanent", - "condition": "DiskBadBlock", - "reason": "DiskBadBlock", - "pattern": ".*([1-9]\\d{2,}) (Currently unreadable.*sectors|Offline uncorrectable sectors).*" - }, - ] -} \ No newline at end of file + "plugin": "filelog", + "pluginConfig": { + "timestamp": "^.{15}", + "message": "(?i)Currently unreadable.*sectors|(?i)Offline uncorrectable sectors", + "timestampFormat": "Jan _2 15:04:05" + }, + "logPath": "/var/log/messages", + "lookback": "10h", + "bufferSize": 1, + "source": "disk-monitor", + "skipList": [ + " audit:", + " audit[" + ], + "conditions": [ + { + "type": "DiskBadBlock", + "reason": "DiskBadBlock", + "message": "Disk no bad block" + } + ], + "rules": [ + { + "type": "permanent", + "condition": "DiskBadBlock", + "reason": "DiskBadBlock", + "pattern": ".*([1-9]\\d{2,}) (Currently unreadable.*sectors|Offline uncorrectable sectors).*" + } + ] +} diff --git a/config/docker-monitor-filelog.json b/config/docker-monitor-filelog.json index db504cac7..7d9510081 100644 --- a/config/docker-monitor-filelog.json +++ b/config/docker-monitor-filelog.json @@ -1,20 +1,20 @@ { - "plugin": "filelog", - "pluginConfig": { - "timestamp": "^time=\"(\\S*)\"", - "message": "msg=\"([^\n]*)\"", - "timestampFormat": "2006-01-02T15:04:05.999999999-07:00" - }, - "logPath": "/var/log/docker.log", - "lookback": "5m", - "bufferSize": 10, - "source": "docker-monitor", - "conditions": [], - "rules": [ - { - "type": "temporary", - "reason": "CorruptDockerImage", - "pattern": "Error trying v2 registry: failed to register layer: rename /var/lib/docker/image/(.+) /var/lib/docker/image/(.+): directory not empty.*" - } - ] + "plugin": "filelog", + "pluginConfig": { + "timestamp": "^time=\"(\\S*)\"", + "message": "msg=\"([^\n]*)\"", + "timestampFormat": "2006-01-02T15:04:05.999999999-07:00" + }, + "logPath": "/var/log/docker.log", + "lookback": "5m", + "bufferSize": 10, + "source": "docker-monitor", + "conditions": [], + "rules": [ + { + "type": "temporary", + "reason": "CorruptDockerImage", + "pattern": "Error trying v2 registry: failed to register layer: rename /var/lib/docker/image/(.+) /var/lib/docker/image/(.+): directory not empty.*" + } + ] } diff --git a/config/docker-monitor.json b/config/docker-monitor.json index 27435be26..3a1e04cd6 100644 --- a/config/docker-monitor.json +++ b/config/docker-monitor.json @@ -1,36 +1,36 @@ { - "plugin": "journald", - "pluginConfig": { - "source": "dockerd" - }, - "logPath": "/var/log/journal", - "lookback": "5m", - "bufferSize": 10, - "source": "docker-monitor", - "metricsReporting": true, - "conditions": [ - { - "type": "CorruptDockerOverlay2", - "reason": "NoCorruptDockerOverlay2", - "message": "docker overlay2 is functioning properly" - } - ], - "rules": [ - { - "type": "temporary", - "reason": "CorruptDockerImage", - "pattern": "Error trying v2 registry: failed to register layer: rename /var/lib/docker/image/(.+) /var/lib/docker/image/(.+): directory not empty.*" - }, - { - "type": "permanent", - "condition": "CorruptDockerOverlay2", - "reason": "CorruptDockerOverlay2", - "pattern": "returned error: readlink /var/lib/docker/overlay2.*: invalid argument.*" - }, - { - "type": "temporary", - "reason": "DockerContainerStartupFailure", - "pattern": "OCI runtime start failed: container process is already dead: unknown" - } - ] + "plugin": "journald", + "pluginConfig": { + "source": "dockerd" + }, + "logPath": "/var/log/journal", + "lookback": "5m", + "bufferSize": 10, + "source": "docker-monitor", + "metricsReporting": true, + "conditions": [ + { + "type": "CorruptDockerOverlay2", + "reason": "NoCorruptDockerOverlay2", + "message": "docker overlay2 is functioning properly" + } + ], + "rules": [ + { + "type": "temporary", + "reason": "CorruptDockerImage", + "pattern": "Error trying v2 registry: failed to register layer: rename /var/lib/docker/image/(.+) /var/lib/docker/image/(.+): directory not empty.*" + }, + { + "type": "permanent", + "condition": "CorruptDockerOverlay2", + "reason": "CorruptDockerOverlay2", + "pattern": "returned error: readlink /var/lib/docker/overlay2.*: invalid argument.*" + }, + { + "type": "temporary", + "reason": "DockerContainerStartupFailure", + "pattern": "OCI runtime start failed: container process is already dead: unknown" + } + ] } diff --git a/config/kernel-monitor-filelog.json b/config/kernel-monitor-filelog.json index 1f7d39ac1..b45b9ee1f 100644 --- a/config/kernel-monitor-filelog.json +++ b/config/kernel-monitor-filelog.json @@ -1,52 +1,52 @@ { - "plugin": "filelog", - "pluginConfig": { - "timestamp": "^.{15}", - "message": "kernel: \\[.*\\] (.*)", - "timestampFormat": "Jan _2 15:04:05" - }, - "logPath": "/var/log/kern.log", - "lookback": "5m", - "bufferSize": 10, - "source": "kernel-monitor", - "conditions": [ - { - "type": "KernelDeadlock", - "reason": "KernelHasNoDeadlock", - "message": "kernel has no deadlock" - } - ], - "rules": [ - { - "type": "temporary", - "reason": "OOMKilling", - "pattern": "Killed process \\d+ (.+) total-vm:\\d+kB, anon-rss:\\d+kB, file-rss:\\d+kB.*" - }, - { - "type": "temporary", - "reason": "TaskHung", - "pattern": "task \\S+:\\w+ blocked for more than \\w+ seconds\\." - }, - { - "type": "temporary", - "reason": "UnregisterNetDevice", - "pattern": "unregister_netdevice: waiting for \\w+ to become free. Usage count = \\d+" - }, - { - "type": "temporary", - "reason": "KernelOops", - "pattern": "BUG: unable to handle kernel NULL pointer dereference at .*" - }, - { - "type": "temporary", - "reason": "KernelOops", - "pattern": "divide error: 0000 \\[#\\d+\\] SMP" - }, - { - "type": "permanent", - "condition": "KernelDeadlock", - "reason": "DockerHung", - "pattern": "task docker:\\w+ blocked for more than \\w+ seconds\\." - } - ] + "plugin": "filelog", + "pluginConfig": { + "timestamp": "^.{15}", + "message": "kernel: \\[.*\\] (.*)", + "timestampFormat": "Jan _2 15:04:05" + }, + "logPath": "/var/log/kern.log", + "lookback": "5m", + "bufferSize": 10, + "source": "kernel-monitor", + "conditions": [ + { + "type": "KernelDeadlock", + "reason": "KernelHasNoDeadlock", + "message": "kernel has no deadlock" + } + ], + "rules": [ + { + "type": "temporary", + "reason": "OOMKilling", + "pattern": "Killed process \\d+ (.+) total-vm:\\d+kB, anon-rss:\\d+kB, file-rss:\\d+kB.*" + }, + { + "type": "temporary", + "reason": "TaskHung", + "pattern": "task \\S+:\\w+ blocked for more than \\w+ seconds\\." + }, + { + "type": "temporary", + "reason": "UnregisterNetDevice", + "pattern": "unregister_netdevice: waiting for \\w+ to become free. Usage count = \\d+" + }, + { + "type": "temporary", + "reason": "KernelOops", + "pattern": "BUG: unable to handle kernel NULL pointer dereference at .*" + }, + { + "type": "temporary", + "reason": "KernelOops", + "pattern": "divide error: 0000 \\[#\\d+\\] SMP" + }, + { + "type": "permanent", + "condition": "KernelDeadlock", + "reason": "DockerHung", + "pattern": "task docker:\\w+ blocked for more than \\w+ seconds\\." + } + ] } diff --git a/config/kernel-monitor.json b/config/kernel-monitor.json index a132e47a3..8557957ef 100644 --- a/config/kernel-monitor.json +++ b/config/kernel-monitor.json @@ -1,100 +1,100 @@ { - "plugin": "kmsg", - "logPath": "/dev/kmsg", - "lookback": "5m", - "bufferSize": 10, - "source": "kernel-monitor", - "metricsReporting": true, - "conditions": [ - { - "type": "KernelDeadlock", - "reason": "KernelHasNoDeadlock", - "message": "kernel has no deadlock" - }, - { - "type": "XfsShutdown", - "reason": "XfsHasNotShutDown", - "message": "XFS has not shutdown" - }, - { - "type": "CperHardwareErrorFatal", - "reason": "CperHardwareHasNoFatalError", - "message": "UEFI CPER has no fatal error" - } - ], - "rules": [ - { - "type": "temporary", - "reason": "OOMKilling", - "pattern": "Killed process \\d+ (.+) total-vm:\\d+kB, anon-rss:\\d+kB, file-rss:\\d+kB.*" - }, - { - "type": "temporary", - "reason": "TaskHung", - "pattern": "task [\\S ]+:\\w+ blocked for more than \\w+ seconds\\." - }, - { - "type": "temporary", - "reason": "UnregisterNetDevice", - "pattern": "unregister_netdevice: waiting for \\w+ to become free. Usage count = \\d+" - }, - { - "type": "temporary", - "reason": "KernelOops", - "pattern": "BUG: unable to handle kernel NULL pointer dereference at .*" - }, - { - "type": "temporary", - "reason": "KernelOops", - "pattern": "divide error: 0000 \\[#\\d+\\] SMP" - }, - { - "type": "temporary", - "reason": "Ext4Error", - "pattern": "EXT4-fs error .*" - }, - { - "type": "temporary", - "reason": "Ext4Warning", - "pattern": "EXT4-fs warning .*" - }, - { - "type": "temporary", - "reason": "IOError", - "pattern": "Buffer I/O error .*" - }, - { - "type": "permanent", - "condition": "XfsShutdown", - "reason": "XfsHasShutdown", - "pattern": "XFS .* Shutting down filesystem.?" - }, - { - "type": "temporary", - "reason": "MemoryReadError", - "pattern": "CE memory read error .*" - }, - { - "type": "temporary", - "reason": "CperHardwareErrorCorrected", - "pattern": ".*\\[Hardware Error\\]: event severity: corrected$" - }, - { - "type": "temporary", - "reason": "CperHardwareErrorRecoverable", - "pattern": ".*\\[Hardware Error\\]: event severity: recoverable$" - }, - { - "type": "permanent", - "condition": "CperHardwareErrorFatal", - "reason": "CperHardwareErrorFatal", - "pattern": ".*\\[Hardware Error\\]: event severity: fatal$" - }, - { - "type": "permanent", - "condition": "KernelDeadlock", - "reason": "DockerHung", - "pattern": "task docker:\\w+ blocked for more than \\w+ seconds\\." - } - ] + "plugin": "kmsg", + "logPath": "/dev/kmsg", + "lookback": "5m", + "bufferSize": 10, + "source": "kernel-monitor", + "metricsReporting": true, + "conditions": [ + { + "type": "KernelDeadlock", + "reason": "KernelHasNoDeadlock", + "message": "kernel has no deadlock" + }, + { + "type": "XfsShutdown", + "reason": "XfsHasNotShutDown", + "message": "XFS has not shutdown" + }, + { + "type": "CperHardwareErrorFatal", + "reason": "CperHardwareHasNoFatalError", + "message": "UEFI CPER has no fatal error" + } + ], + "rules": [ + { + "type": "temporary", + "reason": "OOMKilling", + "pattern": "Killed process \\d+ (.+) total-vm:\\d+kB, anon-rss:\\d+kB, file-rss:\\d+kB.*" + }, + { + "type": "temporary", + "reason": "TaskHung", + "pattern": "task [\\S ]+:\\w+ blocked for more than \\w+ seconds\\." + }, + { + "type": "temporary", + "reason": "UnregisterNetDevice", + "pattern": "unregister_netdevice: waiting for \\w+ to become free. Usage count = \\d+" + }, + { + "type": "temporary", + "reason": "KernelOops", + "pattern": "BUG: unable to handle kernel NULL pointer dereference at .*" + }, + { + "type": "temporary", + "reason": "KernelOops", + "pattern": "divide error: 0000 \\[#\\d+\\] SMP" + }, + { + "type": "temporary", + "reason": "Ext4Error", + "pattern": "EXT4-fs error .*" + }, + { + "type": "temporary", + "reason": "Ext4Warning", + "pattern": "EXT4-fs warning .*" + }, + { + "type": "temporary", + "reason": "IOError", + "pattern": "Buffer I/O error .*" + }, + { + "type": "permanent", + "condition": "XfsShutdown", + "reason": "XfsHasShutdown", + "pattern": "XFS .* Shutting down filesystem.?" + }, + { + "type": "temporary", + "reason": "MemoryReadError", + "pattern": "CE memory read error .*" + }, + { + "type": "temporary", + "reason": "CperHardwareErrorCorrected", + "pattern": ".*\\[Hardware Error\\]: event severity: corrected$" + }, + { + "type": "temporary", + "reason": "CperHardwareErrorRecoverable", + "pattern": ".*\\[Hardware Error\\]: event severity: recoverable$" + }, + { + "type": "permanent", + "condition": "CperHardwareErrorFatal", + "reason": "CperHardwareErrorFatal", + "pattern": ".*\\[Hardware Error\\]: event severity: fatal$" + }, + { + "type": "permanent", + "condition": "KernelDeadlock", + "reason": "DockerHung", + "pattern": "task docker:\\w+ blocked for more than \\w+ seconds\\." + } + ] } diff --git a/config/readonly-monitor.json b/config/readonly-monitor.json index 256e431e8..623aa70af 100644 --- a/config/readonly-monitor.json +++ b/config/readonly-monitor.json @@ -1,23 +1,23 @@ { - "plugin": "kmsg", - "logPath": "/dev/kmsg", - "lookback": "5m", - "bufferSize": 10, - "source": "readonly-monitor", - "metricsReporting": true, - "conditions": [ - { - "type": "ReadonlyFilesystem", - "reason": "FilesystemIsNotReadOnly", - "message": "Filesystem is not read-only" - } - ], - "rules": [ - { - "type": "permanent", - "condition": "ReadonlyFilesystem", - "reason": "FilesystemIsReadOnly", - "pattern": "Remounting filesystem read-only" - } - ] + "plugin": "kmsg", + "logPath": "/dev/kmsg", + "lookback": "5m", + "bufferSize": 10, + "source": "readonly-monitor", + "metricsReporting": true, + "conditions": [ + { + "type": "ReadonlyFilesystem", + "reason": "FilesystemIsNotReadOnly", + "message": "Filesystem is not read-only" + } + ], + "rules": [ + { + "type": "permanent", + "condition": "ReadonlyFilesystem", + "reason": "FilesystemIsReadOnly", + "pattern": "Remounting filesystem read-only" + } + ] } diff --git a/config/systemd-monitor.json b/config/systemd-monitor.json index a749b1256..2206f783e 100644 --- a/config/systemd-monitor.json +++ b/config/systemd-monitor.json @@ -1,29 +1,29 @@ { - "plugin": "journald", - "pluginConfig": { - "source": "systemd" - }, - "logPath": "/var/log/journal", - "lookback": "5m", - "bufferSize": 10, - "source": "systemd-monitor", - "metricsReporting": true, - "conditions": [], - "rules": [ - { - "type": "temporary", - "reason": "KubeletStart", - "pattern": "Started (Kubernetes kubelet|kubelet.service|kubelet.service - Kubernetes kubelet|kubelet.service - .*)." - }, - { - "type": "temporary", - "reason": "DockerStart", - "pattern": "Starting (Docker Application Container Engine|docker.service|docker.service - Docker Application Container Engine)..." - }, - { - "type": "temporary", - "reason": "ContainerdStart", - "pattern": "Starting (containerd container runtime|containerd.service|containerd.service - containerd container runtime)..." - } - ] + "plugin": "journald", + "pluginConfig": { + "source": "systemd" + }, + "logPath": "/var/log/journal", + "lookback": "5m", + "bufferSize": 10, + "source": "systemd-monitor", + "metricsReporting": true, + "conditions": [], + "rules": [ + { + "type": "temporary", + "reason": "KubeletStart", + "pattern": "Started (Kubernetes kubelet|kubelet.service|kubelet.service - Kubernetes kubelet|kubelet.service - .*)." + }, + { + "type": "temporary", + "reason": "DockerStart", + "pattern": "Starting (Docker Application Container Engine|docker.service|docker.service - Docker Application Container Engine)..." + }, + { + "type": "temporary", + "reason": "ContainerdStart", + "pattern": "Starting (containerd container runtime|containerd.service|containerd.service - containerd container runtime)..." + } + ] } diff --git a/config/windows-containerd-monitor-filelog.json b/config/windows-containerd-monitor-filelog.json index 05247415b..1f96d60d3 100644 --- a/config/windows-containerd-monitor-filelog.json +++ b/config/windows-containerd-monitor-filelog.json @@ -1,30 +1,30 @@ { - "plugin": "filelog", - "pluginConfig": { - "timestamp": "^time=\"(\\S*)\"", - "message": "msg=\"?([^\n]*)\"?", - "timestampFormat": "2006-01-02T15:04:05.999999999Z" - }, - "logPath": "C:\\etc\\kubernetes\\logs\\containerd.log", - "lookback": "5m", - "bufferSize": 10, - "source": "containerd", - "conditions": [], - "rules": [ - { - "type": "temporary", - "reason": "ContainerCreationFailed", - "pattern": ".*failed to create containerd container.*error unpacking image.*wrong diff id calculated on extraction.*" - }, - { - "type": "temporary", - "reason": "CorruptContainerImageLayer", - "pattern": ".*failed to pull and unpack image.*failed to extract layer.*archive/tar: invalid tar header.*" - }, - { - "type": "temporary", - "reason": "HCSEmptyLayerchain", - "pattern": ".*Failed to unmarshall layerchain json - invalid character '\\x00' looking for beginning of value*" - } - ] + "plugin": "filelog", + "pluginConfig": { + "timestamp": "^time=\"(\\S*)\"", + "message": "msg=\"?([^\n]*)\"?", + "timestampFormat": "2006-01-02T15:04:05.999999999Z" + }, + "logPath": "C:\\etc\\kubernetes\\logs\\containerd.log", + "lookback": "5m", + "bufferSize": 10, + "source": "containerd", + "conditions": [], + "rules": [ + { + "type": "temporary", + "reason": "ContainerCreationFailed", + "pattern": ".*failed to create containerd container.*error unpacking image.*wrong diff id calculated on extraction.*" + }, + { + "type": "temporary", + "reason": "CorruptContainerImageLayer", + "pattern": ".*failed to pull and unpack image.*failed to extract layer.*archive/tar: invalid tar header.*" + }, + { + "type": "temporary", + "reason": "HCSEmptyLayerchain", + "pattern": ".*Failed to unmarshall layerchain json - invalid character '\\x00' looking for beginning of value*" + } + ] } diff --git a/config/windows-defender-monitor.json b/config/windows-defender-monitor.json index 97d49e27b..efbb2cd3c 100644 --- a/config/windows-defender-monitor.json +++ b/config/windows-defender-monitor.json @@ -1,21 +1,20 @@ { - "plugin": "custom", - "pluginConfig": { - "invoke_interval": "10m", - "timeout": "5s", - "max_output_length": 80, - "concurrency": 3 - }, - "source": "windows-defender-custom-plugin-monitor", - "metricsReporting": true, - "conditions": [], - "rules": [ - { - "type": "temporary", - "reason": "WindowsDefenderThreatsDetected", - "path": "C:\\etc\\kubernetes\\node-problem-detector\\config\\plugin\\windows_defender_problem.ps1", - "timeout": "3s" - } - ] - } - \ No newline at end of file + "plugin": "custom", + "pluginConfig": { + "invoke_interval": "10m", + "timeout": "5s", + "max_output_length": 80, + "concurrency": 3 + }, + "source": "windows-defender-custom-plugin-monitor", + "metricsReporting": true, + "conditions": [], + "rules": [ + { + "type": "temporary", + "reason": "WindowsDefenderThreatsDetected", + "path": "C:\\etc\\kubernetes\\node-problem-detector\\config\\plugin\\windows_defender_problem.ps1", + "timeout": "3s" + } + ] +} diff --git a/config/windows-health-checker-containerd.json b/config/windows-health-checker-containerd.json index 329e1a66e..6757e1225 100644 --- a/config/windows-health-checker-containerd.json +++ b/config/windows-health-checker-containerd.json @@ -1,34 +1,33 @@ { - "plugin": "custom", - "pluginConfig": { - "invoke_interval": "10s", - "timeout": "3m", - "max_output_length": 80, - "concurrency": 1 - }, - "source": "health-checker", - "metricsReporting": true, - "conditions": [ - { - "type": "ContainerRuntimeUnhealthy", - "reason": "ContainerRuntimeIsHealthy", - "message": "Container runtime on the node is functioning properly" - } - ], - "rules": [ - { - "type": "permanent", - "condition": "ContainerRuntimeUnhealthy", - "reason": "ContainerdUnhealthy", - "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", - "args": [ - "--component=cri", - "--enable-repair=true", - "--cooldown-time=2m", - "--health-check-timeout=60s" - ], - "timeout": "3m" - } - ] - } - \ No newline at end of file + "plugin": "custom", + "pluginConfig": { + "invoke_interval": "10s", + "timeout": "3m", + "max_output_length": 80, + "concurrency": 1 + }, + "source": "health-checker", + "metricsReporting": true, + "conditions": [ + { + "type": "ContainerRuntimeUnhealthy", + "reason": "ContainerRuntimeIsHealthy", + "message": "Container runtime on the node is functioning properly" + } + ], + "rules": [ + { + "type": "permanent", + "condition": "ContainerRuntimeUnhealthy", + "reason": "ContainerdUnhealthy", + "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", + "args": [ + "--component=cri", + "--enable-repair=true", + "--cooldown-time=2m", + "--health-check-timeout=60s" + ], + "timeout": "3m" + } + ] +} diff --git a/config/windows-health-checker-docker.json b/config/windows-health-checker-docker.json index a41054a81..52859309f 100644 --- a/config/windows-health-checker-docker.json +++ b/config/windows-health-checker-docker.json @@ -1,34 +1,33 @@ { - "plugin": "custom", - "pluginConfig": { - "invoke_interval": "10s", - "timeout": "3m", - "max_output_length": 80, - "concurrency": 1 - }, - "source": "health-checker", - "metricsReporting": true, - "conditions": [ - { - "type": "ContainerRuntimeUnhealthy", - "reason": "ContainerRuntimeIsHealthy", - "message": "Container runtime on the node is functioning properly" - } - ], - "rules": [ - { - "type": "permanent", - "condition": "ContainerRuntimeUnhealthy", - "reason": "DockerUnhealthy", - "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", - "args": [ - "--component=docker", - "--enable-repair=true", - "--cooldown-time=2m", - "--health-check-timeout=60s" - ], - "timeout": "3m" - } - ] - } - \ No newline at end of file + "plugin": "custom", + "pluginConfig": { + "invoke_interval": "10s", + "timeout": "3m", + "max_output_length": 80, + "concurrency": 1 + }, + "source": "health-checker", + "metricsReporting": true, + "conditions": [ + { + "type": "ContainerRuntimeUnhealthy", + "reason": "ContainerRuntimeIsHealthy", + "message": "Container runtime on the node is functioning properly" + } + ], + "rules": [ + { + "type": "permanent", + "condition": "ContainerRuntimeUnhealthy", + "reason": "DockerUnhealthy", + "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", + "args": [ + "--component=docker", + "--enable-repair=true", + "--cooldown-time=2m", + "--health-check-timeout=60s" + ], + "timeout": "3m" + } + ] +} diff --git a/config/windows-health-checker-kubelet.json b/config/windows-health-checker-kubelet.json index 37ee5ba70..3388defd5 100644 --- a/config/windows-health-checker-kubelet.json +++ b/config/windows-health-checker-kubelet.json @@ -1,34 +1,33 @@ { - "plugin": "custom", - "pluginConfig": { - "invoke_interval": "10s", - "timeout": "3m", - "max_output_length": 80, - "concurrency": 1 - }, - "source": "health-checker", - "metricsReporting": true, - "conditions": [ - { - "type": "KubeletUnhealthy", - "reason": "KubeletIsHealthy", - "message": "kubelet on the node is functioning properly" - } - ], - "rules": [ - { - "type": "permanent", - "condition": "KubeletUnhealthy", - "reason": "KubeletUnhealthy", - "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", - "args": [ - "--component=kubelet", - "--enable-repair=true", - "--cooldown-time=1m", - "--health-check-timeout=10s" - ], - "timeout": "3m" - } - ] - } - \ No newline at end of file + "plugin": "custom", + "pluginConfig": { + "invoke_interval": "10s", + "timeout": "3m", + "max_output_length": 80, + "concurrency": 1 + }, + "source": "health-checker", + "metricsReporting": true, + "conditions": [ + { + "type": "KubeletUnhealthy", + "reason": "KubeletIsHealthy", + "message": "kubelet on the node is functioning properly" + } + ], + "rules": [ + { + "type": "permanent", + "condition": "KubeletUnhealthy", + "reason": "KubeletUnhealthy", + "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", + "args": [ + "--component=kubelet", + "--enable-repair=true", + "--cooldown-time=1m", + "--health-check-timeout=10s" + ], + "timeout": "3m" + } + ] +} diff --git a/config/windows-health-checker-kubeproxy.json b/config/windows-health-checker-kubeproxy.json index 54e2793bf..e35109992 100644 --- a/config/windows-health-checker-kubeproxy.json +++ b/config/windows-health-checker-kubeproxy.json @@ -1,34 +1,33 @@ { - "plugin": "custom", - "pluginConfig": { - "invoke_interval": "10s", - "timeout": "3m", - "max_output_length": 80, - "concurrency": 1 - }, - "source": "health-checker", - "metricsReporting": true, - "conditions": [ - { - "type": "KubeProxyUnhealthy", - "reason": "KubeProxyIsHealthy", - "message": "kube-proxy on the node is functioning properly" - } - ], - "rules": [ - { - "type": "permanent", - "condition": "KubeProxyUnhealthy", - "reason": "KubeProxyUnhealthy", - "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", - "args": [ - "--component=kube-proxy", - "--enable-repair=true", - "--cooldown-time=1m", - "--health-check-timeout=10s" - ], - "timeout": "3m" - } - ] - } - \ No newline at end of file + "plugin": "custom", + "pluginConfig": { + "invoke_interval": "10s", + "timeout": "3m", + "max_output_length": 80, + "concurrency": 1 + }, + "source": "health-checker", + "metricsReporting": true, + "conditions": [ + { + "type": "KubeProxyUnhealthy", + "reason": "KubeProxyIsHealthy", + "message": "kube-proxy on the node is functioning properly" + } + ], + "rules": [ + { + "type": "permanent", + "condition": "KubeProxyUnhealthy", + "reason": "KubeProxyUnhealthy", + "path": "C:\\etc\\kubernetes\\node\\bin\\health-checker.exe", + "args": [ + "--component=kube-proxy", + "--enable-repair=true", + "--cooldown-time=1m", + "--health-check-timeout=10s" + ], + "timeout": "3m" + } + ] +} diff --git a/pkg/systemlogmonitor/config_json_test.go b/pkg/systemlogmonitor/config_json_test.go new file mode 100644 index 000000000..e0bccf86d --- /dev/null +++ b/pkg/systemlogmonitor/config_json_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2026 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package systemlogmonitor + +import ( + "bytes" + "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +// canonicalJSON reformats src into the canonical format for shipped configs: 2-space indent and a +// trailing newline. json.Indent only normalizes whitespace, so key order and values are preserved. +func canonicalJSON(src []byte) ([]byte, error) { + var buf bytes.Buffer + if err := json.Indent(&buf, bytes.TrimSpace(src), "", " "); err != nil { + return nil, err + } + buf.WriteByte('\n') + return buf.Bytes(), nil +} + +// TestShippedConfigs verifies that every JSON file shipped in the config/ directory parses with +// encoding/json, the same way the monitors load them at startup, and that it is written in the +// canonical format. The parse check catches trailing commas, UTF-8 BOMs and other syntax errors +// that would make NPD fail to start with the config. The format check keeps diffs in PRs minimal. +// Run `make fmt-configs` to rewrite nonconforming files in the canonical format. +func TestShippedConfigs(t *testing.T) { + configs, err := filepath.Glob(filepath.Join("..", "..", "config", "*.json")) + if err != nil { + t.Fatalf("failed to glob config files: %v", err) + } + if len(configs) == 0 { + t.Fatal("no config files found in config/ directory") + } + for _, config := range configs { + t.Run(filepath.Base(config), func(t *testing.T) { + data, err := os.ReadFile(config) + if err != nil { + t.Fatalf("failed to read %q: %v", config, err) + } + var parsed interface{} + if err := json.Unmarshal(data, &parsed); err != nil { + t.Fatalf("failed to parse %q: %v", config, err) + } + canonical, err := canonicalJSON(data) + if err != nil { + t.Fatalf("failed to reformat %q: %v", config, err) + } + if bytes.Equal(data, canonical) { + return + } + if os.Getenv("UPDATE_EXPECTED") != "" { + if err := os.WriteFile(config, canonical, 0644); err != nil { + t.Fatalf("failed to rewrite %q: %v", config, err) + } + t.Logf("rewrote %q in the canonical format", config) + return + } + assert.Equal(t, string(canonical), string(data), + "%q is not in the canonical format (2-space indent, trailing newline); "+ + "run `make fmt-configs` to rewrite it", + config) + }) + } +}