Files
feadulta/scripts/cutover/03-importar.sh
rafa 65359338f8 cutover: los scripts con los que se ejecuto, y lo que quedo pendiente
Cutover hecho el 3-ago a las 10:50 UTC. feadulta.com y www.feadulta.com ya
apuntan a 188.40.120.157, proxied. Ventana real ~3 min 10 s: dump 67 s, saneo
2 s, import 114 s, delta de uploads 6 s (0 ficheros, como estaba medido).

Cuadro al digito con produccion: 43.893 posts, 1.228 usuarios, 4.416 terms,
135.959 postmeta. Los options salen 958 frente a 975 porque son transients (hay
580 y caducan solos). Con trafico real: 581 respuestas 200, 62 301, 16 302, cero
5xx y cero errores PHP en 20 minutos, 61 IPs distintas atendidas.

Se anaden los cuatro scripts que faltaban, que hasta hoy solo existian como
comandos sueltos del ensayo: 01-traer-dump, 02-sanear-dump, 03-importar,
04-delta-uploads y 05-mover-dns. El runbook ya los citaba por nombre.

Tres cosas encontradas al ejecutar, anotadas en los propios scripts:

- docker exec -i dentro de un ssh 'bash -s' <<EOF se come el resto del script,
  porque hereda el stdin del heredoc. Las consultas van sin -i y con </dev/null.
- Smart Slider cachea el HTML del slider con URLs absolutas, una fila por idioma
  en wp_nextend2_section_storage con application='cache'. Al verificar el import
  con la constante del staging todavia puesta quedaron 5 filas apuntando a
  nuevo.feadulta.com. Se borran y se regeneran solas.
- El cliente de MariaDB de la jaula de CDMON exige TLS y el servidor local no lo
  tiene: con --skip-ssl si se puede consultar la BD de produccion directamente,
  que es como se comprobo que no habia cambiado nada desde el dump de las 05:09.

Pendiente y fuera de nuestro alcance: purgar la cache de Cloudflare (el token
solo tiene permiso de DNS) y darle a Inma su contrasena nueva. Y los certificados
de Let's Encrypt para www y el apex, que fallan porque el WAF de Cloudflare
devuelve 403 a la validacion; no bloquea mientras la zona este en Full, pero por
eso mismo no se puede subir a Full (strict) todavia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 07:00:38 -04:00

55 lines
2.6 KiB
Bash
Executable File

#!/bin/bash
#
# Paso 4 del cutover: importar el dump saneado en MySQL 8.4.
#
# --default-character-set=utf8mb4 EN EL CLIENTE es obligatorio: omitirlo es lo que
# produjo el mojibake de summaraise. El dump trae DROP TABLE IF EXISTS en las 29
# tablas, asi que no hace falta vaciar la BD antes.
#
set -euo pipefail
ssh -o BatchMode=yes root@188.40.120.157 'bash -s' <<'EOF'
set -euo pipefail
U=r2ssjifwj0r0ghyoqd528uaa
cd /data/feadulta-migracion
RP=$(docker inspect mysql-$U --format '{{range .Config.Env}}{{println .}}{{end}}' | sed -n 's/^MYSQL_ROOT_PASSWORD=//p')
# OJO: sin -i y con </dev/null. Este script llega por el stdin del ssh, y un
# "docker exec -i" sin redirigir se come el resto del script.
m() { docker exec mysql-$U mysql --default-character-set=utf8mb4 -uroot -p"$RP" -N -B -e "$1" wordpress 2>/dev/null </dev/null; }
echo "== antes del import:"
m "SELECT CONCAT(' tablas: ', COUNT(*)) FROM information_schema.tables WHERE table_schema='wordpress';"
echo "== importando..."
T0=$(date +%s)
docker exec -i mysql-$U mysql --default-character-set=utf8mb4 -uroot -p"$RP" wordpress < feadulta-saneado.sql
T1=$(date +%s)
echo " import: $((T1-T0))s"
echo ""
echo "== recuentos en destino (comparar con produccion):"
m "SELECT 'tablas', COUNT(*) FROM information_schema.tables WHERE table_schema='wordpress'
UNION ALL SELECT 'posts', COUNT(*) FROM wp_posts
UNION ALL SELECT 'users', COUNT(*) FROM wp_users
UNION ALL SELECT 'options', COUNT(*) FROM wp_options
UNION ALL SELECT 'terms', COUNT(*) FROM wp_terms
UNION ALL SELECT 'postmeta', COUNT(*) FROM wp_postmeta;" | sed 's/^/ /'
echo ""
echo "== charset/collation de las tablas (no debe quedar nada raro):"
m "SELECT table_collation, COUNT(*) FROM information_schema.tables WHERE table_schema='wordpress' GROUP BY table_collation;" | sed 's/^/ /'
echo ""
echo "== indice FULLTEXT del buscador:"
m "SELECT index_name, COUNT(*) FROM information_schema.statistics WHERE table_schema='wordpress' AND index_type='FULLTEXT' GROUP BY index_name;" | sed 's/^/ /'
echo ""
echo "== acentos y tipografia (mojibake = 0):"
m "SELECT 'con  raro', COUNT(*) FROM wp_posts WHERE post_title COLLATE utf8mb4_bin LIKE '%Ã%' AND post_title COLLATE utf8mb4_bin NOT LIKE '%ÃÂ%'
UNION ALL SELECT '’ (mojibake real)', COUNT(*) FROM wp_posts WHERE post_content COLLATE utf8mb4_bin LIKE '%’%'
UNION ALL SELECT '© mojibake', COUNT(*) FROM wp_posts WHERE post_content COLLATE utf8mb4_bin LIKE '%Â%';" | sed 's/^/ /'
echo ""
echo "== siteurl / home que trae el dump:"
m "SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl','home');" | sed 's/^/ /'
EOF