parent
55fc47f627
commit
8d55618ef9
42
ansible/deploy-config.yml
Normal file
42
ansible/deploy-config.yml
Normal 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
|
||||||
@ -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 }}"
|
||||||
@ -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
|
||||||
delegate_to: localhost
|
drifted_items: []
|
||||||
register: local_file
|
synced_items: []
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
# TASK 2: Read file from server
|
# TASK 2: Check each configured file for drift
|
||||||
# Attempts to read dvir.txt from /tmp on the target server
|
# Compares local (repo) file with server file (content and existence)
|
||||||
# Failure is allowed here (we'll handle it in next task)
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
- name: Read server file
|
- name: Check file drift for each configured file
|
||||||
|
block:
|
||||||
|
# Read local file from repo
|
||||||
|
- name: Read local file ({{ item.name }})
|
||||||
slurp:
|
slurp:
|
||||||
src: /tmp/dvir.txt
|
src: "{{ playbook_dir }}/{{ '../../' + item.src }}"
|
||||||
register: server_file
|
delegate_to: localhost
|
||||||
|
register: local_file_content
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# Try to read file from server
|
||||||
# TASK 3: Compare file contents (if server file exists)
|
- name: Read server file ({{ item.name }})
|
||||||
# Decodes base64 and compares content between repo and server
|
slurp:
|
||||||
# Sets drift_detected to true if content differs
|
src: "{{ item.dest }}"
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
register: server_file_content
|
||||||
- name: Compare file contents
|
failed_when: false
|
||||||
set_fact:
|
|
||||||
drift_detected: "{{ (local_file.content | b64decode) != (server_file.content | b64decode) }}"
|
|
||||||
when: server_file.rc == 0
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# Compare contents and detect drift
|
||||||
# TASK 4: Mark as drift if server file is missing
|
- name: Analyze drift for {{ item.name }}
|
||||||
# If the server file doesn't exist, it's also considered drift
|
set_fact:
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
file_drift_status: "{{ {} }}"
|
||||||
- name: Mark as drift if server file missing
|
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:
|
set_fact:
|
||||||
drift_detected: true
|
drift_detected: true
|
||||||
when: server_file.rc != 0
|
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 5: Output SYNCED status
|
# TASK 3: Generate JSON report with drift details
|
||||||
# Displayed when file on server matches repo file exactly
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
|
- 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
|
- 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
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user