fix: restore script

This commit is contained in:
2026-06-05 17:37:45 +01:00
parent 0d7468dd7f
commit 715993af46

View File

@@ -14,10 +14,24 @@
# - Applies all known post-restore fixes per app # - Applies all known post-restore fixes per app
# - Detects target IP automatically or uses provided one # - Detects target IP automatically or uses provided one
# - Works whether run locally or proxied over SSH # - Works whether run locally or proxied over SSH
# - Works inside Docker containers (no ip command needed)
# - Supports both docker-compose and docker compose
# ============================================= # =============================================
set -uo pipefail set -uo pipefail
# --------------------------------------------------
# Compatibility fixes — must come first
# --------------------------------------------------
# docker compose v2 compat (fixes "docker-compose: command not found")
if ! command -v docker-compose &>/dev/null; then
if docker compose version &>/dev/null 2>&1; then
docker-compose() { docker compose "$@"; }
export -f docker-compose
fi
fi
# -------------------------------------------------- # --------------------------------------------------
# Parse arguments # Parse arguments
# -------------------------------------------------- # --------------------------------------------------
@@ -63,11 +77,9 @@ if [ "$REMOTE_MODE" = true ]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REMOTE_DEST="/tmp/restore-session-$(date +%s)" REMOTE_DEST="/tmp/restore-session-$(date +%s)"
# Build SSH/SCP options
SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=15" SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=15"
if [ -n "$SSH_KEY" ]; then if [ -n "$SSH_KEY" ]; then
SSH_OPTS="$SSH_OPTS -i $SSH_KEY" SSH_OPTS="$SSH_OPTS -i $SSH_KEY"
SCP_OPTS="$SSH_OPTS"
elif [ "$USE_PASSWORD" = true ]; then elif [ "$USE_PASSWORD" = true ]; then
if ! command -v sshpass &>/dev/null; then if ! command -v sshpass &>/dev/null; then
echo "❌ sshpass not installed. Install it with: apt install sshpass" echo "❌ sshpass not installed. Install it with: apt install sshpass"
@@ -123,8 +135,31 @@ fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
# Detect IP of this machine # --------------------------------------------------
VM_IP=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1 | head -1) # Detect IP — works inside containers too
# --------------------------------------------------
VM_IP=""
# Try hostname -I first (works inside containers)
if command -v hostname &>/dev/null; then
VM_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
fi
# Fallback: try ip command
if [ -z "$VM_IP" ] && command -v ip &>/dev/null; then
VM_IP=$(ip -4 addr show 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1 | head -1)
fi
# Fallback: try /proc/net/fib_trie (works in minimal containers)
if [ -z "$VM_IP" ] && [ -f /proc/net/fib_trie ]; then
VM_IP=$(awk '/32 HOST/{print f} {f=$2}' /proc/net/fib_trie 2>/dev/null | grep -v 127.0.0.1 | head -1)
fi
# Final fallback: use known main server IP
if [ -z "$VM_IP" ]; then
VM_IP="173.249.20.244"
echo " ⚠️ Could not detect IP, defaulting to $VM_IP"
fi
echo "=========================================" echo "========================================="
echo "🔄 Smart Restore — LOCAL MODE" echo "🔄 Smart Restore — LOCAL MODE"
@@ -165,33 +200,37 @@ declare -A VOLUME_OWNERS=(
["mautic-setup_mautic-data"]="mautic-app" ["mautic-setup_mautic-data"]="mautic-app"
["mautic-setup_mautic-db-data"]="mautic-mariadb" ["mautic-setup_mautic-db-data"]="mautic-mariadb"
["n8n-setup_n8n-data"]="n8n-app" ["n8n-setup_n8n-data"]="n8n-app"
["n8n-setup_n8n-db-data"]="n8n-db" ["n8n-setup_n8n-db-data"]="n8n-postgres"
["odoo-clean_db-data"]="odoo-clean-db-1" ["odoo-clean_db-data"]="odoo-clean-db-1"
["odoo-clean_odoo-etc"]="odoo-clean-odoo-1" ["odoo-clean_odoo-etc"]="odoo-clean-odoo-1"
) )
cd "$SCRIPT_DIR/volumes" if [ -d "$SCRIPT_DIR/volumes" ]; then
for backup in *.tar.gz; do cd "$SCRIPT_DIR/volumes"
[ -f "$backup" ] || continue for backup in *.tar.gz; do
volume=$(basename "$backup" .tar.gz) [ -f "$backup" ] || { echo " ⚠️ No volume backups found in $SCRIPT_DIR/volumes"; break; }
owner="${VOLUME_OWNERS[$volume]:-}" volume=$(basename "$backup" .tar.gz)
owner="${VOLUME_OWNERS[$volume]:-}"
# If the owning container is healthy, skip this volume # If the owning container is healthy, skip this volume
if [ -n "$owner" ] && container_is_healthy "$owner"; then if [ -n "$owner" ] && container_is_healthy "$owner"; then
echo " ⏭️ $volume — container '$owner' is healthy, skipping" echo " ⏭️ $volume — container '$owner' is healthy, skipping"
continue continue
fi fi
echo -n " 📁 Restoring $volume ... " echo -n " 📁 Restoring $volume ... "
docker volume create "$volume" &>/dev/null || true docker volume create "$volume" &>/dev/null || true
docker run --rm \ docker run --rm \
-v "${volume}:/target" \ -v "${volume}:/target" \
-v "$(pwd):/backup" \ -v "$(pwd):/backup:ro" \
alpine \ alpine \
sh -c "cd /target && tar xzf /backup/$backup" \ sh -c "cd /target && tar xzf /backup/${backup}" \
&& echo "✅" || echo "⚠️ FAILED" && echo "✅" || echo "⚠️ FAILED"
done done
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
else
echo " ⚠️ No volumes/ directory found in backup — skipping volume restore"
fi
# -------------------------------------------------- # --------------------------------------------------
# 2. Start containers — skip healthy ones # 2. Start containers — skip healthy ones
@@ -217,26 +256,30 @@ declare -A APP_MAIN_CONTAINER=(
["n8n"]="n8n-app" ["n8n"]="n8n-app"
) )
cd "$SCRIPT_DIR/compose-files" if [ -d "$SCRIPT_DIR/compose-files" ]; then
for app in Frappe Odoo Nextcloud Mautic n8n; do cd "$SCRIPT_DIR/compose-files"
dir="${APP_DIRS[$app]}" for app in Frappe Odoo Nextcloud Mautic n8n; do
main_ctr="${APP_MAIN_CONTAINER[$app]}" dir="${APP_DIRS[$app]}"
main_ctr="${APP_MAIN_CONTAINER[$app]}"
if container_is_healthy "$main_ctr"; then if container_is_healthy "$main_ctr"; then
echo " ⏭️ $app — already running and healthy, skipping" echo " ⏭️ $app — already running and healthy, skipping"
continue continue
fi fi
if [ -d "$dir" ]; then if [ -d "$dir" ]; then
echo " 🚀 Starting $app..." echo " 🚀 Starting $app..."
cd "$dir" cd "$dir"
docker-compose up -d 2>&1 | tail -3 docker compose up -d 2>&1 | tail -3
cd .. cd ..
else else
echo " ⏭️ $app compose dir '$dir' not found, skipping" echo " ⏭️ $app compose dir '$dir' not found, skipping"
fi fi
done done
cd "$SCRIPT_DIR" cd "$SCRIPT_DIR"
else
echo " ⚠️ No compose-files/ directory found — skipping container start"
fi
echo "" echo ""
echo "⏳ Waiting 60s for containers to initialize..." echo "⏳ Waiting 60s for containers to initialize..."
@@ -381,16 +424,49 @@ fi
# ---- N8N ---- # ---- N8N ----
echo "" echo ""
echo "📌 n8n — Network check..." echo "📌 n8n — Network + volumes check..."
if container_is_healthy n8n-app; then if container_is_healthy n8n-app; then
echo " ⏭️ n8n is healthy, skipping fix" echo " ⏭️ n8n is healthy, skipping fix"
else else
# Ensure network exists
docker network inspect integration-network &>/dev/null \ docker network inspect integration-network &>/dev/null \
|| docker network create integration-network && echo " ✅ Created integration-network" || { docker network create integration-network && echo " ✅ Created integration-network"; }
if ! docker ps | grep -q n8n-app; then # Check if n8n volumes exist in backup — restore them if not already done
cd "$SCRIPT_DIR/compose-files/n8n-setup" && docker-compose up -d && cd "$SCRIPT_DIR" N8N_VOLUMES=("n8n-setup_n8n-data" "n8n-setup_n8n-db-data")
for vol in "${N8N_VOLUMES[@]}"; do
vol_backup="$SCRIPT_DIR/volumes/${vol}.tar.gz"
if [ -f "$vol_backup" ]; then
echo -n " 📁 Restoring $vol ... "
docker volume create "$vol" &>/dev/null || true
docker run --rm \
-v "${vol}:/target" \
-v "$SCRIPT_DIR/volumes:/backup:ro" \
alpine \
sh -c "cd /target && tar xzf /backup/${vol}.tar.gz" \
&& echo "✅" || echo "⚠️ FAILED"
else
echo " ⚠️ $vol backup not found in this archive — n8n will start fresh"
docker volume create "$vol" &>/dev/null || true
fi
done
# Start n8n via compose if compose file exists
N8N_COMPOSE_DIR="$SCRIPT_DIR/compose-files/n8n-setup"
if [ -d "$N8N_COMPOSE_DIR" ]; then
cd "$N8N_COMPOSE_DIR"
docker compose up -d 2>&1 | tail -3
cd "$SCRIPT_DIR"
else
# Fallback: check if n8n-app container exists but is stopped
if docker ps -a | grep -q n8n-app; then
docker start n8n-app && echo " ✅ Started existing n8n-app container"
else
echo " ⚠️ No compose file and no existing n8n-app container found"
echo " Start manually: docker start n8n-app"
fi
fi fi
echo " ✅ n8n → http://${VM_IP}:5678" echo " ✅ n8n → http://${VM_IP}:5678"
fi fi
@@ -406,4 +482,4 @@ echo " Mautic → http://${VM_IP}:8081/s/login (admin / Admin!Password123)"
echo " Odoo → http://${VM_IP}:8069/web" echo " Odoo → http://${VM_IP}:8069/web"
echo " n8n → http://${VM_IP}:5678" echo " n8n → http://${VM_IP}:5678"
echo " Frappe → http://${VM_IP}:8080" echo " Frappe → http://${VM_IP}:8080"
echo "=========================================" echo "========================================="