#!/bin/bash # ============================================================================= # GitOps Status Update Script # 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 # Environment variables: # - GITOPS_STATUS_SERVER_URL: API endpoint URL # - REPO_NAME: Repository name # - SERVER_NAME: Server name # - MODE: post-deploy or cron (optional, for logging) # - ANSIBLE_CONFIG: Path to ansible.cfg # ============================================================================= set -e # Get configuration from environment variables API_URL="${GITOPS_STATUS_SERVER_URL}/api/status" REPO_NAME="${REPO_NAME:-unknown}" SERVER_NAME="${SERVER_NAME:-unknown}" MODE="${MODE:-check}" 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 " API URL: $API_URL" echo " Mode: $MODE" # Verify required environment variables if [[ -z "$GITOPS_STATUS_SERVER_URL" || -z "$REPO_NAME" || -z "$SERVER_NAME" ]]; then echo "ERROR: Missing required environment variables (GITOPS_STATUS_SERVER_URL, REPO_NAME, SERVER_NAME)" exit 1 fi # Verify files exist if [[ ! -f "$INVENTORY" ]]; then 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" DRIFT_COUNT=0 DEPLOYED_FILES="[]" DRIFTED_FILES="[]" # ───────────────────────────────────────────────────────────────────────── # 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 \ "$PLAYBOOK_DIR/drift-check.yml" \ > "$ANSIBLE_OUTPUT" 2>&1; then SYNC_STATUS="SYNCED" DRIFT_COUNT=0 DRIFTED_FILES="[]" echo " ✓ All servers are SYNCED with Git" else # Drift detected DRIFT_CHECK_SUCCESS=false SYNC_STATUS="OUT_OF_SYNC" echo " ✗ Configuration drift detected on one or more servers" fi # ───────────────────────────────────────────────────────────────────────── # Extract drift information from JSON output files # The drift-check.yml playbook creates /tmp/drifted_files_.json # ───────────────────────────────────────────────────────────────────────── echo "==> Extracting drift information from playbook output..." TEMP_DRIFTED_FILES=$(mktemp) echo "[]" > "$TEMP_DRIFTED_FILES" # Collect drifted files from all servers for drift_file in /tmp/drifted_files_*.json; do 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 DRIFTED_FILES="[]" fi fi # ───────────────────────────────────────────────────────────────────────── # Get current timestamp in ISO 8601 format # ───────────────────────────────────────────────────────────────────────── TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # ───────────────────────────────────────────────────────────────────────── # Build comprehensive JSON payload # ───────────────────────────────────────────────────────────────────────── JSON_PAYLOAD=$(cat < Sending status update to API..." echo "$JSON_PAYLOAD" | jq . # ───────────────────────────────────────────────────────────────────────── # Send to API using curl # ───────────────────────────────────────────────────────────────────────── HTTP_CODE=$(curl -s -o /tmp/api_response.json -w "%{http_code}" \ -X POST "$API_URL" \ -H "Content-Type: application/json" \ -d "$JSON_PAYLOAD") if [[ "$HTTP_CODE" == "200" ]]; then echo " ✓ Status update sent successfully (HTTP $HTTP_CODE)" cat /tmp/api_response.json | jq . 2>/dev/null || cat /tmp/api_response.json else echo " ✗ Failed to send status update (HTTP $HTTP_CODE)" cat /tmp/api_response.json 2>/dev/null || true fi # ───────────────────────────────────────────────────────────────────────── # 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