Démarrage de la pile par un simple docker compose up
La pile de test de la branche ne démarrait pas : « Connexion à la base impossible ». Trois causes cumulées, toutes corrigées. 1. PTA_DB_PORT et DB_PORT étaient passés à 9306. Ces variables désignent le port joint À L'INTÉRIEUR du réseau Docker, où MariaDB écoute sur 3306, et non un port publié sur l'hôte : la connexion était refusée. Elles reviennent à 3306, et le port hôte 9306 est désormais réellement publié par le service db (sur la boucle locale), pour un client SQL externe. 2. Le service db-migrate manquait sur la branche. Le schéma d'initialisation ne contient aucune des tables et vues d'accès V7.8 : sur un volume neuf, l'application refusait de démarrer. db-migrate applique maintenant tous les database/migration_*.sql, dont celle du tableau de bord V7.9 — plus aucune étape SQL manuelle. 3. Le défaut de PTA_DB_PASS (change_me) différait de celui de MARIADB_PASSWORD (pta). Sans fichier .env — et ce répertoire n'en a pas, il est ignoré par git — l'authentification échouait. Les deux défauts sont alignés. Le bandeau du tableau de bord ne prétend plus que « tous les lieux ont des horaires attendus » quand aucun lieu n'est enregistré. Vérifié : volume détruit puis « docker compose up -d --build » seul suffit à obtenir les onze pages en 200, l'atterrissage sur le tableau de bord et les deux migrations appliquées ; un second up les ignore ; la base répond sur 127.0.0.1:9306 ; la pile principale sur 8080 est restée intacte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
153
docker/db/apply-migrations.sh
Executable file
153
docker/db/apply-migrations.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/bin/sh
|
||||
# ============================================================================
|
||||
# PTA — application automatique des migrations SQL au démarrage de la stack
|
||||
# ============================================================================
|
||||
# Exécuté par le service jetable `db-migrate` du docker-compose, une fois que
|
||||
# MariaDB est déclaré sain. Le service `php` attend la fin de ce script en
|
||||
# succès : si une migration échoue, l'application ne démarre pas du tout.
|
||||
#
|
||||
# Le schéma initial (database/pta_prod_schema_mariadb.sql) reste joué par
|
||||
# docker-entrypoint-initdb.d à la création du volume. Ce script ne traite que
|
||||
# les fichiers `migration_*.sql`, dans l'ordre alphabétique, sur une base déjà
|
||||
# existante comme sur une base fraîchement créée.
|
||||
#
|
||||
# Un registre `schema_migration` mémorise chaque fichier appliqué avec son
|
||||
# empreinte. Un fichier déjà appliqué et inchangé est ignoré ; un fichier
|
||||
# modifié est rejoué — les migrations PTA sont écrites idempotentes
|
||||
# (CREATE TABLE IF NOT EXISTS, INSERT ... ON DUPLICATE KEY UPDATE,
|
||||
# CREATE OR REPLACE VIEW), les rejouer est sans effet de bord.
|
||||
# ============================================================================
|
||||
|
||||
set -eu
|
||||
|
||||
DB_HOST="${DB_HOST:-db}"
|
||||
DB_PORT="${DB_PORT:-3306}"
|
||||
DB_NAME="${DB_NAME:-pta}"
|
||||
DB_USER="${DB_USER:-root}"
|
||||
MIGRATIONS_DIR="${MIGRATIONS_DIR:-/migrations}"
|
||||
|
||||
# Le mot de passe passe par MYSQL_PWD et jamais par la ligne de commande :
|
||||
# un `ps` dans le conteneur ne doit pas le révéler.
|
||||
MYSQL_PWD="${DB_PASSWORD:-}"
|
||||
export MYSQL_PWD
|
||||
|
||||
log() {
|
||||
echo "[pta-migrate] $*"
|
||||
}
|
||||
|
||||
sql() {
|
||||
# --ssl-verify-server-cert=0 : le client MariaDB 11.4 désactive de toute
|
||||
# façon cette vérification quand le mot de passe ne vient pas de la ligne
|
||||
# de commande, en émettant un avertissement trompeur parlant de « login
|
||||
# sans mot de passe ». Le poser explicitement supprime ce bruit dans les
|
||||
# journaux de déploiement sans rien changer au comportement réel : la
|
||||
# liaison reste interne au réseau bridge du compose.
|
||||
mariadb --host="$DB_HOST" --port="$DB_PORT" --user="$DB_USER" \
|
||||
--database="$DB_NAME" --default-character-set=utf8mb4 \
|
||||
--ssl-verify-server-cert=0 "$@"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Attente de la base
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le compose garantit déjà `service_healthy`, mais le healthcheck interroge la
|
||||
# boucle locale du conteneur : cette boucle couvre le court instant où le port
|
||||
# n'accepte pas encore de connexion depuis le réseau.
|
||||
attente=0
|
||||
until sql -N -B -e 'SELECT 1' >/dev/null 2>&1; do
|
||||
attente=$((attente + 1))
|
||||
if [ "$attente" -ge 30 ]; then
|
||||
log "ERREUR : base $DB_NAME injoignable sur $DB_HOST:$DB_PORT après 60 s."
|
||||
exit 1
|
||||
fi
|
||||
log "Base pas encore joignable, nouvelle tentative dans 2 s ($attente/30)…"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
log "Base $DB_NAME joignable sur $DB_HOST:$DB_PORT."
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Registre des migrations appliquées
|
||||
# ----------------------------------------------------------------------------
|
||||
sql <<'SQL'
|
||||
CREATE TABLE IF NOT EXISTS schema_migration (
|
||||
fichier VARCHAR(190) NOT NULL,
|
||||
empreinte CHAR(32) NOT NULL,
|
||||
applique_le DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY (fichier)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
SQL
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Application des migrations
|
||||
# ----------------------------------------------------------------------------
|
||||
applique=0
|
||||
ignore=0
|
||||
|
||||
for fichier in "$MIGRATIONS_DIR"/migration_*.sql; do
|
||||
# Le glob non résolu se présente tel quel quand aucun fichier ne correspond.
|
||||
[ -f "$fichier" ] || continue
|
||||
|
||||
nom=$(basename "$fichier")
|
||||
empreinte=$(md5sum < "$fichier" | cut -d' ' -f1)
|
||||
connue=$(sql -N -B -e \
|
||||
"SELECT empreinte FROM schema_migration WHERE fichier = '$nom'")
|
||||
|
||||
if [ "$connue" = "$empreinte" ]; then
|
||||
log "$nom : déjà appliquée, ignorée."
|
||||
ignore=$((ignore + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -n "$connue" ]; then
|
||||
log "$nom : contenu modifié depuis la dernière application, rejeu."
|
||||
else
|
||||
log "$nom : application…"
|
||||
fi
|
||||
|
||||
if ! sql < "$fichier"; then
|
||||
log "ERREUR : échec de $nom. L'application ne sera pas démarrée."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sql -e "INSERT INTO schema_migration (fichier, empreinte)
|
||||
VALUES ('$nom', '$empreinte')
|
||||
ON DUPLICATE KEY UPDATE empreinte = VALUES(empreinte),
|
||||
applique_le = CURRENT_TIMESTAMP"
|
||||
|
||||
log "$nom : appliquée."
|
||||
applique=$((applique + 1))
|
||||
done
|
||||
|
||||
log "Bilan : $applique migration(s) appliquée(s), $ignore ignorée(s)."
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Contrôle final : les vues de droits doivent exister
|
||||
# ----------------------------------------------------------------------------
|
||||
# Même contrôle que SchemaModel::assertAccessViews() côté PHP. Le faire ici
|
||||
# évite de laisser démarrer une pile dont la page d'accueil renverrait une
|
||||
# erreur 500 incompréhensible.
|
||||
manquantes=$(sql -N -B -e "
|
||||
SELECT GROUP_CONCAT(attendue.nom ORDER BY attendue.nom SEPARATOR ', ')
|
||||
FROM (
|
||||
SELECT 'v_acces_role_page' AS nom
|
||||
UNION ALL SELECT 'v_acces_role_permission'
|
||||
UNION ALL SELECT 'v_acces_identite_agent'
|
||||
UNION ALL SELECT 'v_acces_identite_structure'
|
||||
UNION ALL SELECT 'v_acces_agent_par_structure'
|
||||
UNION ALL SELECT 'v_acces_perimetre_creneau'
|
||||
UNION ALL SELECT 'v_acces_perimetre_planning'
|
||||
) AS attendue
|
||||
LEFT JOIN information_schema.VIEWS v
|
||||
ON v.TABLE_SCHEMA = DATABASE()
|
||||
AND v.TABLE_NAME = attendue.nom
|
||||
WHERE v.TABLE_NAME IS NULL")
|
||||
|
||||
if [ -n "$manquantes" ] && [ "$manquantes" != "NULL" ]; then
|
||||
log "ERREUR : vue(s) de contrôle d'accès manquante(s) : $manquantes"
|
||||
log "La migration v7.8 n'a pas produit le résultat attendu."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Les sept vues de contrôle d'accès sont présentes. Base à jour."
|
||||
Reference in New Issue
Block a user