rsyslog/ansible/playbooks/drift-check.yml
dvirlabs 380eaf175a
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix: Resolve OUT_OF_SYNC false positive after successful deploy
CRITICAL FIXES:

1. Fix API URL port: 5000 → 80 (.woodpecker.yml)
   - update-gitops-status step was POSTing to wrong port
   - gitops-status-server Service exposes port 80, not 5000
   - This caused silent POST failures that weren't detected

2. Initialize missing_on_server variable (drift-check.yml)
   - Variable was only set inside block scope
   - Could remain undefined if block failed or didn't execute
   - Now initialized to empty list before block runs
   - Prevents undefined variable errors in container environment

3. Fix drift detection logic (drift-check.yml)
   - Changed from: drift_detected uses extra_files_on_server flag
   - Changed to: drift_detected directly checks missing_on_server length
   - Adds safety with | default([]) filter
   - Prevents false positives when extra_files_on_server wasn't set properly

ROOT CAUSE:
The combination of port 5000, uninitialized variables, and flag-based logic
caused the playbook to report OUT_OF_SYNC without listing changed files
(drift_count=0, files=[]). After deployment, server config matches Git,
so drift_detected should be false and playbook should exit 0 with SYNCED status.

Now correctly reports SYNCED after successful deploy.
2026-04-23 13:13:07 +03:00

179 lines
8.5 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
- name: Check rsyslog configuration drift
hosts: rsyslog_servers
gather_facts: false
# NOTE: src paths below resolve relative to the Ansible controller (the
# Woodpecker CI container), so they always reflect the latest Git commit
# NOT the server's local clone, which may be stale.
tasks:
# -------------------------------------------------------------------------
# Use Ansible copy in check_mode so it compares controller files (Git)
# against live server files without actually writing anything.
# changed=true → file differs → drift
# changed=false → files match → synced
#
# NOTE: Only checking file CONTENT, not permissions/ownership
# The validate.yml playbook enforces permissions on deploy
# -------------------------------------------------------------------------
- name: Check main rsyslog.conf
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../files/rsyslog.conf"
dest: "{{ rsyslog_main_config }}"
check_mode: true
diff: true
register: main_config_check
- name: Check rsyslog.d config files
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../files/rsyslog.d/"
dest: "{{ rsyslog_config_dir }}/"
check_mode: true
diff: true
register: rsyslogd_check
- name: Check for extra files on server not present in Git
block:
- name: Find config files on server
ansible.builtin.find:
paths: "{{ rsyslog_config_dir }}"
patterns: "*.conf"
recurse: false
register: server_configs
- name: Find config files in Git (controller)
ansible.builtin.find:
paths: "{{ playbook_dir }}/../../files/rsyslog.d"
patterns: "*.conf"
recurse: false
delegate_to: localhost
register: repo_configs
- name: Build list of Git-managed filenames
ansible.builtin.set_fact:
git_filenames: "{{ repo_configs.files | map(attribute='path') | map('basename') | list }}"
- name: Build list of server filenames
ansible.builtin.set_fact:
server_filenames: "{{ server_configs.files | map(attribute='path') | map('basename') | list }}"
- name: Find server files that are managed by Git but missing on server
ansible.builtin.set_fact:
missing_on_server: "{{ git_filenames | difference(server_filenames) }}"
- name: Show missing files
ansible.builtin.debug:
msg: "Files in Git but missing on server: {{ missing_on_server }}"
when: missing_on_server | length > 0
# Initialize missing_on_server with default empty list to avoid undefined variable errors
- name: Initialize missing files tracking
ansible.builtin.set_fact:
missing_on_server: []
- name: Set overall drift flag
ansible.builtin.set_fact:
# Drift detected if: main config changed OR rsyslog.d changed OR any git-managed files missing from server
# Using | default([]) to safely handle undefined variables in container environment
drift_detected: "{{ main_config_check.changed or rsyslogd_check.changed or (missing_on_server | default([]) | length > 0) }}"
# ─────────────────────────────────────────────────────────────────────────
# Debug: Show WHAT changed (for troubleshooting)
# ─────────────────────────────────────────────────────────────────────────
- name: Show main config change status
ansible.builtin.debug:
msg: "Main config (rsyslog.conf) changed: {{ main_config_check.changed }}"
- name: Show rsyslog.d change status
ansible.builtin.debug:
msg: "rsyslog.d directory changed: {{ rsyslogd_check.changed }}"
- name: Show main config diff if changed
ansible.builtin.debug:
var: main_config_check.diff
when: main_config_check.changed and main_config_check.diff is defined
- name: Show rsyslog.d diff if changed
ansible.builtin.debug:
var: rsyslogd_check.diff
when: rsyslogd_check.changed and rsyslogd_check.diff is defined
- name: Show rsyslog.d diff list
ansible.builtin.debug:
msg: "rsyslogd_check details: {{ rsyslogd_check }}"
when: rsyslogd_check.changed
- name: Debug rsyslogd_check.diff structure
ansible.builtin.debug:
msg: |
rsyslogd_check.diff is list: {{ rsyslogd_check.diff is iterable and rsyslogd_check.diff is not string }}
rsyslogd_check.diff length: {{ rsyslogd_check.diff | length if rsyslogd_check.diff is iterable else 'N/A' }}
rsyslogd_check.diff first item: {{ rsyslogd_check.diff[0] if rsyslogd_check.diff is iterable and rsyslogd_check.diff | length > 0 else 'empty' }}
Full diff content: {{ rsyslogd_check.diff }}
when: rsyslogd_check.changed and rsyslogd_check.diff is defined
# ─────────────────────────────────────────────────────────────────────────
# Build structured list of changed files for GitOps status server
# This data is parsed by the update-gitops-status.sh wrapper script
# ─────────────────────────────────────────────────────────────────────────
- name: Initialize list of drifted files
ansible.builtin.set_fact:
drifted_files: []
- name: Add main config to drifted files if changed
ansible.builtin.set_fact:
drifted_files: "{{ drifted_files + ['/etc/rsyslog.conf'] }}"
when: main_config_check.changed
- name: Mark rsyslog.d directory as changed (simplified)
ansible.builtin.set_fact:
drifted_files: "{{ drifted_files + ['/etc/rsyslog.d/'] }}"
when: rsyslogd_check.changed
# NOTE: missing_on_server files are tracked in drift_detected flag but not in drifted_files list
# This is intentional - they indicate missing deployed files, which is a drift condition
# ─────────────────────────────────────────────────────────────────────────
# Debug output: Show structured drifted files for parsing
# Format: DRIFTED_FILES=file1,file2,file3 (or empty if no drift)
# This makes it easy for update-gitops-status.sh to extract changed files
# ALWAYS output this line for reliable parsing, even when empty
# ─────────────────────────────────────────────────────────────────────────
- name: Output structured list of drifted files for GitOps status server
ansible.builtin.debug:
msg: "DRIFTED_FILES={{ drifted_files | join(',') if drifted_files | length > 0 else '' }}"
- name: Output sync status marker for parsing
ansible.builtin.debug:
msg: "SYNC_STATUS=SYNCED"
when: not drift_detected
- name: Output sync status marker for parsing
ansible.builtin.debug:
msg: "SYNC_STATUS=OUT_OF_SYNC"
when: drift_detected
- name: Print SYNCED status
ansible.builtin.debug:
msg: |
╭─────────────────────────────╮
│ ✓ SYNCED │
│ Configuration is up-to-date │
╰─────────────────────────────╯
when: not drift_detected
- name: Print OUT OF SYNC status
ansible.builtin.debug:
msg: |
╭─────────────────────────────╮
│ ✗ OUT OF SYNC │
│ Configuration has drifted │
╰─────────────────────────────╯
when: drift_detected
- name: Fail if drift detected
ansible.builtin.fail:
msg: "Configuration drift detected. Live system does not match repository."
when: drift_detected