Commit 7caa2ede authored by Kourser's avatar Kourser
Browse files

Repartir à neuf, sans avoir à deviner le nom des volumes

L'installateur savait reprendre une instance existante et refusait de la
casser. Il ne savait pas l'effacer. Or on veut parfois repartir de zéro — un
essai qu'on refait, une machine qu'on recycle — et le faire à la main demande
de connaître « down -v », les deux profils, et le nom des quatre volumes. Ne
pas l'outiller ne protège personne : ça pousse à improviser des « docker
volume rm » un par un, ce qui est plus dangereux que de le proposer.

Ce qu'il montre avant de demander
  Les conteneurs du projet avec leur état, les volumes, et la présence d'un
  .env. Trois choix : reprendre — le défaut, et le cas ordinaire —, tout
  effacer, ou ne rien faire.

Ce qui garde la porte
  L'effacement emporte le journal de la main courante, et le journal est le
  produit : il refuse toute modification, et c'est précisément pourquoi rien
  ne le ramènera. Le script le dit dans ces termes, énumère ce qui meurt, et
  donne la commande de sauvegarde AVANT de demander confirmation — après, elle
  ne servirait plus à rien.

  La confirmation n'est pas un « o » : il faut frapper le nom du projet.
  Toute autre saisie, y compris une entrée vide, abandonne sans rien toucher.

  Les images ne sont pas effacées. Elles se reconstruisent seules, et les
  perdre ne coûterait que du temps — l'effacement doit viser les données, pas
  le confort.

Deux détails qui décident si l'effacement est complet
  Les profils « mobile » et « complet » sont nommés explicitement : sans eux
  le relais survivrait à un nettoyage qui se croit entier.

  Un balayage des volumes du projet suit le « down -v », parce que celui-ci ne
  connaît que les volumes déclarés : un volume laissé par une version
  antérieure de la composition resterait sinon en place, invisible et prêt à
  rendre le prochain démarrage incompréhensible.

  Le .env n'est pas détruit mais déplacé en .env.sauvegarde-* : il porte des
  secrets qui viennent d'ailleurs — la clé d'Apple notamment — et « repartir à
  neuf » n'est pas « perdre ses clés ». Le motif est déjà couvert par
  .gitignore.

Contrôlé
  Sur un projet isolé, avec des volumes leurres : refus de confirmation qui
  laisse tout en place, confirmation correcte qui efface et enchaîne sur une
  installation vierge, « ne rien faire » qui sort sans toucher au .env, et
  « reprendre » qui redonne la main aux deux dialogues existants — celui du
  .env, puis celui de la base déjà initialisée. En français et en anglais. Le
  projet voisin, ses quatre volumes et ses sept conteneurs n'ont pas bougé.

Co-Authored-By: default avatarClaude Opus 5 <noreply@anthropic.com>
parent b73cc10a
Loading
Loading
Loading
Loading
Loading
+145 −0
Changes for outils/installer.sh: 145 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -370,6 +370,151 @@ projet="$(sed -n 's/^name:[[:space:]]*//p' "$COMPOSE" | head -n 1)"
[ -n "$projet" ] || projet="kastell"
volume_base="${projet}_base"

conteneurs_projet() {
  docker ps -a --filter "label=com.docker.compose.project=$projet" \
              --format '{{.Names}} ({{.State}})' 2>/dev/null
}

volumes_projet() {
  docker volume ls -q -f "name=^${projet}_" 2>/dev/null
}

# ── Une instance déjà là ───────────────────────────────────────────────────
#
# Reprendre une instance existante est le cas ordinaire, et reste le défaut.
# Mais il arrive qu'on veuille repartir de zéro — un essai qu'on refait, une
# machine qu'on recycle — et le faire à la main demande de connaître « down -v »
# et le nom des volumes. Ne pas le proposer pousse à improviser des « docker
# volume rm » un à un, ce qui est plus dangereux que de l'outiller.
#
# Ce que l'effacement emporte n'est pas rattrapable : le volume de base porte
# le journal, et le journal est le produit. D'où la confirmation par frappe du
# nom du projet, et la commande de sauvegarde donnée avant, pas après.

conteneurs="$(conteneurs_projet)"
volumes="$(volumes_projet)"

if [ -n "$conteneurs" ] || [ -n "$volumes" ] || [ -f .env ]; then
  echo
  dire "── Une instance est déjà là ───────────────────────────────────────────" \
       "── An instance is already here ───────────────────────────────────────"
  echo
  if [ -n "$conteneurs" ]; then
    dire "  Conteneurs :" "  Containers:"
    echo "$conteneurs" | sed 's/^/      /'
  fi
  if [ -n "$volumes" ]; then
    dire "  Volumes :" "  Volumes:"
    echo "$volumes" | sed 's/^/      /'
  fi
  if [ -f .env ]; then
    dire "  Fichier    : .env" "  File       : .env"
  fi
  echo
  dire "    1) Reprendre cette instance" \
       "    1) Keep this instance"
  dire "    2) Tout effacer et repartir à neuf" \
       "    2) Erase everything and start fresh"
  dire "    3) Ne rien faire" \
       "    3) Do nothing"
  echo
  demander_b "Votre choix" "Your choice" "1"

  case "$REPONSE" in
    2)
      echo
      dire "  ⚠  Ceci détruit définitivement :" \
           "  ⚠  This permanently destroys:"
      echo
      dire "       le journal de la main courante, dans « $volume_base »" \
           "       the incident log, in \"$volume_base\""
      dire "       les documents déposés, le cache, les signatures antivirales" \
           "       uploaded documents, the cache, the antivirus signatures"
      dire "       les conteneurs de ce projet" \
           "       this project's containers"
      echo
      dire "     Le journal est ce que Kastell existe pour tenir : il se refuse" \
           "     The log is what Kastell exists to keep: it refuses to be"
      dire "     à toute modification, et c'est justement pourquoi rien ne le" \
           "     modified at all, and that is exactly why nothing will bring it"
      dire "     ramènera. Pour en garder une copie, avant d'aller plus loin :" \
           "     back. To keep a copy, before going any further:"
      echo
      echo "       docker compose -f $COMPOSE --env-file .env exec -T postgres \\"
      echo "         pg_dumpall -U \"\$POSTGRES_USER\" > kastell-$(date '+%Y%m%d-%H%M%S').sql"
      echo
      dire "     Les images construites ne sont pas touchées : elles se" \
           "     Built images are left alone: they rebuild on their own, and"
      dire "     reconstruisent seules, et les effacer ne coûterait que du temps." \
           "     erasing them would only cost time."
      echo
      dire "  Tapez le nom du projet pour confirmer, ou toute autre chose pour" \
           "  Type the project name to confirm, or anything else to abandon"
      dire "  abandonner l'effacement." \
           "  the erasure."
      echo
      demander_b "Nom du projet" "Project name" ""
      if [ "$REPONSE" != "$projet" ]; then
        echo
        dire "  Rien n'a été effacé." "  Nothing has been erased."
        exit 0
      fi

      # Les deux profils sont nommés : sans eux, le relais survivrait à un
      # effacement qui se croit complet.
      set -- -f "$COMPOSE"
      [ -f .env ] && set -- "$@" --env-file .env
      set -- "$@" --profile mobile --profile complet
      echo
      if ! docker compose "$@" down -v --remove-orphans; then
        echo
        dire_err "✗ L'effacement a échoué. Rien n'a été supposé de la suite :" \
                 "✗ The erasure failed. Nothing further has been assumed:"
        dire_err "  l'instance est peut-être partiellement démontée." \
                 "  the instance may be partly torn down."
        exit 1
      fi

      # « down -v » ne connaît que les volumes déclarés : un volume laissé par
      # une version antérieure de la composition resterait sinon en place.
      for v in $(volumes_projet); do
        docker volume rm "$v" > /dev/null 2>&1 || true
      done

      # Le .env part aussi, mais à la corbeille plutôt qu'au feu : il porte des
      # secrets, et « repartir à neuf » n'est pas « perdre ses clés APNS ».
      if [ -f .env ]; then
        sauvegarde=".env.sauvegarde-$(date '+%Y%m%d-%H%M%S')"
        mv .env "$sauvegarde"
        echo
        dire "  ✓ .env déplacé vers $sauvegarde — il porte peut-être des" \
             "  ✓ .env moved to $sauvegarde — it may carry secrets that come"
        dire "    secrets qui viennent d'ailleurs, la clé d'Apple notamment." \
             "    from elsewhere, Apple's key in particular."
      fi
      rm -f docker/livekit.local.yaml

      restants="$(volumes_projet)"
      echo
      if [ -n "$restants" ]; then
        dire "  ⚠  Volumes encore présents :" "  ⚠  Volumes still present:"
        echo "$restants" | sed 's/^/       /'
      else
        dire "  ✓ Tout est effacé. L'installation repart de zéro." \
             "  ✓ Everything is erased. The install starts from nothing."
      fi
      ;;

    1) ;;

    *)
      echo
      dire "  Rien n'a été modifié." "  Nothing has been changed."
      exit 0
      ;;
  esac
fi

base_existe="non"
if docker volume inspect "$volume_base" > /dev/null 2>&1; then
  base_existe="oui"