Normalize list order before comparing alert config - fixes flip-flop update

Confirmed live: "CRITICAL: unrecognized critical-severity syslog" (the
only alert with a 2-element streams list) kept reporting "config changed"
every single run even with no actual edit, because a plain dict/list ==
comparison in Python is order-sensitive and Graylog doesn't necessarily
return the streams array in the same order it was submitted in. List
values are now sorted before comparing on both sides, since list order
was never semantically meaningful here. Verified locally against a
same-elements-different-order case (now matches) and a genuinely-changed
case (still correctly detected as different) before pushing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
byrsapty 2026-07-23 16:37:27 +03:00
parent 19643a74dd
commit 32f2a922e8

View file

@ -532,11 +532,22 @@ print(next((e['id'] for e in d['event_definitions'] if e['title'] == '$title'),
if [ -n "$id" ]; then
if python3 -c "
import json, sys
def normalize(v):
# List order isn't semantically meaningful here (e.g. 'streams' with
# two entries) but a plain dict/list == comparison is order-sensitive -
# confirmed live this caused a false 'changed' positive specifically
# for the one alert with a 2-element streams list, every single run.
if isinstance(v, list):
return sorted(v, key=str)
return v
existing = json.load(open('$existing_defs_file'))
current_full = next(e['config'] for e in existing['event_definitions'] if e['id'] == '$id')
desired = json.load(open('$body_file'))['config']
filtered_current = {k: current_full.get(k) for k in desired}
sys.exit(0 if filtered_current == desired else 1)
filtered_current = {k: normalize(current_full.get(k)) for k in desired}
desired_normalized = {k: normalize(v) for k, v in desired.items()}
sys.exit(0 if filtered_current == desired_normalized else 1)
"; then
skip "alert '$title' already up to date ($id)"
rm -f "$body_file"