#!/bin/bash # run-playbook.sh # Usage: # ./run-playbook.sh [inventory.ini] [limit] # Behavior: # 1) Attempt 1: key auth as user "bummsa" (override with SSH_KEY_USER) # 2) Attempt 2: --ask-pass as root, -e ansible_become=false # 3) Attempt 3 (optional): --ask-pass as SSH_KEY_USER set -euo pipefail PLAYBOOK="${1:-}" INVENTORY="${2:-inventory.ini}" LIMIT_ARG="${3:-}" SSH_KEY_USER="${SSH_KEY_USER:-bummsa}" FINAL_FALLBACK_AS_USER="${FINAL_FALLBACK_AS_USER:-yes}" if [[ -z "$PLAYBOOK" ]]; then echo "Usage: $0 [inventory.ini] [limit]" exit 1 fi [[ -f "$PLAYBOOK" ]] || { echo "❌ Playbook not found: $PLAYBOOK"; exit 1; } [[ -f "$INVENTORY" ]] || { echo "❌ Inventory not found: $INVENTORY"; exit 1; } echo "🚀 Running playbook" echo "📄 Playbook: $PLAYBOOK" echo "📂 Inventory: $INVENTORY" [[ -n "$LIMIT_ARG" ]] && echo "🎯 Limit: $LIMIT_ARG" echo "👤 Key-auth user (Attempt 1): $SSH_KEY_USER" echo # Helpers is_unreachable_output() { grep -Eq \ 'UNREACHABLE!|Failed to connect to the host via ssh|Permission denied \(publickey,password\)|Permission denied, please try again|No route to host|Could not resolve hostname|Name or service not known|Host key verification failed' \ "$1" } ANSIBLE_LIMIT_OPTS=() [[ -n "$LIMIT_ARG" ]] && ANSIBLE_LIMIT_OPTS=(--limit "$LIMIT_ARG") echo "=== Inventory Validation ===" ansible-inventory -i "$INVENTORY" --list >/dev/null echo "✅ Inventory OK" echo # ---- Attempt 1: key auth as SSH_KEY_USER ---- echo "=== Attempt 1: Key auth as ${SSH_KEY_USER} ===" TMP1="$(mktemp)" set +e ansible-playbook -i "$INVENTORY" "${ANSIBLE_LIMIT_OPTS[@]-}" -u "$SSH_KEY_USER" -b "$PLAYBOOK" 2>&1 | tee "$TMP1" RC1=${PIPESTATUS[0]} set -e if [[ $RC1 -eq 0 ]]; then echo echo "✅ Run successful (key auth as $SSH_KEY_USER)" rm -f "$TMP1" exit 0 fi if ! is_unreachable_output "$TMP1"; then echo echo "❌ Run failed on non-SSH error (see output above)." echo " Log: $TMP1" exit $RC1 fi # Need interactive terminal for password prompts if [[ ! -t 0 ]]; then echo echo "❌ SSH unreachable and no TTY available for password prompt." echo " Fix key auth or run interactively. Log: $TMP1" exit 1 fi # ---- Attempt 2: password as root (no become) ---- echo echo "⚠️ Key auth failed. Falling back to password as root (no become)…" echo "=== Attempt 2: Password as root (no become) ===" TMP2="$(mktemp)" set +e ansible-playbook -i "$INVENTORY" "${ANSIBLE_LIMIT_OPTS[@]-}" "$PLAYBOOK" --ask-pass -u root -e ansible_become=false 2>&1 | tee "$TMP2" RC2=${PIPESTATUS[0]} set -e if [[ $RC2 -eq 0 ]]; then echo echo "✅ Run successful (password auth as root)" rm -f "$TMP1" "$TMP2" exit 0 fi if ! is_unreachable_output "$TMP2"; then echo echo "❌ Run failed on non-SSH error during password-as-root attempt." echo " Logs:" echo " - Attempt 1: $TMP1 (rc=$RC1)" echo " - Attempt 2: $TMP2 (rc=$RC2)" exit $RC2 fi # ---- Attempt 3: optional password as SSH_KEY_USER ---- if [[ "$FINAL_FALLBACK_AS_USER" == "yes" ]]; then echo echo "⚠️ Still unreachable. Trying password as ${SSH_KEY_USER} (final fallback)…" echo "=== Attempt 3: Password as ${SSH_KEY_USER} ===" TMP3="$(mktemp)" set +e ansible-playbook -i "$INVENTORY" "${ANSIBLE_LIMIT_OPTS[@]-}" "$PLAYBOOK" --ask-pass -u "$SSH_KEY_USER" 2>&1 | tee "$TMP3" RC3=${PIPESTATUS[0]} set -e if [[ $RC3 -eq 0 ]]; then echo echo "✅ Run successful (password auth as $SSH_KEY_USER)" rm -f "$TMP1" "$TMP2" "$TMP3" exit 0 fi echo echo "❌ All attempts failed." echo " Logs:" echo " - Attempt 1: $TMP1 (rc=$RC1)" echo " - Attempt 2: $TMP2 (rc=$RC2)" echo " - Attempt 3: $TMP3 (rc=$RC3)" exit 1 else echo echo "❌ Attempts 1 & 2 failed; final user fallback disabled." echo " Logs:" echo " - Attempt 1: $TMP1 (rc=$RC1)" echo " - Attempt 2: $TMP2 (rc=$RC2)" exit 1 fi