From a7c3e3e7fefec9d0b4b9e530b53c979829f69bcc Mon Sep 17 00:00:00 2001 From: ameniboukattaya Date: Sat, 6 Jun 2026 15:10:39 +0100 Subject: [PATCH] fix: restore script --- platform/app.py | 3 +- platform/restore-myapps.sh | 187 ++++++++++--------------------------- 2 files changed, 51 insertions(+), 139 deletions(-) diff --git a/platform/app.py b/platform/app.py index e9050ad..ed5e25f 100644 --- a/platform/app.py +++ b/platform/app.py @@ -746,7 +746,8 @@ def restore_start(): if target == 'local': hostname = os.uname().nodename - session_dir = f"/tmp/restore-session-{uuid.uuid4().hex[:8]}" + os.makedirs('/root/tmp', exist_ok=True) + session_dir = f"/root/tmp/restore-session-{uuid.uuid4().hex[:8]}" cmd = ( f"set -e && " f"echo 'Restoring on this server ({hostname})...' && " diff --git a/platform/restore-myapps.sh b/platform/restore-myapps.sh index 24db97f..a3e32e8 100755 --- a/platform/restore-myapps.sh +++ b/platform/restore-myapps.sh @@ -1,36 +1,12 @@ #!/bin/bash # ============================================= # restore-myapps.sh โ€” Smart Restore Script -# -# Can run: -# - Locally on the server/vm: -# ./restore-myapps.sh -# -# - Remotely (from VM targeting the main server, or vice versa): -# ./restore-myapps.sh --remote [--key /path/to/key | --password] -# -# Features: -# - Skips containers that are already healthy/running -# - Applies all known post-restore fixes per app -# - Detects target IP automatically or uses provided one -# - 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 -# -------------------------------------------------- -# 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 +# docker compose v2 compat +command -v docker-compose &>/dev/null || docker-compose() { docker compose "$@"; } # -------------------------------------------------- # Parse arguments @@ -39,7 +15,6 @@ REMOTE_MODE=false REMOTE_IP="" REMOTE_USER="root" SSH_KEY="" -SSH_PASSWORD="" USE_PASSWORD=false while [[ $# -gt 0 ]]; do @@ -65,12 +40,11 @@ while [[ $# -gt 0 ]]; do done # -------------------------------------------------- -# If remote mode: copy this script + backup to target and run it there +# Remote mode # -------------------------------------------------- if [ "$REMOTE_MODE" = true ]; then if [ -z "$REMOTE_IP" ]; then echo "โŒ --remote requires an IP address." - echo " Usage: $0 --remote [USER] [--key /path/key]" exit 1 fi @@ -87,7 +61,7 @@ if [ "$REMOTE_MODE" = true ]; then fi read -s -p "SSH password for ${REMOTE_USER}@${REMOTE_IP}: " SSH_PASS echo "" - SSH_CMD="sshpass -p '$SSH_PASS' ssh $SSH_OPTS" + SSH_CMD="sshpass -p '$SSH_PASS' ssh $SSH_OPTS ${REMOTE_USER}@${REMOTE_IP}" SCP_CMD="sshpass -p '$SSH_PASS' scp $SSH_OPTS" fi @@ -100,66 +74,28 @@ if [ "$REMOTE_MODE" = true ]; then echo "=========================================" echo "๐Ÿ“ก REMOTE RESTORE MODE" echo " Target: ${REMOTE_USER}@${REMOTE_IP}" - echo " Backup: $SCRIPT_DIR" echo "=========================================" - echo "" - echo "๐Ÿ“ค Copying backup to remote server..." $SSH_CMD "mkdir -p $REMOTE_DEST" $SCP_CMD -r "$SCRIPT_DIR/." "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_DEST}/" - - if [ $? -ne 0 ]; then - echo "โŒ Failed to copy backup to remote server." - exit 1 - fi - - echo "โœ… Backup copied." - echo "" - echo "๐Ÿš€ Running restore on remote server..." $SSH_CMD "chmod +x $REMOTE_DEST/restore-myapps.sh && cd $REMOTE_DEST && bash restore-myapps.sh" - - echo "" - echo "๐Ÿงน Cleaning up remote temp files..." $SSH_CMD "rm -rf $REMOTE_DEST" - echo "=========================================" echo "โœ… Remote restore complete on $REMOTE_IP" - echo "=========================================" exit 0 fi # =================================================== -# LOCAL RESTORE (runs directly on the target machine) +# LOCAL RESTORE # =================================================== SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" -# -------------------------------------------------- -# 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 +# Detect IP โ€” works inside containers and on host +VM_IP=$(hostname -I 2>/dev/null | awk '{print $1}') +[ -z "$VM_IP" ] && VM_IP=$(ip -4 addr show 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1 | head -1) +[ -z "$VM_IP" ] && VM_IP="173.249.20.244" echo "=========================================" echo "๐Ÿ”„ Smart Restore โ€” LOCAL MODE" @@ -167,25 +103,20 @@ echo " Machine IP: $VM_IP" echo " Backup dir: $SCRIPT_DIR" echo "=========================================" -# -------------------------------------------------- -# Helper: check if a container is healthy/running -# Returns 0 (true) if container should be skipped -# -------------------------------------------------- container_is_healthy() { local name="$1" local status status=$(docker inspect --format='{{.State.Status}}' "$name" 2>/dev/null || echo "missing") local health health=$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$name" 2>/dev/null || echo "none") - if [ "$status" = "running" ] && { [ "$health" = "healthy" ] || [ "$health" = "none" ]; }; then - return 0 # healthy โ†’ skip + return 0 fi - return 1 # not healthy โ†’ restore + return 1 } # -------------------------------------------------- -# 1. Restore volumes โ€” skip if container using it is healthy +# STEP 1: Restore Volumes # -------------------------------------------------- echo "" echo "=========================================" @@ -208,11 +139,10 @@ declare -A VOLUME_OWNERS=( if [ -d "$SCRIPT_DIR/volumes" ]; then cd "$SCRIPT_DIR/volumes" for backup in *.tar.gz; do - [ -f "$backup" ] || { echo " โš ๏ธ No volume backups found in $SCRIPT_DIR/volumes"; break; } + [ -f "$backup" ] || continue volume=$(basename "$backup" .tar.gz) owner="${VOLUME_OWNERS[$volume]:-}" - # If the owning container is healthy, skip this volume if [ -n "$owner" ] && container_is_healthy "$owner"; then echo " โญ๏ธ $volume โ€” container '$owner' is healthy, skipping" continue @@ -229,11 +159,11 @@ if [ -d "$SCRIPT_DIR/volumes" ]; then done cd "$SCRIPT_DIR" else - echo " โš ๏ธ No volumes/ directory found in backup โ€” skipping volume restore" + echo " โš ๏ธ No volumes/ directory found โ€” skipping" fi # -------------------------------------------------- -# 2. Start containers โ€” skip healthy ones +# STEP 2: Start Containers # -------------------------------------------------- echo "" echo "=========================================" @@ -270,7 +200,7 @@ if [ -d "$SCRIPT_DIR/compose-files" ]; then if [ -d "$dir" ]; then echo " ๐Ÿš€ Starting $app..." cd "$dir" - docker compose up -d 2>&1 | tail -3 + docker-compose up -d 2>&1 | tail -3 cd .. else echo " โญ๏ธ $app compose dir '$dir' not found, skipping" @@ -278,7 +208,7 @@ if [ -d "$SCRIPT_DIR/compose-files" ]; then done cd "$SCRIPT_DIR" else - echo " โš ๏ธ No compose-files/ directory found โ€” skipping container start" + echo " โš ๏ธ No compose-files/ directory โ€” skipping" fi echo "" @@ -286,7 +216,7 @@ echo "โณ Waiting 60s for containers to initialize..." sleep 60 # -------------------------------------------------- -# 3. Post-restore fixes +# STEP 3: Post-Restore Fixes # -------------------------------------------------- echo "" echo "=========================================" @@ -306,16 +236,12 @@ else docker exec nextcloud-app php /var/www/html/occ config:system:set trusted_domains 1 --value="$VM_IP" docker exec nextcloud-app php /var/www/html/occ config:system:set trusted_domains 2 --value="${VM_IP}:8082" docker exec nextcloud-app php /var/www/html/occ config:system:set trusted_domains 3 --value="localhost:8082" - docker restart nextcloud-app - - # Fix permissions for oc_admin on nextcloud tables docker exec nextcloud-postgres psql -U nextcloud -d nextcloud -c " GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO oc_admin; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO oc_admin; " 2>/dev/null || true docker restart nextcloud-app - - echo " โœ… Nextcloud trusted domains fixed" + echo " โœ… Nextcloud fixed" else echo " โš ๏ธ nextcloud-app not running" fi @@ -346,7 +272,6 @@ EOF docker exec mautic-app chown -R www-data:www-data /var/www/html/var /var/www/html/config 2>/dev/null || true docker restart mautic-app sleep 10 - HASH=$(docker exec mautic-app php -r "echo password_hash('Admin!Password123', PASSWORD_BCRYPT);" 2>/dev/null || true) if [ -n "$HASH" ]; then docker exec mautic-mariadb mysql -uroot -pmautic_root_password \ @@ -362,17 +287,34 @@ fi # ---- ODOO ---- echo "" -echo "๐Ÿ“Œ Odoo โ€” Assets + DB user..." +echo "๐Ÿ“Œ Odoo โ€” Assets + DB + Config..." if container_is_healthy odoo-clean-odoo-1; then echo " โญ๏ธ Odoo is healthy, skipping fix" else if docker ps | grep -q odoo-clean-db-1; then + # Fix odoo.conf with proper settings + docker run --rm -v odoo-clean_odoo-etc:/etc/odoo alpine sh -c 'cat > /etc/odoo/odoo.conf << CONF +[options] +addons_path = /mnt/extra-addons +data_dir = /var/lib/odoo +db_host = db +db_user = odoo +db_password = odoo +db_name = odoo +workers = 4 +max_cron_threads = 1 +proxy_mode = True +assets_bundle_enabled = True +limit_memory_hard = 2684354560 +limit_memory_soft = 2147483648 +CONF' 2>/dev/null || true + docker exec odoo-clean-db-1 psql -U odoo -d odoo \ -c "DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';" 2>/dev/null || true + docker exec odoo-clean-db-1 psql -U odoo -d odoo \ + -c "UPDATE ir_config_parameter SET value='https://odooo.nav.ovh' WHERE key='web.base.url';" 2>/dev/null || true docker exec odoo-clean-db-1 psql -U odoo \ -c "ALTER USER odoo WITH PASSWORD 'odoo';" 2>/dev/null || true - docker exec odoo-clean-odoo-1 bash -c \ - "grep -q 'filestore_check_missing' /etc/odoo/odoo.conf || echo 'filestore_check_missing = False' >> /etc/odoo/odoo.conf" 2>/dev/null || true docker restart odoo-clean-odoo-1 echo " โœ… Odoo fixed โ†’ http://${VM_IP}:8069/web" else @@ -388,14 +330,10 @@ if container_is_healthy frappe-erpnext; then else if docker ps | grep -q frappe-erpnext && docker ps | grep -q frappe-mariadb; then SITE_CONFIG="/home/frappe/frappe-bench/sites/erpnext.navitrends.ovh/site_config.json" - DB_NAME=$(docker exec frappe-erpnext cat "$SITE_CONFIG" 2>/dev/null \ - | grep -o '"db_name": *"[^"]*"' | cut -d'"' -f4) - DB_PASS=$(docker exec frappe-erpnext cat "$SITE_CONFIG" 2>/dev/null \ - | grep -o '"db_password": *"[^"]*"' | cut -d'"' -f4) + DB_NAME=$(docker exec frappe-erpnext cat "$SITE_CONFIG" 2>/dev/null | grep -o '"db_name": *"[^"]*"' | cut -d'"' -f4) + DB_PASS=$(docker exec frappe-erpnext cat "$SITE_CONFIG" 2>/dev/null | grep -o '"db_password": *"[^"]*"' | cut -d'"' -f4) if [ -n "$DB_NAME" ] && [ -n "$DB_PASS" ]; then - echo " DB: $DB_NAME" - docker exec frappe-mariadb mysql -uroot -p123 -e " GRANT ALL PRIVILEGES ON *.* TO '${DB_NAME}'@'%' IDENTIFIED BY '${DB_PASS}' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO '${DB_NAME}'@'172.%' IDENTIFIED BY '${DB_PASS}' WITH GRANT OPTION; @@ -424,49 +362,22 @@ fi # ---- N8N ---- echo "" -echo "๐Ÿ“Œ n8n โ€” Network + volumes check..." +echo "๐Ÿ“Œ n8n โ€” Network check..." if container_is_healthy n8n-app; then echo " โญ๏ธ n8n is healthy, skipping fix" else - # Ensure network exists docker network inspect integration-network &>/dev/null \ || { docker network create integration-network && echo " โœ… Created integration-network"; } - # Check if n8n volumes exist in backup โ€” restore them if not already done - 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" + if ! docker ps | grep -q n8n-app; then + if [ -d "$SCRIPT_DIR/compose-files/n8n-setup" ]; then + cd "$SCRIPT_DIR/compose-files/n8n-setup" + docker-compose up -d 2>&1 | tail -3 + cd "$SCRIPT_DIR" 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" + docker start n8n-app 2>/dev/null && echo " โœ… Started n8n-app" || echo " โš ๏ธ Could not start n8n" fi fi - echo " โœ… n8n โ†’ http://${VM_IP}:5678" fi @@ -479,7 +390,7 @@ echo "โœ… RESTORE COMPLETE" echo "=========================================" echo " Nextcloud โ†’ http://${VM_IP}:8082" echo " Mautic โ†’ http://${VM_IP}:8081/s/login (admin / Admin!Password123)" -echo " Odoo โ†’ http://${VM_IP}:8069/web" +echo " Odoo โ†’ https://odooo.nav.ovh/web" echo " n8n โ†’ http://${VM_IP}:5678" echo " Frappe โ†’ http://${VM_IP}:8080" echo "=========================================" \ No newline at end of file