🎉 Initial commit - Hazard Odoo 16 project
- Custom modules: hazard_shopify, hazard_inventory_report, hazard_website - Third-party modules: bi_sql_editor, query_deluxe, sql_request_abstract, l10n_mx_sat_sync_itadmin_ee - Docker setup: Odoo 16 + PostgreSQL 17 - Utility scripts: backup_hazard.sh, update_module.py - Agent configuration: .agents/AGENTS.md - Security: Enterprise modules, credentials, backups and production data excluded via .gitignore
This commit is contained in:
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/bin/bash
|
||||
|
||||
# =============================================================
|
||||
# BACKUP SCRIPT PARA HAZARD (Odoo 16 en Docker)
|
||||
# Respalda: Base de datos PostgreSQL + Código del módulo
|
||||
# Frecuencia: Cada 12 horas (cron)
|
||||
# Retención local: 15 días
|
||||
# Nota: Plesk sube estos archivos a Google Drive automáticamente
|
||||
# como parte del backup del dominio tesscorp.com.mx
|
||||
# =============================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- CONFIGURACIÓN ---
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
BACKUP_NAME="backup_hazard_$(date +%Y%m%d_%H%M%S)"
|
||||
BACKUP_DIR="$SCRIPT_DIR/backups"
|
||||
MODULE_PATH="$SCRIPT_DIR/Addons/custom/hazard_shopify"
|
||||
DB_CONTAINER="odoo-16-db-hazard-new"
|
||||
ODOO_CONTAINER="odoo-16-hazard-new"
|
||||
DB_NAME="hazard_new"
|
||||
DB_USER="odoo"
|
||||
LOG_FILE="$SCRIPT_DIR/logs/backup.log"
|
||||
MAX_RETENTION_DAYS=15
|
||||
LOCK_FILE="/tmp/backup_hazard.lock"
|
||||
|
||||
# --- FUNCIONES ---
|
||||
log() {
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
cleanup_on_exit() {
|
||||
rm -f "$LOCK_FILE"
|
||||
rm -f "$BACKUP_DIR/code_$BACKUP_NAME.tar.gz" 2>/dev/null
|
||||
rm -f "$BACKUP_DIR/db_$BACKUP_NAME.sql" 2>/dev/null
|
||||
}
|
||||
|
||||
trap cleanup_on_exit EXIT
|
||||
|
||||
# --- PREVENIR EJECUCIONES SIMULTÁNEAS ---
|
||||
if [ -f "$LOCK_FILE" ]; then
|
||||
LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null)
|
||||
if kill -0 "$LOCK_PID" 2>/dev/null; then
|
||||
log "⚠️ [$(date '+%Y-%m-%d %H:%M:%S')] Backup ya en ejecución (PID: $LOCK_PID). Saliendo."
|
||||
exit 1
|
||||
else
|
||||
log "🔓 [$(date '+%Y-%m-%d %H:%M:%S')] Lock file huérfano encontrado. Limpiando..."
|
||||
rm -f "$LOCK_FILE"
|
||||
fi
|
||||
fi
|
||||
echo $$ > "$LOCK_FILE"
|
||||
|
||||
# --- CREAR DIRECTORIOS ---
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
|
||||
log "🚀 [$(date '+%Y-%m-%d %H:%M:%S')] Iniciando respaldo total de Hazard..."
|
||||
|
||||
# --- VERIFICAR QUE LOS CONTENEDORES ESTÉN CORRIENDO ---
|
||||
if ! docker ps --format '{{.Names}}' | grep -q "^${DB_CONTAINER}$"; then
|
||||
log "❌ [$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Contenedor $DB_CONTAINER no está corriendo. Abortando."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker ps --format '{{.Names}}' | grep -q "^${ODOO_CONTAINER}$"; then
|
||||
log "⚠️ [$(date '+%Y-%m-%d %H:%M:%S')] ADVERTENCIA: Contenedor $ODOO_CONTAINER no está corriendo. Continuando solo con DB..."
|
||||
fi
|
||||
|
||||
# --- 1. RESPALDAR CÓDIGO DEL MÓDULO ---
|
||||
log "📦 Comprimiendo código del módulo..."
|
||||
if [ -d "$MODULE_PATH" ]; then
|
||||
tar -czf "$BACKUP_DIR/code_$BACKUP_NAME.tar.gz" -C "$(dirname "$MODULE_PATH")" "$(basename "$MODULE_PATH")"
|
||||
CODE_SIZE=$(du -sh "$BACKUP_DIR/code_$BACKUP_NAME.tar.gz" | cut -f1)
|
||||
log " ✓ Código comprimido: $CODE_SIZE"
|
||||
else
|
||||
log "⚠️ ADVERTENCIA: Ruta del módulo no encontrada: $MODULE_PATH"
|
||||
fi
|
||||
|
||||
# --- 2. RESPALDAR BASE DE DATOS (SQL Dump) ---
|
||||
log "🗄️ Extrayendo base de datos desde el contenedor Docker..."
|
||||
if docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" "$DB_NAME" > "$BACKUP_DIR/db_$BACKUP_NAME.sql" 2>/dev/null; then
|
||||
DB_SIZE=$(du -sh "$BACKUP_DIR/db_$BACKUP_NAME.sql" | cut -f1)
|
||||
log " ✓ Base de datos exportada: $DB_SIZE"
|
||||
else
|
||||
log "❌ [$(date '+%Y-%m-%d %H:%M:%S')] ERROR: Falló el dump de la base de datos."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- 3. VERIFICAR QUE EL DUMP NO ESTÉ VACÍO ---
|
||||
if [ ! -s "$BACKUP_DIR/db_$BACKUP_NAME.sql" ]; then
|
||||
log "❌ [$(date '+%Y-%m-%d %H:%M:%S')] ERROR: El dump de la base de datos está vacío. Abortando."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- 4. EMPAQUETAR TODO ---
|
||||
log "🎁 Creando paquete comprimido final..."
|
||||
tar -czf "$BACKUP_DIR/$BACKUP_NAME.tar.gz" -C "$BACKUP_DIR" "code_$BACKUP_NAME.tar.gz" "db_$BACKUP_NAME.sql"
|
||||
|
||||
FINAL_SIZE=$(du -sh "$BACKUP_DIR/$BACKUP_NAME.tar.gz" | cut -f1)
|
||||
log " ✓ Paquete final: $FINAL_SIZE"
|
||||
|
||||
# --- 5. VERIFICAR INTEGRIDAD DEL ARCHIVO ---
|
||||
if tar -tzf "$BACKUP_DIR/$BACKUP_NAME.tar.gz" > /dev/null 2>&1; then
|
||||
log " ✓ Integridad verificada: OK"
|
||||
else
|
||||
log "❌ [$(date '+%Y-%m-%d %H:%M:%S')] ERROR: El archivo de backup está corrupto."
|
||||
rm -f "$BACKUP_DIR/$BACKUP_NAME.tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Limpiar archivos temporales (también se limpian en trap EXIT)
|
||||
rm -f "$BACKUP_DIR/code_$BACKUP_NAME.tar.gz" "$BACKUP_DIR/db_$BACKUP_NAME.sql"
|
||||
|
||||
# --- 6. POLÍTICA DE RETENCIÓN ---
|
||||
log "🧹 Ejecutando política de retención (Limpiando archivos de más de $MAX_RETENTION_DAYS días)..."
|
||||
DELETED_COUNT=$(find "$BACKUP_DIR" -name "backup_hazard_*.tar.gz" -type f -mtime +$MAX_RETENTION_DAYS -delete -print | wc -l)
|
||||
log " ✓ Archivos eliminados: $DELETED_COUNT"
|
||||
|
||||
# --- 7. RESUMEN ---
|
||||
TOTAL_BACKUPS=$(find "$BACKUP_DIR" -name "backup_hazard_*.tar.gz" -type f | wc -l)
|
||||
TOTAL_SIZE=$(du -sh "$BACKUP_DIR" | cut -f1)
|
||||
|
||||
echo "----------------------------------------------------"
|
||||
log "✅ ¡RESPALDO COMPLETADO CON ÉXITO!"
|
||||
log "📍 Archivo: $BACKUP_DIR/$BACKUP_NAME.tar.gz"
|
||||
log "📊 Tamaño: $FINAL_SIZE"
|
||||
log "📁 Total backups locales: $TOTAL_BACKUPS ($TOTAL_SIZE)"
|
||||
log "☁️ Google Drive: Plesk subirá este archivo en su próximo backup programado"
|
||||
echo "----------------------------------------------------"
|
||||
Reference in New Issue
Block a user