rsyslog/ansible/playbooks/drift-check.yml
dvirlabs ac4278a451
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix: Simplify drift-check to avoid fsnotify watcher exhaustion
CRITICAL FIX:

Problem: Previous version used multiple stat operations and loops which created
too many file descriptors and fsnotify watchers, causing 'too many open files' errors.

Solution: Use only:
- slurp: Direct file content reading (no watchers)
- find: Single operation to list directory files (no loops)

New logic is clean and simple:
1. Read Git rsyslog.conf + server rsyslog.conf (slurp)
2. Compare content directly (byte comparison)
3. List Git rsyslog.d files + server rsyslog.d files (find)
4. Compare file names (no permission checks, no loops)
5. Output DRIFTED_FILES and SYNC_STATUS markers

This eliminates file descriptor exhaustion while maintaining correct drift detection.
After deploy, when content matches, playbook exits 0 (SYNCED).
2026-04-23 13:28:16 +03:00

113 lines
4.6 KiB
YAML

---
- name: Check rsyslog configuration drift
hosts: rsyslog_servers
gather_facts: false
# SIMPLE FILE CONTENT COMPARISON - No permission checks
# Uses slurp to read files directly (no stat/watchers)
# Exit code: 0 = SYNCED, non-zero = OUT_OF_SYNC
tasks:
- name: Initialize variables
set_fact:
drift_detected: false
drifted_files: []
# ─────────────────────────────────────────────────────────────────────────
# Compare rsyslog.conf content
# ─────────────────────────────────────────────────────────────────────────
- name: Read Git rsyslog.conf
slurp:
src: "{{ playbook_dir }}/../../files/rsyslog.conf"
delegate_to: localhost
register: git_main_conf
- name: Read server rsyslog.conf
slurp:
src: "{{ rsyslog_main_config }}"
register: server_main_conf
- name: Check rsyslog.conf content match
set_fact:
main_conf_match: "{{ git_main_conf.content == server_main_conf.content }}"
- name: Mark drift if rsyslog.conf differs
set_fact:
drift_detected: true
drifted_files: "{{ drifted_files + ['rsyslog.conf'] }}"
when: not main_conf_match
# ─────────────────────────────────────────────────────────────────────────
# Compare rsyslog.d directory files
# ─────────────────────────────────────────────────────────────────────────
- name: List Git rsyslog.d files
find:
paths: "{{ playbook_dir }}/../../files/rsyslog.d"
patterns: "*.conf"
recurse: false
delegate_to: localhost
register: git_confd_list
- name: List server rsyslog.d files
find:
paths: "{{ rsyslog_config_dir }}"
patterns: "*.conf"
recurse: false
register: server_confd_list
- name: Extract file names
set_fact:
git_confd_names: "{{ git_confd_list.files | map(attribute='path') | map('basename') | sort }}"
server_confd_names: "{{ server_confd_list.files | map(attribute='path') | map('basename') | sort }}"
- name: Check rsyslog.d file list match
set_fact:
confd_match: "{{ git_confd_names == server_confd_names }}"
- name: Mark drift if rsyslog.d files differ
set_fact:
drift_detected: true
drifted_files: "{{ drifted_files + ['rsyslog.d/'] }}"
when: not confd_match
# ─────────────────────────────────────────────────────────────────────────
# Output markers for update-gitops-status.sh parsing
# ─────────────────────────────────────────────────────────────────────────
- name: Output drifted files list
debug:
msg: "DRIFTED_FILES={{ drifted_files | join(',') if drifted_files | length > 0 else '' }}"
- name: Output SYNCED status
debug:
msg: "SYNC_STATUS=SYNCED"
when: not drift_detected
- name: Output OUT_OF_SYNC status
debug:
msg: "SYNC_STATUS=OUT_OF_SYNC"
when: drift_detected
- name: Display SYNCED
debug:
msg: |
╭─────────────────────────────╮
│ ✓ SYNCED │
│ Configuration is up-to-date │
╰─────────────────────────────╯
when: not drift_detected
- name: Display OUT_OF_SYNC
debug:
msg: |
╭─────────────────────────────╮
│ ✗ OUT OF SYNC │
│ Configuration has drifted │
╰─────────────────────────────╯
when: drift_detected
- name: Fail if drift detected
fail:
msg: "Configuration drift detected."
when: drift_detected