--- # ============================================================================= # DRIFT-CHECK PLAYBOOK # Purpose: Check file drift and output detailed file-level JSON report # Usage: ansible-playbook drift-check.yml # Output: Structured JSON with sync status and drifted files info # Registers: drift_detected, drifted_files_json for consumption by update script # ============================================================================= - name: Check file drift hosts: all gather_facts: false vars_files: - ../deploy-config.yml tasks: # ───────────────────────────────────────────────────────────────────── # TASK 1: Initialize drift tracking variables # ───────────────────────────────────────────────────────────────────── - name: Initialize drift tracking set_fact: drift_detected: false drifted_items: [] synced_items: [] # ───────────────────────────────────────────────────────────────────── # TASK 2: Check each configured file for drift # Compares local (repo) file with server file (content and existence) # ───────────────────────────────────────────────────────────────────── - name: Check file drift for each configured file block: # Read local file from repo - name: Read local file ({{ item.name }}) slurp: src: "{{ playbook_dir }}/{{ '../../' + item.src }}" delegate_to: localhost register: local_file_content failed_when: false # Try to read file from server - name: Read server file ({{ item.name }}) slurp: src: "{{ item.dest }}" register: server_file_content failed_when: false # Compare contents and detect drift - name: Analyze drift for {{ item.name }} set_fact: file_drift_status: "{{ {} }}" file_has_drift: false - name: Check if server file is missing ({{ item.name }}) set_fact: file_has_drift: true file_drift_status: | { "name": "{{ item.name }}", "destination": "{{ item.dest }}", "status": "MISSING", "reason": "File not found on server" } when: server_file_content.rc != 0 - name: Check if file content differs ({{ item.name }}) set_fact: file_has_drift: true file_drift_status: | { "name": "{{ item.name }}", "destination": "{{ item.dest }}", "status": "CONTENT_DIFFERS", "reason": "File content differs from repository" } when: - server_file_content.rc == 0 - local_file_content.content | b64decode != server_file_content.content | b64decode # Track drifted and synced files - name: Track drifted file ({{ item.name }}) set_fact: drift_detected: true drifted_items: "{{ drifted_items + [file_drift_status | from_json] }}" when: file_has_drift - name: Track synced file ({{ item.name }}) set_fact: synced_items: "{{ synced_items + [{'name': item.name, 'destination': item.dest, 'status': 'SYNCED'}] }}" when: not file_has_drift loop: "{{ deploy_items }}" loop_control: loop_var: item label: "{{ item.name }}" # ───────────────────────────────────────────────────────────────────── # TASK 3: Generate JSON report with drift details # ───────────────────────────────────────────────────────────────────── - name: Generate drift detection JSON report set_fact: drifted_files_json: "{{ drifted_items | to_nice_json }}" # ───────────────────────────────────────────────────────────────────── # TASK 4: Save drift report to file for script consumption # ───────────────────────────────────────────────────────────────────── - name: Save drift report to file copy: content: "{{ drifted_files_json }}" dest: "/tmp/drifted_files_{{ inventory_hostname }}.json" owner: root group: root mode: "0644" delegate_to: localhost # ───────────────────────────────────────────────────────────────────── # TASK 5: Output status summary # ───────────────────────────────────────────────────────────────────── - name: Output SYNCED status debug: msg: | ✓ All files are in sync Synced files: {{ synced_items | length }} when: not drift_detected - name: Output OUT_OF_SYNC status with details debug: msg: | ✗ Configuration drift detected! Drifted files: {{ drifted_items | length }} Details: {{ drifted_files_json }} when: drift_detected # ───────────────────────────────────────────────────────────────────── # TASK 6: Fail if drift detected (for CI/CD pipeline) # ───────────────────────────────────────────────────────────────────── - name: Fail if drift detected fail: msg: "Configuration drift detected. {{ drifted_items | length }} file(s) out of sync." when: drift_detected