parent
8d55618ef9
commit
cf83072c38
@ -1,41 +1,49 @@
|
|||||||
---
|
---
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# VALIDATE PLAYBOOK
|
# VALIDATE PLAYBOOK
|
||||||
# Purpose: Verify that dvir.txt exists and is readable on target servers
|
# Purpose: Verify that all configured files exist and are readable on servers
|
||||||
# Usage: ansible-playbook validate.yml
|
# Usage: ansible-playbook validate.yml
|
||||||
# Output: Success if file exists and is readable, Failure if not
|
# Output: Success if all files exist and readable, Failure if any are missing
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
- name: Validate file exists
|
- name: Validate deployed files
|
||||||
hosts: all
|
hosts: all
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
|
vars_files:
|
||||||
|
- ../deploy-config.yml
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
# TASK 1: Check file status
|
# TASK 1: Check each configured file status
|
||||||
# Gathers file stats (exists, readable, permissions, etc.)
|
# Gathers file stats (exists, readable, permissions, etc.)
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
- name: Check if file is readable
|
- name: Check if file is readable ({{ item.name }})
|
||||||
stat:
|
stat:
|
||||||
path: /tmp/dvir.txt
|
path: "{{ item.dest }}"
|
||||||
register: file_stat
|
register: file_stats
|
||||||
|
loop: "{{ deploy_items }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: item
|
||||||
|
label: "{{ item.name }}"
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
# TASK 2: Assert file requirements
|
# TASK 2: Verify each file exists and is readable
|
||||||
# Verifies that the file exists and is readable
|
# Fails if any configured file is missing or not readable
|
||||||
# Fails the playbook if either condition is false
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
- name: Verify file exists and is readable
|
- name: Verify all files exist and are readable
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- file_stat.stat.exists
|
- item.stat.exists
|
||||||
- file_stat.stat.readable
|
- item.stat.readable
|
||||||
msg: "dvir.txt not found or not readable"
|
msg: "{{ item.item.name }} ({{ item.item.dest }}) is missing or not readable"
|
||||||
|
loop: "{{ file_stats.results }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.item.name }}"
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
# TASK 3: Display validation result
|
# TASK 3: Display validation result
|
||||||
# Shows success message if all checks passed
|
# Shows success message if all files passed validation
|
||||||
# ─────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────
|
||||||
- name: Display validation result
|
- name: Display validation result
|
||||||
debug:
|
debug:
|
||||||
msg: "✓ dvir.txt is valid and readable"
|
msg: "✓ All {{ deploy_items | length }} file(s) are valid and readable on {{ inventory_hostname }}"
|
||||||
|
|||||||
@ -2,6 +2,13 @@
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# GitOps Status Update Script
|
# GitOps Status Update Script
|
||||||
# Checks Ansible sync status and sends JSON update to gitops-status-server API
|
# Checks Ansible sync status and sends JSON update to gitops-status-server API
|
||||||
|
#
|
||||||
|
# This script:
|
||||||
|
# 1. Runs drift-check.yml to detect configuration drift
|
||||||
|
# 2. Extracts deployed files from deploy-config.yml
|
||||||
|
# 3. Reads structured JSON outputs from Ansible playbooks
|
||||||
|
# 4. Sends comprehensive status to gitops-status-server API
|
||||||
|
#
|
||||||
# Usage: ./update-gitops-status.sh
|
# Usage: ./update-gitops-status.sh
|
||||||
# Environment variables:
|
# Environment variables:
|
||||||
# - GITOPS_STATUS_SERVER_URL: API endpoint URL
|
# - GITOPS_STATUS_SERVER_URL: API endpoint URL
|
||||||
@ -19,6 +26,9 @@ REPO_NAME="${REPO_NAME:-unknown}"
|
|||||||
SERVER_NAME="${SERVER_NAME:-unknown}"
|
SERVER_NAME="${SERVER_NAME:-unknown}"
|
||||||
MODE="${MODE:-check}"
|
MODE="${MODE:-check}"
|
||||||
ANSIBLE_CONFIG="${ANSIBLE_CONFIG:-ansible.cfg}"
|
ANSIBLE_CONFIG="${ANSIBLE_CONFIG:-ansible.cfg}"
|
||||||
|
PLAYBOOK_DIR="ansible/playbooks"
|
||||||
|
INVENTORY="ansible/inventory/hosts.yml"
|
||||||
|
DEPLOY_CONFIG="ansible/deploy-config.yml"
|
||||||
|
|
||||||
echo "==> GitOps Status Update: $REPO_NAME / $SERVER_NAME"
|
echo "==> GitOps Status Update: $REPO_NAME / $SERVER_NAME"
|
||||||
echo " API URL: $API_URL"
|
echo " API URL: $API_URL"
|
||||||
@ -30,61 +40,110 @@ if [[ -z "$GITOPS_STATUS_SERVER_URL" || -z "$REPO_NAME" || -z "$SERVER_NAME" ]];
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run Ansible validation to check sync status
|
# Verify files exist
|
||||||
echo "==> Running Ansible sync check..."
|
if [[ ! -f "$INVENTORY" ]]; then
|
||||||
ANSIBLE_OUTPUT=$(mktemp)
|
echo "ERROR: Inventory file not found: $INVENTORY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$DEPLOY_CONFIG" ]]; then
|
||||||
|
echo "ERROR: Deploy config not found: $DEPLOY_CONFIG"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initialize variables
|
||||||
SYNC_STATUS="UNKNOWN"
|
SYNC_STATUS="UNKNOWN"
|
||||||
DRIFT_COUNT=0
|
DRIFT_COUNT=0
|
||||||
DEPLOYED_FILES="[]"
|
DEPLOYED_FILES="[]"
|
||||||
DRIFTED_FILES="[]"
|
DRIFTED_FILES="[]"
|
||||||
|
|
||||||
# Try to run the validate playbook and capture output
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
if ansible-playbook -i ansible/inventory/hosts.yml \
|
# Extract deployed files from deploy-config.yml
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
echo "==> Extracting deployed files from deploy-config.yml..."
|
||||||
|
DEPLOYED_FILES=$(grep -A1 "name:" "$DEPLOY_CONFIG" | grep "name:" | \
|
||||||
|
sed "s/.*name: \"\([^\"]*\)\".*/\1/" | \
|
||||||
|
jq -R -s 'split("\n") | map(select(length > 0) | {name: .})')
|
||||||
|
|
||||||
|
if [[ "$DEPLOYED_FILES" == "[]" ]] || [[ -z "$DEPLOYED_FILES" ]]; then
|
||||||
|
echo " WARNING: Could not extract deployed files, using empty array"
|
||||||
|
DEPLOYED_FILES="[]"
|
||||||
|
else
|
||||||
|
echo " ✓ Found deployed files: $(echo "$DEPLOYED_FILES" | jq '.[] | .name' | wc -l) file(s)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Run drift-check playbook to detect configuration drift
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
echo "==> Running drift-check playbook..."
|
||||||
|
ANSIBLE_OUTPUT=$(mktemp)
|
||||||
|
DRIFT_CHECK_SUCCESS=true
|
||||||
|
|
||||||
|
# Run drift-check and capture output
|
||||||
|
if ansible-playbook -i "$INVENTORY" \
|
||||||
-c local \
|
-c local \
|
||||||
ansible/playbooks/validate.yml \
|
"$PLAYBOOK_DIR/drift-check.yml" \
|
||||||
-vv > "$ANSIBLE_OUTPUT" 2>&1; then
|
> "$ANSIBLE_OUTPUT" 2>&1; then
|
||||||
|
|
||||||
SYNC_STATUS="SYNCED"
|
SYNC_STATUS="SYNCED"
|
||||||
DRIFT_COUNT=0
|
DRIFT_COUNT=0
|
||||||
echo " ✓ Server is SYNCED with Git"
|
DRIFTED_FILES="[]"
|
||||||
|
echo " ✓ All servers are SYNCED with Git"
|
||||||
else
|
else
|
||||||
# If playbook fails, it means there's drift/differences
|
# Drift detected
|
||||||
|
DRIFT_CHECK_SUCCESS=false
|
||||||
SYNC_STATUS="OUT_OF_SYNC"
|
SYNC_STATUS="OUT_OF_SYNC"
|
||||||
|
|
||||||
# Parse output to extract changed files
|
echo " ✗ Configuration drift detected on one or more servers"
|
||||||
# Look for "CHANGED" or "failed" tasks
|
fi
|
||||||
CHANGED_TASKS=$(grep -E "CHANGED|changed:|failed:" "$ANSIBLE_OUTPUT" | wc -l || true)
|
|
||||||
DRIFT_COUNT=$((CHANGED_TASKS > 0 ? CHANGED_TASKS : 1))
|
|
||||||
|
|
||||||
# Try to extract file information from Ansible output
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
# This is a best-effort attempt based on common Ansible patterns
|
# Extract drift information from JSON output files
|
||||||
CHANGED_FILES=$(grep -oE "path=([^ ]+)|src=([^ ]+)" "$ANSIBLE_OUTPUT" | cut -d= -f2 | sort -u | head -20)
|
# The drift-check.yml playbook creates /tmp/drifted_files_<hostname>.json
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
echo "==> Extracting drift information from playbook output..."
|
||||||
|
TEMP_DRIFTED_FILES=$(mktemp)
|
||||||
|
echo "[]" > "$TEMP_DRIFTED_FILES"
|
||||||
|
|
||||||
if [[ -n "$CHANGED_FILES" ]]; then
|
# Collect drifted files from all servers
|
||||||
# Format changed files as JSON array
|
for drift_file in /tmp/drifted_files_*.json; do
|
||||||
DRIFTED_FILES=$(echo "$CHANGED_FILES" | jq -R -s 'split("\n") | map(select(length > 0) | {name: .})')
|
if [[ -f "$drift_file" ]]; then
|
||||||
|
echo " Reading drift report: $drift_file"
|
||||||
|
cat "$drift_file" >> "$TEMP_DRIFTED_FILES"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If we have drift files, use them; otherwise try to extract from Ansible output
|
||||||
|
if [[ -f "$TEMP_DRIFTED_FILES" ]] && [[ -s "$TEMP_DRIFTED_FILES" ]] && [[ "$(cat "$TEMP_DRIFTED_FILES")" != "[]" ]]; then
|
||||||
|
# Merge all drifted files into a single array
|
||||||
|
DRIFTED_FILES=$(jq -s 'add' "$TEMP_DRIFTED_FILES" 2>/dev/null || echo "[]")
|
||||||
|
DRIFT_COUNT=$(echo "$DRIFTED_FILES" | jq '. | length')
|
||||||
|
echo " ✓ Found $DRIFT_COUNT drifted file(s)"
|
||||||
|
else
|
||||||
|
# Fallback: parse Ansible output for drift indicators
|
||||||
|
echo " Analyzing Ansible output for drift indicators..."
|
||||||
|
DRIFT_INDICATORS=$(grep -E "CHANGED|changed:|failed:|drifted|drift" "$ANSIBLE_OUTPUT" | wc -l || true)
|
||||||
|
|
||||||
|
if [[ $DRIFT_INDICATORS -gt 0 ]]; then
|
||||||
|
DRIFT_COUNT=$DRIFT_INDICATORS
|
||||||
|
# Build minimal drift entries from grep results
|
||||||
|
DRIFTED_FILES=$(grep -E "CHANGED|changed:|failed:" "$ANSIBLE_OUTPUT" | \
|
||||||
|
head -10 | \
|
||||||
|
jq -R -s 'split("\n") | map(select(length > 0) | {name: ., status: "UNKNOWN", reason: "Detected from Ansible output"})' || echo "[]")
|
||||||
|
echo " Found $DRIFT_COUNT drift indicator(s)"
|
||||||
else
|
else
|
||||||
DRIFTED_FILES="[]"
|
DRIFTED_FILES="[]"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo " ✗ Server is OUT_OF_SYNC with Git (drift count: $DRIFT_COUNT)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get list of all managed files (best effort)
|
|
||||||
if [[ -f "ansible/playbooks/apply.yml" ]]; then
|
|
||||||
# Extract file paths from the apply playbook
|
|
||||||
MANAGED_FILES=$(grep -E "src:|path:|name:" ansible/playbooks/apply.yml | \
|
|
||||||
grep -oE "'[^']+'" | tr -d "'" | sort -u | head -50)
|
|
||||||
|
|
||||||
if [[ -n "$MANAGED_FILES" ]]; then
|
|
||||||
DEPLOYED_FILES=$(echo "$MANAGED_FILES" | jq -R -s 'split("\n") | map(select(length > 0) | {name: .})')
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
# Get current timestamp in ISO 8601 format
|
# Get current timestamp in ISO 8601 format
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
# Build JSON payload
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# Build comprehensive JSON payload
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
JSON_PAYLOAD=$(cat <<EOF
|
JSON_PAYLOAD=$(cat <<EOF
|
||||||
{
|
{
|
||||||
"repo": "$REPO_NAME",
|
"repo": "$REPO_NAME",
|
||||||
@ -98,10 +157,13 @@ JSON_PAYLOAD=$(cat <<EOF
|
|||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
echo ""
|
||||||
echo "==> Sending status update to API..."
|
echo "==> Sending status update to API..."
|
||||||
echo "$JSON_PAYLOAD" | jq .
|
echo "$JSON_PAYLOAD" | jq .
|
||||||
|
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
# Send to API using curl
|
# Send to API using curl
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
HTTP_CODE=$(curl -s -o /tmp/api_response.json -w "%{http_code}" \
|
HTTP_CODE=$(curl -s -o /tmp/api_response.json -w "%{http_code}" \
|
||||||
-X POST "$API_URL" \
|
-X POST "$API_URL" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@ -109,13 +171,18 @@ HTTP_CODE=$(curl -s -o /tmp/api_response.json -w "%{http_code}" \
|
|||||||
|
|
||||||
if [[ "$HTTP_CODE" == "200" ]]; then
|
if [[ "$HTTP_CODE" == "200" ]]; then
|
||||||
echo " ✓ Status update sent successfully (HTTP $HTTP_CODE)"
|
echo " ✓ Status update sent successfully (HTTP $HTTP_CODE)"
|
||||||
cat /tmp/api_response.json | jq .
|
cat /tmp/api_response.json | jq . 2>/dev/null || cat /tmp/api_response.json
|
||||||
else
|
else
|
||||||
echo " ✗ Failed to send status update (HTTP $HTTP_CODE)"
|
echo " ✗ Failed to send status update (HTTP $HTTP_CODE)"
|
||||||
cat /tmp/api_response.json
|
cat /tmp/api_response.json 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cleanup
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
rm -f "$ANSIBLE_OUTPUT" /tmp/api_response.json
|
# Cleanup temporary files
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
rm -f "$ANSIBLE_OUTPUT" /tmp/api_response.json "$TEMP_DRIFTED_FILES"
|
||||||
|
|
||||||
|
# Exit with success regardless of sync status
|
||||||
|
# (The script's job is to report status, not to fail on drift)
|
||||||
|
echo "==> GitOps status update complete"
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user