From 8d55618ef955c5b2dc839551c8ee320b5ce64a8f Mon Sep 17 00:00:00 2001 From: dvirlabs <114520947+dvirlabs@users.noreply.github.com> Date: Tue, 9 Jun 2026 17:38:33 +0300 Subject: [PATCH] test --- ansible/deploy-config.yml | 42 ++++++++ ansible/playbooks/apply.yml | 69 +++++++++++-- ansible/playbooks/drift-check.yml | 160 +++++++++++++++++++++--------- 3 files changed, 212 insertions(+), 59 deletions(-) create mode 100644 ansible/deploy-config.yml diff --git a/ansible/deploy-config.yml b/ansible/deploy-config.yml new file mode 100644 index 0000000..5404158 --- /dev/null +++ b/ansible/deploy-config.yml @@ -0,0 +1,42 @@ +--- +# ============================================================================= +# Deploy Configuration +# Purpose: Centralized list of files and folders to deploy to target servers +# Usage: Referenced by apply.yml and drift-check.yml playbooks +# ============================================================================= + +# List of files to deploy +# Each item specifies: +# - src: source path (relative to repo root) +# - dest: destination path on target servers +# - owner: file owner (default: root) +# - group: file group (default: root) +# - mode: file permissions (default: 0644) +# - recursive: if True, use recursive copy for directories (optional) +# ============================================================================= + +deploy_items: + - name: "dvir.txt" + src: "files/dvir.txt" + dest: "/tmp/dvir.txt" + owner: root + group: root + mode: "0644" + description: "Main configuration file" + + # Example: add more files below + # - name: "example.conf" + # src: "files/example.conf" + # dest: "/etc/example/example.conf" + # owner: root + # group: root + # mode: "0644" + # + # Example: recursive folder deployment + # - name: "config_folder" + # src: "files/config/" + # dest: "/etc/myapp/config/" + # owner: root + # group: root + # mode: "0755" + # recursive: true diff --git a/ansible/playbooks/apply.yml b/ansible/playbooks/apply.yml index a2e6a63..1d5b92f 100644 --- a/ansible/playbooks/apply.yml +++ b/ansible/playbooks/apply.yml @@ -1,31 +1,78 @@ --- # ============================================================================= # APPLY PLAYBOOK -# Purpose: Deploy dvir.txt file to target servers at /tmp/dvir.txt +# Purpose: Deploy files from deploy-config.yml to target servers # Usage: ansible-playbook apply.yml +# Note: Uses Ansible's register mechanism to capture deployed files # ============================================================================= -- name: Deploy file to servers +- name: Deploy files to servers hosts: all become: true + vars_files: + - ../deploy-config.yml tasks: # ───────────────────────────────────────────────────────────────────── - # TASK 1: Copy file to destination - # Copies the dvir.txt from the repo to /tmp/dvir.txt on target servers + # TASK 1: Deploy each configured file/folder + # Loops through deploy_items and copies each to destination + # Registers which files were successfully deployed # ───────────────────────────────────────────────────────────────────── - - name: Copy file to destination + - name: Deploy configured files copy: - src: ../../files/dvir.txt - dest: /tmp/dvir.txt + src: "{{ playbook_dir }}/{{ '../../' + item.src }}" + dest: "{{ item.dest }}" + owner: "{{ item.owner | default('root') }}" + group: "{{ item.group | default('root') }}" + mode: "{{ item.mode | default('0644') }}" + backup: yes + register: deploy_results + loop: "{{ deploy_items }}" + loop_control: + loop_var: item + label: "{{ item.name }}" + + # ───────────────────────────────────────────────────────────────────── + # TASK 2: Extract deployed file information + # Builds a list of deployed files from the copy task results + # ───────────────────────────────────────────────────────────────────── + - name: Extract deployed file information + set_fact: + deployed_file_list: | + [ + {%- for result in deploy_results.results -%} + { + "name": "{{ result.item.name }}", + "src": "{{ result.item.src }}", + "dest": "{{ result.item.dest }}", + "changed": {{ result.changed | lower }} + }{{ "," if not loop.last else "" }} + {%- endfor -%} + ] + + # ───────────────────────────────────────────────────────────────────── + # TASK 3: Save deployed files list to a temporary file + # This file will be read by the GitOps status script + # ───────────────────────────────────────────────────────────────────── + - name: Save deployed files list + copy: + content: "{{ deployed_file_list }}" + dest: "/tmp/deployed_files_{{ inventory_hostname }}.json" owner: root group: root mode: "0644" # ───────────────────────────────────────────────────────────────────── - # TASK 2: Confirm deployment success - # Displays success message with the hostname for verification + # TASK 4: Confirm deployment success + # Displays summary of deployed files # ───────────────────────────────────────────────────────────────────── - - name: Confirm deployment + - name: Display deployment summary debug: - msg: "✅ File deployed successfully to /tmp/dvir.txt on {{ inventory_hostname }}" \ No newline at end of file + msg: "✅ Deployed {{ deploy_results.results | length }} file(s) to {{ inventory_hostname }}" + + - name: Display deployed files + debug: + msg: " - {{ item.item.name }} → {{ item.item.dest }} ({{ 'changed' if item.changed else 'unchanged' }})" + loop: "{{ deploy_results.results }}" + loop_control: + label: "{{ item.item.name }}" \ No newline at end of file diff --git a/ansible/playbooks/drift-check.yml b/ansible/playbooks/drift-check.yml index a9d805b..ef35e74 100644 --- a/ansible/playbooks/drift-check.yml +++ b/ansible/playbooks/drift-check.yml @@ -1,76 +1,140 @@ --- # ============================================================================= # DRIFT-CHECK PLAYBOOK -# Purpose: Compare file on repo vs server to detect if they're in sync +# Purpose: Check file drift and output detailed file-level JSON report # Usage: ansible-playbook drift-check.yml -# Output: SYNCED or OUT_OF_SYNC status +# 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: Read local file from repo - # Reads dvir.txt from the local repository using base64 encoding + # TASK 1: Initialize drift tracking variables # ───────────────────────────────────────────────────────────────────── - - name: Read local file - slurp: - src: "{{ playbook_dir }}/../../files/dvir.txt" + - 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 - register: local_file # ───────────────────────────────────────────────────────────────────── - # TASK 2: Read file from server - # Attempts to read dvir.txt from /tmp on the target server - # Failure is allowed here (we'll handle it in next task) - # ───────────────────────────────────────────────────────────────────── - - name: Read server file - slurp: - src: /tmp/dvir.txt - register: server_file - failed_when: false - - # ───────────────────────────────────────────────────────────────────── - # TASK 3: Compare file contents (if server file exists) - # Decodes base64 and compares content between repo and server - # Sets drift_detected to true if content differs - # ───────────────────────────────────────────────────────────────────── - - name: Compare file contents - set_fact: - drift_detected: "{{ (local_file.content | b64decode) != (server_file.content | b64decode) }}" - when: server_file.rc == 0 - - # ───────────────────────────────────────────────────────────────────── - # TASK 4: Mark as drift if server file is missing - # If the server file doesn't exist, it's also considered drift - # ───────────────────────────────────────────────────────────────────── - - name: Mark as drift if server file missing - set_fact: - drift_detected: true - when: server_file.rc != 0 - - # ───────────────────────────────────────────────────────────────────── - # TASK 5: Output SYNCED status - # Displayed when file on server matches repo file exactly + # TASK 5: Output status summary # ───────────────────────────────────────────────────────────────────── - name: Output SYNCED status debug: - msg: "✓ dvir.txt is synced" + msg: | + ✓ All files are in sync + Synced files: {{ synced_items | length }} when: not drift_detected - # ───────────────────────────────────────────────────────────────────── - # TASK 6: Output OUT_OF_SYNC status - # Displayed when file on server differs from repo or is missing - # ───────────────────────────────────────────────────────────────────── - - name: Output OUT_OF_SYNC status + - name: Output OUT_OF_SYNC status with details debug: - msg: "✗ dvir.txt is out of sync" + 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." + msg: "Configuration drift detected. {{ drifted_items | length }} file(s) out of sync." when: drift_detected