test
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

This commit is contained in:
dvirlabs 2026-06-09 17:38:33 +03:00
parent 55fc47f627
commit 8d55618ef9
3 changed files with 212 additions and 59 deletions

42
ansible/deploy-config.yml Normal file
View File

@ -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

View File

@ -1,31 +1,78 @@
--- ---
# ============================================================================= # =============================================================================
# APPLY PLAYBOOK # 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 # 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 hosts: all
become: true become: true
vars_files:
- ../deploy-config.yml
tasks: tasks:
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
# TASK 1: Copy file to destination # TASK 1: Deploy each configured file/folder
# Copies the dvir.txt from the repo to /tmp/dvir.txt on target servers # 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: copy:
src: ../../files/dvir.txt src: "{{ playbook_dir }}/{{ '../../' + item.src }}"
dest: /tmp/dvir.txt 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 owner: root
group: root group: root
mode: "0644" mode: "0644"
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
# TASK 2: Confirm deployment success # TASK 4: Confirm deployment success
# Displays success message with the hostname for verification # Displays summary of deployed files
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
- name: Confirm deployment - name: Display deployment summary
debug: debug:
msg: "✅ File deployed successfully to /tmp/dvir.txt on {{ inventory_hostname }}" 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 }}"

View File

@ -1,76 +1,140 @@
--- ---
# ============================================================================= # =============================================================================
# DRIFT-CHECK PLAYBOOK # 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 # 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 - name: Check file drift
hosts: all hosts: all
gather_facts: false gather_facts: false
vars_files:
- ../deploy-config.yml
tasks: tasks:
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
# TASK 1: Read local file from repo # TASK 1: Initialize drift tracking variables
# Reads dvir.txt from the local repository using base64 encoding
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
- name: Read local file - name: Initialize drift tracking
slurp: set_fact:
src: "{{ playbook_dir }}/../../files/dvir.txt" 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 delegate_to: localhost
register: local_file
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
# TASK 2: Read file from server # TASK 5: Output status summary
# 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
# ───────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────
- name: Output SYNCED status - name: Output SYNCED status
debug: debug:
msg: "✓ dvir.txt is synced" msg: |
✓ All files are in sync
Synced files: {{ synced_items | length }}
when: not drift_detected when: not drift_detected
# ───────────────────────────────────────────────────────────────────── - name: Output OUT_OF_SYNC status with details
# TASK 6: Output OUT_OF_SYNC status
# Displayed when file on server differs from repo or is missing
# ─────────────────────────────────────────────────────────────────────
- name: Output OUT_OF_SYNC status
debug: debug:
msg: "✗ dvir.txt is out of sync" msg: |
✗ Configuration drift detected!
Drifted files: {{ drifted_items | length }}
Details: {{ drifted_files_json }}
when: drift_detected when: drift_detected
# ─────────────────────────────────────────────────────────────────────
# TASK 6: Fail if drift detected (for CI/CD pipeline)
# ─────────────────────────────────────────────────────────────────────
- name: Fail if drift detected - name: Fail if drift detected
fail: fail:
msg: "Configuration drift detected." msg: "Configuration drift detected. {{ drifted_items | length }} file(s) out of sync."
when: drift_detected when: drift_detected