Project

General

Profile

Tareas #137 » copiar_schema_sn_de_dev_a_prd.sh

Demo MiGestion365 Admin, 09/23/2026 12:32 PM

 
#!/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 "============================================================"

(1-1/2)