diff --git a/.woodpecker.yml b/.woodpecker.yml index b977b82..89ff39e 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -97,6 +97,7 @@ steps: GITOPS_STATUS_SERVER_URL: http://gitops-status-server.observability-stack.svc.cluster.local:5000 REPO_NAME: rsyslog SERVER_NAME: rsyslog-lab + MODE: post-deploy # Optimize Ansible for container environment ANSIBLE_HOST_KEY_CHECKING: "False" ANSIBLE_FORCE_COLOR: "False" @@ -108,8 +109,8 @@ steps: # Increase file descriptor limit for Ansible (max safe value) ulimit -n 65536 - # Install dependencies: curl for HTTP requests, jq for JSON formatting - apk add --no-cache curl jq > /dev/null 2>&1 + # Install dependencies: git for detecting deployed files, curl for HTTP requests, jq for JSON formatting + apk add --no-cache git curl jq > /dev/null 2>&1 # Setup SSH key for Ansible mkdir -p ~/.ssh diff --git a/update-gitops-status.sh b/update-gitops-status.sh index 636472d..6d8d0a7 100644 --- a/update-gitops-status.sh +++ b/update-gitops-status.sh @@ -49,128 +49,165 @@ REPO_NAME="${REPO_NAME:-rsyslog}" SERVER_NAME="${SERVER_NAME:-rsyslog-lab}" INVENTORY_FILE="ansible/inventory/hosts.yml" PLAYBOOK="ansible/playbooks/drift-check.yml" +MODE="${MODE:-drift-check}" # drift-check or post-deploy echo "═══════════════════════════════════════════════════════════════════════════════" echo " GitOps Status Update" echo " Repository: $REPO_NAME | Server: $SERVER_NAME" echo " Target: $GITOPS_STATUS_SERVER_URL" +echo " Mode: $MODE" echo "═══════════════════════════════════════════════════════════════════════════════" echo "" -# ───────────────────────────────────────────────────────────────────────────────── -# Step 1: Run drift-check playbook -# ───────────────────────────────────────────────────────────────────────────────── -echo "Step 1/4: Running drift-check playbook..." - -# Capture playbook output to a temp file for parsing -PLAYBOOK_LOG=$(mktemp) -KEEP_LOG="${KEEP_PLAYBOOK_LOG:-false}" -if [ "$KEEP_LOG" = "true" ]; then - PLAYBOOK_LOG="./drift-check-output.log" - echo " Playbook output will be saved to: $PLAYBOOK_LOG" -fi - -# Set up cleanup trap (will be updated later with RESPONSE_BODY) -trap "rm -f $PLAYBOOK_LOG" EXIT - -# Run playbook (no -v flag to avoid file descriptor exhaustion in containers) -# Exit code: 0 = synced, non-zero = drift detected (expected) -# Limit forks to 1 to reduce file descriptor usage -set +e -ANSIBLE_FORCE_COLOR=false \ -ANSIBLE_FORKS=1 \ -ansible-playbook \ - -i "$INVENTORY_FILE" \ - "$PLAYBOOK" \ - > "$PLAYBOOK_LOG" 2>&1 -DRIFT_RC=$? -set -e - -# Show playbook output for debugging (compact) -echo "Playbook output (last 25 lines):" -cat "$PLAYBOOK_LOG" | tail -25 -echo "" -echo "DEBUG: Full playbook output saved to: $PLAYBOOK_LOG" -echo "" - -# ───────────────────────────────────────────────────────────────────────────────── -# Step 2: Determine sync status and collect changed files -# ───────────────────────────────────────────────────────────────────────────────── -echo "Step 2/4: Analyzing drift detection results..." - CHANGED_FILES=() DRIFT_COUNT=0 +SYNC_STATUS="SYNCED" -# Exit code 0 = synced (all tasks succeeded) -# Exit code non-zero = drift detected (fail task was reached) -if [ "$DRIFT_RC" -eq 0 ]; then - SYNC_STATUS="SYNCED" - echo " ✓ Status: SYNCED - server configuration matches Git" -else - SYNC_STATUS="OUT_OF_SYNC" - echo " ✗ Status: OUT OF SYNC - configuration drift detected" -fi - -# Extract structured drifted files from playbook output -# The drift-check.yml playbook outputs: DRIFTED_FILES=file1,file2,file3 -# With YAML callback, the output format is: msg: DRIFTED_FILES=... -echo " DEBUG: Searching for DRIFTED_FILES in playbook output..." -if grep -q "DRIFTED_FILES=" "$PLAYBOOK_LOG"; then - echo " DEBUG: Found DRIFTED_FILES pattern" - DRIFTED_FILES_LINE=$(grep "DRIFTED_FILES=" "$PLAYBOOK_LOG" | tail -1) - echo " DEBUG: Raw line: $DRIFTED_FILES_LINE" +# ───────────────────────────────────────────────────────────────────────────────── +# MODE 1: post-deploy - Report what files were deployed from Git +# ───────────────────────────────────────────────────────────────────────────────── +if [ "$MODE" = "post-deploy" ]; then + echo "Step 1/4: Analyzing Git changes (what was just deployed)..." - # Extract value after DRIFTED_FILES= (handles both YAML and default callback formats) - # Format: "msg: DRIFTED_FILES=file1,file2" or "DRIFTED_FILES=file1,file2" - DRIFTED_FILES_STR=$(echo "$DRIFTED_FILES_LINE" | sed 's/.*DRIFTED_FILES=//' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//' | tr -d '"') - echo " DEBUG: Extracted value: '$DRIFTED_FILES_STR'" - - # Check if the value is an empty list ([] or empty string) - if [ -n "$DRIFTED_FILES_STR" ] && [ "$DRIFTED_FILES_STR" != "[]" ] && [ "$DRIFTED_FILES_STR" != "" ]; then - # Parse comma-separated list into array - IFS=',' read -ra CHANGED_FILES <<<"$DRIFTED_FILES_STR" + # Check what files changed in the last commit in files/ directory + if command -v git >/dev/null 2>&1 && [ -d .git ]; then + # Get list of changed files in files/ directory from last commit + CHANGED_FILE_PATHS=$(git diff-tree --no-commit-id --name-only -r HEAD -- files/ 2>/dev/null || echo "") - echo " DEBUG: Parsed ${#CHANGED_FILES[@]} files" - - # Clean up whitespace and normalize paths - for i in "${!CHANGED_FILES[@]}"; do - CHANGED_FILES[$i]=$(echo "${CHANGED_FILES[$i]}" | xargs) + if [ -n "$CHANGED_FILE_PATHS" ]; then + echo " Files changed in last commit:" + while IFS= read -r filepath; do + if [ -n "$filepath" ]; then + # Strip "files/" prefix to get the config file name + filename="${filepath#files/}" + + # Skip if it's just "files/" (directory change) + if [ "$filename" != "" ] && [ "$filename" != "files/" ]; then + CHANGED_FILES+=("$filename") + echo " - $filename" + fi + fi + done <<< "$CHANGED_FILE_PATHS" - # Convert full paths to relative paths for cleaner output - if [[ "${CHANGED_FILES[$i]}" == /etc/rsyslog.conf ]]; then - CHANGED_FILES[$i]="rsyslog.conf" - elif [[ "${CHANGED_FILES[$i]}" == /etc/rsyslog.d/* ]]; then - CHANGED_FILES[$i]=$(echo "${CHANGED_FILES[$i]}" | sed 's|^/etc/||') - fi - - if [ "$SYNC_STATUS" = "OUT_OF_SYNC" ]; then - echo " - Drift detected in: ${CHANGED_FILES[$i]}" - fi - done - - DRIFT_COUNT=${#CHANGED_FILES[@]} + DRIFT_COUNT=${#CHANGED_FILES[@]} + else + echo " No files changed in files/ directory" + fi else - echo " DEBUG: DRIFTED_FILES is empty or []" + echo " Git not available, cannot determine deployed files" fi -else - echo " DEBUG: DRIFTED_FILES not found in playbook output" - echo " DEBUG: Attempting to parse from changed task output..." - # Fallback: Look for "changed:" indicators in the playbook output - if grep -q "changed: \[" "$PLAYBOOK_LOG"; then - echo " DEBUG: Found changed tasks, but no structured DRIFTED_FILES output" - echo " DEBUG: This might indicate a playbook output format issue" + # Always SYNCED after successful deploy + SYNC_STATUS="SYNCED" + echo " ✓ Status: SYNCED - files were deployed successfully" + echo " Total deployed files: $DRIFT_COUNT" + echo "" + +# ───────────────────────────────────────────────────────────────────────────────── +# MODE 2: drift-check - Check for manual changes on server (drift detection) +# ───────────────────────────────────────────────────────────────────────────────── +else + echo "Step 1/4: Running drift-check playbook..." + + # Capture playbook output to a temp file for parsing + PLAYBOOK_LOG=$(mktemp) + KEEP_LOG="${KEEP_PLAYBOOK_LOG:-false}" + if [ "$KEEP_LOG" = "true" ]; then + PLAYBOOK_LOG="./drift-check-output.log" + echo " Playbook output will be saved to: $PLAYBOOK_LOG" fi -fi -# Additional validation: If OUT_OF_SYNC but no files found, show warning -if [ "$SYNC_STATUS" = "OUT_OF_SYNC" ] && [ "$DRIFT_COUNT" -eq 0 ]; then - echo " ⚠️ WARNING: Status is OUT_OF_SYNC but no drifted files were extracted" - echo " ⚠️ This might indicate a parsing issue. Check the playbook output above." -fi + # Set up cleanup trap (will be updated later with RESPONSE_BODY) + trap "rm -f $PLAYBOOK_LOG" EXIT -echo " Total drift count: $DRIFT_COUNT" -echo "" + # Run playbook (no -v flag to avoid file descriptor exhaustion in containers) + # Exit code: 0 = synced, non-zero = drift detected (expected) + # Limit forks to 1 to reduce file descriptor usage + set +e + ANSIBLE_FORCE_COLOR=false \ + ANSIBLE_FORKS=1 \ + ansible-playbook \ + -i "$INVENTORY_FILE" \ + "$PLAYBOOK" \ + > "$PLAYBOOK_LOG" 2>&1 + DRIFT_RC=$? + set -e + + # Show playbook output for debugging (compact) + echo "Playbook output (last 25 lines):" + cat "$PLAYBOOK_LOG" | tail -25 + echo "" + echo "DEBUG: Full playbook output saved to: $PLAYBOOK_LOG" + echo "" + + # ───────────────────────────────────────────────────────────────────────────────── + # Step 2: Determine sync status and collect changed files + # ───────────────────────────────────────────────────────────────────────────────── + echo "Step 2/4: Analyzing drift detection results..." + + # Exit code 0 = synced (all tasks succeeded) + # Exit code non-zero = drift detected (fail task was reached) + if [ "$DRIFT_RC" -eq 0 ]; then + SYNC_STATUS="SYNCED" + echo " ✓ Status: SYNCED - server configuration matches Git" + else + SYNC_STATUS="OUT_OF_SYNC" + echo " ✗ Status: OUT OF SYNC - configuration drift detected" + fi + + # Extract structured drifted files from playbook output + # The drift-check.yml playbook outputs: DRIFTED_FILES=file1,file2,file3 + echo " DEBUG: Searching for DRIFTED_FILES in playbook output..." + if grep -q "DRIFTED_FILES=" "$PLAYBOOK_LOG"; then + echo " DEBUG: Found DRIFTED_FILES pattern" + DRIFTED_FILES_LINE=$(grep "DRIFTED_FILES=" "$PLAYBOOK_LOG" | tail -1) + echo " DEBUG: Raw line: $DRIFTED_FILES_LINE" + + # Extract value after DRIFTED_FILES= (handles both YAML and default callback formats) + # Format: "msg: DRIFTED_FILES=file1,file2" or "DRIFTED_FILES=file1,file2" + DRIFTED_FILES_STR=$(echo "$DRIFTED_FILES_LINE" | sed 's/.*DRIFTED_FILES=//' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//' | tr -d '"') + echo " DEBUG: Extracted value: '$DRIFTED_FILES_STR'" + + # Check if the value is an empty list ([] or empty string) + if [ -n "$DRIFTED_FILES_STR" ] && [ "$DRIFTED_FILES_STR" != "[]" ] && [ "$DRIFTED_FILES_STR" != "" ]; then + # Parse comma-separated list into array + IFS=',' read -ra CHANGED_FILES <<<"$DRIFTED_FILES_STR" + + echo " DEBUG: Parsed ${#CHANGED_FILES[@]} files" + + # Clean up whitespace and normalize paths + for i in "${!CHANGED_FILES[@]}"; do + CHANGED_FILES[$i]=$(echo "${CHANGED_FILES[$i]}" | xargs) + + # Convert full paths to relative paths for cleaner output + if [[ "${CHANGED_FILES[$i]}" == /etc/rsyslog.conf ]]; then + CHANGED_FILES[$i]="rsyslog.conf" + elif [[ "${CHANGED_FILES[$i]}" == /etc/rsyslog.d/* ]]; then + CHANGED_FILES[$i]=$(echo "${CHANGED_FILES[$i]}" | sed 's|^/etc/||') + fi + + if [ "$SYNC_STATUS" = "OUT_OF_SYNC" ]; then + echo " - Drift detected in: ${CHANGED_FILES[$i]}" + fi + done + + DRIFT_COUNT=${#CHANGED_FILES[@]} + else + echo " DEBUG: DRIFTED_FILES is empty or []" + fi + else + echo " DEBUG: DRIFTED_FILES not found in playbook output" + fi + + # Additional validation: If OUT_OF_SYNC but no files found, show warning + if [ "$SYNC_STATUS" = "OUT_OF_SYNC" ] && [ "$DRIFT_COUNT" -eq 0 ]; then + echo " ⚠️ WARNING: Status is OUT_OF_SYNC but no drifted files were extracted" + echo " ⚠️ This might indicate a parsing issue. Check the playbook output above." + fi + + echo " Total drift count: $DRIFT_COUNT" + echo "" +fi # ───────────────────────────────────────────────────────────────────────────────── # Step 3: Build JSON payload