Files
ATLAS/deploy/scripts/restore.sh
2026-01-21 08:26:01 +00:00

550 lines
15 KiB
Bash

#!/bin/bash
# ============================================
# Sistema de ADAN - Script de Restauracion
# ============================================
# Restaura backups de base de datos y configuracion
#
# Uso: ./restore.sh [--db backup.sql.gz] [--config config.tar.gz] [--list]
#
# Opciones:
# --db FILE Restaurar backup de base de datos
# --config FILE Restaurar backup de configuracion
# --list Listar backups disponibles
# --latest Restaurar el backup mas reciente
# --date YYYYMMDD Restaurar backup de fecha especifica
# ============================================
set -e
set -o pipefail
# ---------------------------------------------
# Colores
# ---------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# ---------------------------------------------
# Variables
# ---------------------------------------------
INSTALL_DIR="${INSTALL_DIR:-/opt/adan}"
BACKUP_DIR="${BACKUP_DIR:-/var/backups/adan}"
# Cargar variables de entorno
if [[ -f "$INSTALL_DIR/.env" ]]; then
export $(grep -v '^#' "$INSTALL_DIR/.env" | xargs)
fi
# Base de datos
DB_HOST="${POSTGRES_HOST:-localhost}"
DB_PORT="${POSTGRES_PORT:-5432}"
DB_NAME="${POSTGRES_DB:-adan}"
DB_USER="${POSTGRES_USER:-adan}"
DB_PASSWORD="${POSTGRES_PASSWORD:-}"
# Opciones
DB_BACKUP=""
CONFIG_BACKUP=""
LIST_ONLY=false
USE_LATEST=false
RESTORE_DATE=""
# ---------------------------------------------
# Funciones
# ---------------------------------------------
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[OK]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# ---------------------------------------------
# Parsear argumentos
# ---------------------------------------------
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
--db)
DB_BACKUP="$2"
shift 2
;;
--config)
CONFIG_BACKUP="$2"
shift 2
;;
--list)
LIST_ONLY=true
shift
;;
--latest)
USE_LATEST=true
shift
;;
--date)
RESTORE_DATE="$2"
shift 2
;;
--help|-h)
show_help
exit 0
;;
*)
log_error "Opcion desconocida: $1"
exit 1
;;
esac
done
}
show_help() {
echo "Sistema de ADAN - Restauracion de Backup"
echo ""
echo "Uso: $0 [opciones]"
echo ""
echo "Opciones:"
echo " --db FILE Restaurar backup de base de datos"
echo " --config FILE Restaurar backup de configuracion"
echo " --list Listar backups disponibles"
echo " --latest Restaurar el backup mas reciente"
echo " --date YYYYMMDD Restaurar backup de fecha especifica"
echo ""
echo "Ejemplos:"
echo " $0 --list"
echo " $0 --latest"
echo " $0 --date 20240115"
echo " $0 --db /var/backups/adan/daily/adan_20240115_030000_db.sql.gz"
}
# ---------------------------------------------
# Listar backups disponibles
# ---------------------------------------------
list_backups() {
echo ""
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} BACKUPS DISPONIBLES${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
if [[ ! -d "$BACKUP_DIR/daily" ]]; then
log_warn "No hay backups disponibles"
return
fi
echo -e "${GREEN}Base de Datos:${NC}"
echo "---------------------------------------------"
printf "%-40s %10s %s\n" "Archivo" "Tamanio" "Fecha"
echo "---------------------------------------------"
for file in $(ls -t "$BACKUP_DIR/daily"/*_db.sql.gz 2>/dev/null); do
local name=$(basename "$file")
local size=$(du -h "$file" | cut -f1)
local date=$(stat -c %y "$file" | cut -d' ' -f1)
printf "%-40s %10s %s\n" "$name" "$size" "$date"
done
echo ""
echo -e "${GREEN}Configuracion:${NC}"
echo "---------------------------------------------"
for file in $(ls -t "$BACKUP_DIR/daily"/*_config.tar.gz 2>/dev/null); do
local name=$(basename "$file")
local size=$(du -h "$file" | cut -f1)
local date=$(stat -c %y "$file" | cut -d' ' -f1)
printf "%-40s %10s %s\n" "$name" "$size" "$date"
done
echo ""
echo -e "${GREEN}Backups Completos:${NC}"
echo "---------------------------------------------"
for file in $(ls -t "$BACKUP_DIR/daily"/*_full.tar.gz 2>/dev/null); do
local name=$(basename "$file")
local size=$(du -h "$file" | cut -f1)
local date=$(stat -c %y "$file" | cut -d' ' -f1)
printf "%-40s %10s %s\n" "$name" "$size" "$date"
done
echo ""
}
# ---------------------------------------------
# Encontrar backup mas reciente
# ---------------------------------------------
find_latest_backup() {
local type="$1" # db, config, full
local pattern="*_${type}.*gz"
local latest=$(ls -t "$BACKUP_DIR/daily"/$pattern 2>/dev/null | head -1)
if [[ -z "$latest" ]]; then
log_error "No se encontro backup de tipo: $type"
return 1
fi
echo "$latest"
}
# ---------------------------------------------
# Encontrar backup por fecha
# ---------------------------------------------
find_backup_by_date() {
local type="$1"
local date="$2"
local pattern="adan_${date}*_${type}.*gz"
local found=$(ls -t "$BACKUP_DIR/daily"/$pattern 2>/dev/null | head -1)
if [[ -z "$found" ]]; then
log_error "No se encontro backup de tipo '$type' para fecha: $date"
return 1
fi
echo "$found"
}
# ---------------------------------------------
# Detener servicios
# ---------------------------------------------
stop_services() {
log_info "Deteniendo servicios..."
systemctl stop adan-api 2>/dev/null || true
systemctl stop adan-web 2>/dev/null || true
# Esperar a que se detengan
sleep 2
log_success "Servicios detenidos"
}
# ---------------------------------------------
# Iniciar servicios
# ---------------------------------------------
start_services() {
log_info "Iniciando servicios..."
systemctl start adan-api 2>/dev/null || true
systemctl start adan-web 2>/dev/null || true
log_success "Servicios iniciados"
}
# ---------------------------------------------
# Restaurar base de datos
# ---------------------------------------------
restore_database() {
local backup_file="$1"
if [[ ! -f "$backup_file" ]]; then
log_error "Archivo no encontrado: $backup_file"
return 1
fi
log_info "Restaurando base de datos desde: $(basename "$backup_file")"
# Verificar integridad
log_info "Verificando integridad del archivo..."
if ! gzip -t "$backup_file" 2>/dev/null; then
log_error "El archivo de backup esta corrupto"
return 1
fi
# Confirmar
echo ""
echo -e "${YELLOW}ADVERTENCIA: Esto reemplazara TODOS los datos actuales${NC}"
echo -e "${YELLOW}Base de datos: ${DB_NAME}${NC}"
echo ""
read -p "Continuar? (escribir 'SI' para confirmar): " confirm
if [[ "$confirm" != "SI" ]]; then
log_warn "Restauracion cancelada"
return 1
fi
stop_services
# Exportar password
export PGPASSWORD="$DB_PASSWORD"
# Crear backup de seguridad antes de restaurar
log_info "Creando backup de seguridad..."
local safety_backup="$BACKUP_DIR/temp/pre_restore_$(date +%Y%m%d_%H%M%S).sql.gz"
mkdir -p "$BACKUP_DIR/temp"
pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" 2>/dev/null | gzip > "$safety_backup" || true
log_info "Backup de seguridad: $safety_backup"
# Terminar conexiones activas
log_info "Cerrando conexiones activas..."
psql -h "$DB_HOST" -p "$DB_PORT" -U postgres -c "
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = '${DB_NAME}' AND pid <> pg_backend_pid();
" 2>/dev/null || true
# Recrear base de datos
log_info "Recreando base de datos..."
# Eliminar y recrear BD
psql -h "$DB_HOST" -p "$DB_PORT" -U postgres <<EOF
DROP DATABASE IF EXISTS ${DB_NAME};
CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};
EOF
# Conectar y crear extensiones
psql -h "$DB_HOST" -p "$DB_PORT" -U postgres -d "$DB_NAME" <<EOF
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
GRANT ALL ON DATABASE ${DB_NAME} TO ${DB_USER};
GRANT ALL ON SCHEMA public TO ${DB_USER};
EOF
# Restaurar datos
log_info "Restaurando datos..."
gunzip -c "$backup_file" | psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -q
unset PGPASSWORD
log_success "Base de datos restaurada exitosamente"
start_services
}
# ---------------------------------------------
# Restaurar configuracion
# ---------------------------------------------
restore_config() {
local backup_file="$1"
if [[ ! -f "$backup_file" ]]; then
log_error "Archivo no encontrado: $backup_file"
return 1
fi
log_info "Restaurando configuracion desde: $(basename "$backup_file")"
# Verificar integridad
if ! gzip -t "$backup_file" 2>/dev/null; then
log_error "El archivo de backup esta corrupto"
return 1
fi
# Confirmar
echo ""
echo -e "${YELLOW}ADVERTENCIA: Esto sobrescribira archivos de configuracion${NC}"
echo ""
read -p "Continuar? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_warn "Restauracion cancelada"
return 1
fi
stop_services
# Crear directorio temporal
local temp_dir=$(mktemp -d)
# Extraer
log_info "Extrayendo configuracion..."
tar -xzf "$backup_file" -C "$temp_dir"
# Restaurar archivos
log_info "Restaurando archivos..."
# .env
if [[ -f "$temp_dir$INSTALL_DIR/.env" ]]; then
cp "$temp_dir$INSTALL_DIR/.env" "$INSTALL_DIR/.env"
log_info "Restaurado: .env"
fi
# Traccar
if [[ -f "$temp_dir/opt/traccar/conf/traccar.xml" ]]; then
cp "$temp_dir/opt/traccar/conf/traccar.xml" /opt/traccar/conf/traccar.xml
log_info "Restaurado: traccar.xml"
fi
# MediaMTX
if [[ -f "$temp_dir/opt/mediamtx/mediamtx.yml" ]]; then
cp "$temp_dir/opt/mediamtx/mediamtx.yml" /opt/mediamtx/mediamtx.yml
log_info "Restaurado: mediamtx.yml"
fi
# Servicios systemd
for service in $temp_dir/etc/systemd/system/adan-*.service; do
if [[ -f "$service" ]]; then
cp "$service" /etc/systemd/system/
log_info "Restaurado: $(basename "$service")"
fi
done
# Recargar systemd
systemctl daemon-reload
# Limpiar
rm -rf "$temp_dir"
log_success "Configuracion restaurada"
start_services
}
# ---------------------------------------------
# Restaurar backup completo
# ---------------------------------------------
restore_full() {
local backup_file="$1"
if [[ ! -f "$backup_file" ]]; then
log_error "Archivo no encontrado: $backup_file"
return 1
fi
log_info "Restaurando backup completo desde: $(basename "$backup_file")"
echo ""
echo -e "${RED}ADVERTENCIA: Esto reemplazara TODO el directorio de la aplicacion${NC}"
echo ""
read -p "Continuar? (escribir 'SI' para confirmar): " confirm
if [[ "$confirm" != "SI" ]]; then
log_warn "Restauracion cancelada"
return 1
fi
stop_services
# Backup actual
log_info "Respaldando instalacion actual..."
local current_backup="$BACKUP_DIR/temp/pre_restore_full_$(date +%Y%m%d_%H%M%S).tar.gz"
tar -czf "$current_backup" "$INSTALL_DIR" 2>/dev/null || true
# Extraer
log_info "Extrayendo backup completo..."
tar -xzf "$backup_file" -C /
log_success "Backup completo restaurado"
# Reinstalar dependencias
log_info "Reinstalando dependencias..."
cd "$INSTALL_DIR/backend"
source venv/bin/activate
pip install -r requirements.txt -q 2>/dev/null || pip install -e . -q
deactivate
cd "$INSTALL_DIR/frontend"
npm install 2>/dev/null || true
start_services
}
# ---------------------------------------------
# Main
# ---------------------------------------------
main() {
parse_args "$@"
# Solo listar
if [[ "$LIST_ONLY" == "true" ]]; then
list_backups
exit 0
fi
# Modo interactivo si no se especificaron opciones
if [[ -z "$DB_BACKUP" ]] && [[ -z "$CONFIG_BACKUP" ]] && [[ "$USE_LATEST" != "true" ]] && [[ -z "$RESTORE_DATE" ]]; then
echo ""
echo "Sistema de ADAN - Restauracion"
echo "===================================="
echo ""
echo "Selecciona una opcion:"
echo " 1) Restaurar backup mas reciente (DB + Config)"
echo " 2) Restaurar solo base de datos"
echo " 3) Restaurar solo configuracion"
echo " 4) Listar backups disponibles"
echo " 5) Cancelar"
echo ""
read -p "Opcion: " option
case $option in
1)
USE_LATEST=true
;;
2)
list_backups
echo ""
read -p "Ingresa ruta del archivo de BD: " DB_BACKUP
;;
3)
list_backups
echo ""
read -p "Ingresa ruta del archivo de config: " CONFIG_BACKUP
;;
4)
list_backups
exit 0
;;
*)
echo "Cancelado"
exit 0
;;
esac
fi
# Restaurar por fecha
if [[ -n "$RESTORE_DATE" ]]; then
log_info "Buscando backups para fecha: $RESTORE_DATE"
DB_BACKUP=$(find_backup_by_date "db.sql" "$RESTORE_DATE") || exit 1
CONFIG_BACKUP=$(find_backup_by_date "config.tar" "$RESTORE_DATE") || true
fi
# Restaurar mas reciente
if [[ "$USE_LATEST" == "true" ]]; then
log_info "Buscando backups mas recientes..."
DB_BACKUP=$(find_latest_backup "db.sql") || exit 1
CONFIG_BACKUP=$(find_latest_backup "config.tar") || true
fi
# Ejecutar restauraciones
if [[ -n "$DB_BACKUP" ]]; then
restore_database "$DB_BACKUP"
fi
if [[ -n "$CONFIG_BACKUP" ]]; then
restore_config "$CONFIG_BACKUP"
fi
echo ""
log_success "=========================================="
log_success "RESTAURACION COMPLETADA"
log_success "=========================================="
echo ""
echo "Verifica que los servicios esten funcionando:"
echo " systemctl status adan-api"
echo " systemctl status adan-web"
echo ""
}
# Ejecutar
main "$@"