Sistema completo para monitoreo y gestion de flotas de vehiculos con: - Backend FastAPI con PostgreSQL/TimescaleDB - Frontend React con TypeScript y TailwindCSS - App movil React Native con Expo - Soporte para dispositivos GPS, Meshtastic y celulares - Video streaming en vivo con MediaMTX - Geocercas, alertas, viajes y reportes - Autenticacion JWT y WebSockets en tiempo real Documentacion completa y guias de usuario incluidas.
550 lines
15 KiB
Bash
550 lines
15 KiB
Bash
#!/bin/bash
|
|
# ============================================
|
|
# Sistema de Flotillas - 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/flotillas}"
|
|
BACKUP_DIR="${BACKUP_DIR:-/var/backups/flotillas}"
|
|
|
|
# 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:-flotillas}"
|
|
DB_USER="${POSTGRES_USER:-flotillas}"
|
|
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 Flotillas - 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/flotillas/daily/flotillas_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="flotillas_${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 flotillas-api 2>/dev/null || true
|
|
systemctl stop flotillas-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 flotillas-api 2>/dev/null || true
|
|
systemctl start flotillas-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/flotillas-*.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 Flotillas - 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 flotillas-api"
|
|
echo " systemctl status flotillas-web"
|
|
echo ""
|
|
}
|
|
|
|
# Ejecutar
|
|
main "$@"
|