|
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
# ============================================================
|
|
# CONFIGURACION
|
|
# ============================================================
|
|
|
|
DEV_HOST="10.90.1.197"
|
|
PROD_HOST="10.90.1.199" # Durante la prueba apunta a MAQ
|
|
|
|
DB_NAME="postgres"
|
|
DB_USER="postgres"
|
|
DB_PASSWORD="post3008"
|
|
SCHEMA_NAME="sn"
|
|
|
|
BASE_DIR="/home/ingenieria/sn2psql/backup_schema_sn"
|
|
DUMP_DIR="${BASE_DIR}/dumps"
|
|
LOG_DIR="${BASE_DIR}/logs"
|
|
CONTROL_DIR="${BASE_DIR}/control"
|
|
|
|
FECHA=$(date '+%Y%m%d_%H%M%S')
|
|
|
|
DUMP_NUEVO="${DUMP_DIR}/sn_dev_${FECHA}.dump"
|
|
DUMP_VALIDADO="${DUMP_DIR}/sn_dev_validado.dump"
|
|
BACKUP_PROD="${DUMP_DIR}/sn_prod_antes_restore_${FECHA}.dump"
|
|
|
|
CONTROL_DEV="${CONTROL_DIR}/conteos_dev_${FECHA}.txt"
|
|
CONTROL_PROD="${CONTROL_DIR}/conteos_prod_${FECHA}.txt"
|
|
DIFERENCIAS="${CONTROL_DIR}/diferencias_${FECHA}.txt"
|
|
|
|
LOG_FILE="${LOG_DIR}/copia_schema_sn_${FECHA}.log"
|
|
|
|
# El dump nuevo puede variar hasta un 20% respecto
|
|
# del dump validado anterior.
|
|
PORCENTAJE_TOLERANCIA=20
|
|
|
|
# ============================================================
|
|
# PREPARACION
|
|
# ============================================================
|
|
|
|
mkdir -p "$DUMP_DIR" "$LOG_DIR" "$CONTROL_DIR"
|
|
|
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
|
|
|
export PGPASSWORD="$DB_PASSWORD"
|
|
|
|
echo "============================================================"
|
|
echo "Inicio del proceso: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "Origen DEV : $DEV_HOST"
|
|
echo "Destino PROD : $PROD_HOST"
|
|
echo "Base de datos : $DB_NAME"
|
|
echo "Schema : $SCHEMA_NAME"
|
|
echo "Log : $LOG_FILE"
|
|
echo "============================================================"
|
|
|
|
# ============================================================
|
|
# FUNCION PARA CONTAR REGISTROS POR TABLA
|
|
# ============================================================
|
|
|
|
contar_registros()
|
|
{
|
|
HOST="$1"
|
|
ARCHIVO_SALIDA="$2"
|
|
|
|
psql \
|
|
-X \
|
|
-q \
|
|
-h "$HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-v ON_ERROR_STOP=1 \
|
|
-Atc "
|
|
SELECT format(
|
|
'SELECT %L || ''|'' || count(*) FROM %I.%I;',
|
|
tablename,
|
|
schemaname,
|
|
tablename
|
|
)
|
|
FROM pg_tables
|
|
WHERE schemaname = '${SCHEMA_NAME}'
|
|
ORDER BY tablename;
|
|
" |
|
|
psql \
|
|
-X \
|
|
-q \
|
|
-h "$HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-v ON_ERROR_STOP=1 \
|
|
-At |
|
|
sort > "$ARCHIVO_SALIDA"
|
|
}
|
|
|
|
# ============================================================
|
|
# 1. VALIDAR CONECTIVIDAD
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Validando conexión con DEV..."
|
|
|
|
psql \
|
|
-X \
|
|
-h "$DEV_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-v ON_ERROR_STOP=1 \
|
|
-c "SELECT 1;" > /dev/null
|
|
|
|
echo "Conexión con DEV correcta."
|
|
|
|
echo "Validando conexión con PROD..."
|
|
|
|
psql \
|
|
-X \
|
|
-h "$PROD_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-v ON_ERROR_STOP=1 \
|
|
-c "SELECT 1;" > /dev/null
|
|
|
|
echo "Conexión con PROD correcta."
|
|
|
|
# ============================================================
|
|
# 2. GENERAR DUMP DE DEV
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Generando dump del schema $SCHEMA_NAME en DEV..."
|
|
|
|
pg_dump \
|
|
-h "$DEV_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-n "$SCHEMA_NAME" \
|
|
-Fc \
|
|
-f "$DUMP_NUEVO"
|
|
|
|
if [ ! -s "$DUMP_NUEVO" ]; then
|
|
echo "ERROR: el dump no existe o tiene tamaño cero."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Dump generado correctamente:"
|
|
ls -lh "$DUMP_NUEVO"
|
|
|
|
# ============================================================
|
|
# 3. VALIDAR ESTRUCTURA DEL DUMP
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Validando que el dump pueda ser leído por pg_restore..."
|
|
|
|
pg_restore --list "$DUMP_NUEVO" > /dev/null
|
|
|
|
echo "La estructura del dump es válida."
|
|
|
|
# ============================================================
|
|
# 4. COMPARAR TAMAÑO CONTRA EL DUMP VALIDADO ANTERIOR
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Validando tamaño del nuevo dump..."
|
|
|
|
TAMANIO_NUEVO=$(stat -c%s "$DUMP_NUEVO")
|
|
|
|
if [ ! -f "$DUMP_VALIDADO" ]; then
|
|
echo "ERROR: no existe un dump validado anterior:"
|
|
echo "$DUMP_VALIDADO"
|
|
echo
|
|
echo "El nuevo dump fue generado, pero el proceso se detiene antes"
|
|
echo "de modificar PROD."
|
|
echo
|
|
echo "Tamaño del nuevo dump: $TAMANIO_NUEVO bytes"
|
|
exit 1
|
|
fi
|
|
|
|
TAMANIO_ANTERIOR=$(stat -c%s "$DUMP_VALIDADO")
|
|
|
|
TAMANIO_MINIMO=$((TAMANIO_ANTERIOR * (100 - PORCENTAJE_TOLERANCIA) / 100))
|
|
TAMANIO_MAXIMO=$((TAMANIO_ANTERIOR * (100 + PORCENTAJE_TOLERANCIA) / 100))
|
|
|
|
echo "Dump anterior : $TAMANIO_ANTERIOR bytes"
|
|
echo "Dump nuevo : $TAMANIO_NUEVO bytes"
|
|
echo "Tamaño mínimo válido: $TAMANIO_MINIMO bytes"
|
|
echo "Tamaño máximo válido: $TAMANIO_MAXIMO bytes"
|
|
|
|
if [ "$TAMANIO_NUEVO" -lt "$TAMANIO_MINIMO" ]; then
|
|
echo "ERROR: el nuevo dump se encuentra fuera de la tolerancia inferior del 20%."
|
|
echo "No se realizará ninguna modificación en PROD."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$TAMANIO_NUEVO" -gt "$TAMANIO_MAXIMO" ]; then
|
|
echo "ERROR: el nuevo dump supera en más de un 20% al anterior."
|
|
echo "No se realizará ninguna modificación en PROD."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Validación de tamaño correcta."
|
|
echo "El nuevo dump se encuentra dentro de la tolerancia de ±20%."
|
|
|
|
# ============================================================
|
|
# 5. OBTENER CONTEOS DE DEV ANTES DEL RESTORE
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Contando registros por tabla en DEV..."
|
|
|
|
contar_registros "$DEV_HOST" "$CONTROL_DEV"
|
|
|
|
echo "Conteos de DEV guardados en:"
|
|
echo "$CONTROL_DEV"
|
|
|
|
cat "$CONTROL_DEV"
|
|
|
|
# ============================================================
|
|
# 6. GENERAR BACKUP PREVIO DE PROD
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Generando backup preventivo del schema $SCHEMA_NAME en PROD..."
|
|
|
|
pg_dump \
|
|
-h "$PROD_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-n "$SCHEMA_NAME" \
|
|
-Fc \
|
|
-f "$BACKUP_PROD"
|
|
|
|
if [ ! -s "$BACKUP_PROD" ]; then
|
|
echo "ERROR: no se pudo generar el backup preventivo de PROD."
|
|
echo "No se realizará el DROP."
|
|
exit 1
|
|
fi
|
|
|
|
pg_restore --list "$BACKUP_PROD" > /dev/null
|
|
|
|
echo "Backup preventivo de PROD generado y validado:"
|
|
ls -lh "$BACKUP_PROD"
|
|
|
|
# ============================================================
|
|
# 7. CONFIRMACION MANUAL ANTES DEL DROP
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "============================================================"
|
|
echo "ATENCION"
|
|
echo "El dump de DEV fue generado y validado."
|
|
echo "El backup preventivo de PROD fue generado y validado."
|
|
echo
|
|
echo "El siguiente paso eliminará el schema $SCHEMA_NAME en PROD:"
|
|
echo "$PROD_HOST"
|
|
echo "============================================================"
|
|
echo
|
|
|
|
read -r -p "Escriba CONTINUAR para ejecutar el DROP y restore: " CONFIRMACION
|
|
|
|
if [ "$CONFIRMACION" != "CONTINUAR" ]; then
|
|
echo "Proceso cancelado por el operador."
|
|
exit 1
|
|
fi
|
|
|
|
# ============================================================
|
|
# 8. ELIMINAR SCHEMA EN PROD
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Eliminando schema $SCHEMA_NAME en PROD..."
|
|
|
|
psql \
|
|
-X \
|
|
-h "$PROD_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-v ON_ERROR_STOP=1 \
|
|
-c "DROP SCHEMA IF EXISTS ${SCHEMA_NAME} CASCADE;"
|
|
|
|
echo "Schema eliminado."
|
|
|
|
# ============================================================
|
|
# 9. RESTAURAR DUMP EN PROD
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Restaurando dump de DEV en PROD..."
|
|
|
|
if ! pg_restore \
|
|
--exit-on-error \
|
|
--no-owner \
|
|
-h "$PROD_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
"$DUMP_NUEVO"
|
|
then
|
|
echo "ERROR: falló la restauración del dump de DEV."
|
|
echo "Se intentará recuperar el backup previo de PROD."
|
|
|
|
psql \
|
|
-X \
|
|
-h "$PROD_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
-v ON_ERROR_STOP=1 \
|
|
-c "DROP SCHEMA IF EXISTS ${SCHEMA_NAME} CASCADE;"
|
|
|
|
pg_restore \
|
|
--exit-on-error \
|
|
--no-owner \
|
|
-h "$PROD_HOST" \
|
|
-U "$DB_USER" \
|
|
-d "$DB_NAME" \
|
|
"$BACKUP_PROD"
|
|
|
|
echo "Se restauró el backup anterior de PROD."
|
|
exit 1
|
|
fi
|
|
|
|
echo "Restauración finalizada correctamente."
|
|
|
|
# ============================================================
|
|
# 10. CONTAR REGISTROS EN PROD
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Contando registros por tabla en PROD..."
|
|
|
|
contar_registros "$PROD_HOST" "$CONTROL_PROD"
|
|
|
|
echo "Conteos de PROD guardados en:"
|
|
echo "$CONTROL_PROD"
|
|
|
|
cat "$CONTROL_PROD"
|
|
|
|
# ============================================================
|
|
# 11. COMPARAR DEV CONTRA PROD
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "Comparando cantidad de registros por tabla..."
|
|
|
|
if diff -u "$CONTROL_DEV" "$CONTROL_PROD" > "$DIFERENCIAS"; then
|
|
echo "VALIDACION CORRECTA."
|
|
echo "Todas las tablas tienen la misma cantidad de registros."
|
|
rm -f "$DIFERENCIAS"
|
|
VALIDACION_FINAL="CORRECTA"
|
|
else
|
|
echo "ERROR DE VALIDACION."
|
|
echo "Existen diferencias entre DEV y PROD:"
|
|
cat "$DIFERENCIAS"
|
|
VALIDACION_FINAL="CON DIFERENCIAS"
|
|
fi
|
|
|
|
TOTAL_TABLAS_DEV=$(wc -l < "$CONTROL_DEV")
|
|
TOTAL_TABLAS_PROD=$(wc -l < "$CONTROL_PROD")
|
|
|
|
TOTAL_FILAS_DEV=$(
|
|
awk -F'|' '{s += $2} END {print s+0}' "$CONTROL_DEV"
|
|
)
|
|
|
|
TOTAL_FILAS_PROD=$(
|
|
awk -F'|' '{s += $2} END {print s+0}' "$CONTROL_PROD"
|
|
)
|
|
|
|
# ============================================================
|
|
# 12. RESULTADO FINAL
|
|
# ============================================================
|
|
|
|
echo
|
|
echo "============================================================"
|
|
echo "RESULTADO FINAL"
|
|
echo "============================================================"
|
|
echo "Dump utilizado : $DUMP_NUEVO"
|
|
echo "Backup previo de PROD : $BACKUP_PROD"
|
|
echo "Tablas en DEV : $TOTAL_TABLAS_DEV"
|
|
echo "Tablas en PROD : $TOTAL_TABLAS_PROD"
|
|
echo "Total registros DEV : $TOTAL_FILAS_DEV"
|
|
echo "Total registros PROD : $TOTAL_FILAS_PROD"
|
|
echo "Validación final : $VALIDACION_FINAL"
|
|
echo "Log : $LOG_FILE"
|
|
echo "Finalización : $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "============================================================"
|
|
|
|
if [ "$VALIDACION_FINAL" != "CORRECTA" ]; then
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "============================================================"
|
|
echo "PROMOCION MANUAL DEL DUMP VALIDADO"
|
|
echo "============================================================"
|
|
echo
|
|
echo "La restauración y validaciones finalizaron correctamente."
|
|
echo
|
|
echo "El dump utilizado en esta ejecución fue:"
|
|
echo "$DUMP_NUEVO"
|
|
echo
|
|
echo "El dump de referencia actual es:"
|
|
echo "$DUMP_VALIDADO"
|
|
echo
|
|
echo "Luego de revisar los logs y validar la operatoria,"
|
|
echo "ejecutar el siguiente comando para promover el nuevo"
|
|
echo "dump como baseline de referencia:"
|
|
echo
|
|
echo "cp -p \"$DUMP_NUEVO\" \"$DUMP_VALIDADO\""
|
|
echo
|
|
echo "IMPORTANTE:"
|
|
echo "La promoción es una decisión manual del operador."
|
|
echo "Ejecutar únicamente después de revisar los logs,"
|
|
echo "los conteos de registros y el resultado general."
|
|
echo
|
|
echo "============================================================"
|
|
|