fix: Use checksum-based content comparison to avoid permission-based drift false positives
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

CRITICAL FIX:

Problem: drift-check.yml was using 'copy' module in check_mode, which compares:
  - File content ✓
  - Permissions (owner, group, mode) ✗
  - Ownership ✗

After deploy, files have root:root 0644 permissions. Even though content matches,
the copy module marked files as 'changed' because permissions were being compared.
This caused false OUT_OF_SYNC reports even when configuration was actually synced.

Solution: Use MD5 checksum-based comparison instead:
  - Compare only file CONTENT using stat checksums
  - Ignore permissions/ownership differences
  - This is what matters for config management

Also fixed URLs:
  - Changed back from port 80 to port 5000 (API only)
  - Updated service name to gitops-status-api

Now drift detection only triggers on actual config changes, not permission differences.
After successful deploy, should correctly report SYNCED status.
This commit is contained in:
dvirlabs 2026-04-23 13:21:20 +03:00
parent 57870e65ce
commit 1cbe3d4de7
3 changed files with 61 additions and 27 deletions

View File

@ -94,7 +94,7 @@ steps:
ANSIBLE_CONFIG: ansible.cfg
SSH_PRIVATE_KEY:
from_secret: SSH_PRIVATE_KEY
GITOPS_STATUS_SERVER_URL: http://gitops-status-server.observability-stack.svc.cluster.local:80
GITOPS_STATUS_SERVER_URL: http://gitops-status-api.observability-stack.svc.cluster.local:5000
REPO_NAME: rsyslog
SERVER_NAME: rsyslog-lab
# Optimize Ansible for container environment
@ -145,7 +145,7 @@ steps:
ANSIBLE_CONFIG: ansible.cfg
SSH_PRIVATE_KEY:
from_secret: SSH_PRIVATE_KEY
GITOPS_STATUS_SERVER_URL: http://gitops-status-server.observability-stack.svc.cluster.local:80
GITOPS_STATUS_SERVER_URL: http://gitops-status-api.observability-stack.svc.cluster.local:5000
REPO_NAME: rsyslog
SERVER_NAME: rsyslog-lab
# Optimize Ansible for container environment

View File

@ -3,35 +3,69 @@
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.
# NOTE: This playbook compares file CONTENT ONLY using md5 checksums.
# It ignores permissions/ownership differences.
# Permissions are enforced during deploy (apply.yml)
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
# Checksum-based content comparison (ignores permissions/ownership)
# This is the only reliable way to detect actual config changes
# after deployment when permissions have been set.
# -------------------------------------------------------------------------
- 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: Get MD5 checksum of Git version of rsyslog.conf
stat:
path: "{{ playbook_dir }}/../../files/rsyslog.conf"
delegate_to: localhost
register: git_rsyslog_conf_stat
- 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: Get MD5 checksum of server version of rsyslog.conf
stat:
path: "{{ rsyslog_main_config }}"
register: server_rsyslog_conf_stat
- name: Compare rsyslog.conf content
set_fact:
main_config_check:
changed: "{{ git_rsyslog_conf_stat.stat.checksum != server_rsyslog_conf_stat.stat.checksum }}"
checksum_git: "{{ git_rsyslog_conf_stat.stat.checksum }}"
checksum_server: "{{ server_rsyslog_conf_stat.stat.checksum }}"
- name: Get checksums for rsyslog.d directory files
block:
- name: Find Git rsyslog.d files
find:
paths: "{{ playbook_dir }}/../../files/rsyslog.d"
patterns: "*.conf"
recurse: false
delegate_to: localhost
register: git_confd_files
- name: Find server rsyslog.d files
find:
paths: "{{ rsyslog_config_dir }}"
patterns: "*.conf"
recurse: false
register: server_confd_files
- name: Get checksums for all Git rsyslog.d files
stat:
path: "{{ item.path }}"
delegate_to: localhost
loop: "{{ git_confd_files.files }}"
register: git_confd_checksums
- name: Get checksums for all server rsyslog.d files
stat:
path: "{{ item.path }}"
loop: "{{ server_confd_files.files }}"
register: server_confd_checksums
- name: Compare rsyslog.d file checksums
set_fact:
rsyslogd_check:
changed: "{{ git_confd_checksums.results | map(attribute='stat.checksum') | list != server_confd_checksums.results | map(attribute='stat.checksum') | list }}"
- name: Check for extra files on server not present in Git
block:

View File

@ -44,7 +44,7 @@ set -euo pipefail
# ─────────────────────────────────────────────────────────────────────────────
# Configuration
# ─────────────────────────────────────────────────────────────────────────────
GITOPS_STATUS_SERVER_URL="${GITOPS_STATUS_SERVER_URL:-http://gitops-status-server.observability-stack.svc.cluster.local:80}"
GITOPS_STATUS_SERVER_URL="${GITOPS_STATUS_SERVER_URL:-http://gitops-status-api.observability-stack.svc.cluster.local:5000}"
REPO_NAME="${REPO_NAME:-rsyslog}"
SERVER_NAME="${SERVER_NAME:-rsyslog-lab}"
INVENTORY_FILE="ansible/inventory/hosts.yml"