Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Déboguer Terragrunt : cache, chemins relatifs, hooks et logs

Par mis à jour le

Améliorer cette page

Quand un terragrunt apply échoue, commencez par savoir où Terragrunt travaille réellement : terragrunt info print donne le dossier d'exécution, .terragrunt-cache contient la copie de travail et le state local, et --log-level debug montre les étapes. Cette leçon donne une méthode de diagnostic en cinq outils : le cache, info print, les logs, les chemins relatifs et les hooks. Elle a été rejouée avec Terragrunt 1.1.6 et OpenTofu 1.13.1, sur un unit unique pour isoler chaque mécanisme.

  • Expliquer le rôle de .terragrunt-cache et pourquoi on n'y exécute pas depuis le dossier source
  • Lire le contexte réel d'exécution avec terragrunt info print
  • Régler --log-level et --log-format sans modifier le code
  • Ancrer les chemins relatifs sur des repères stables
  • Écrire un before_hook, un after_hook et un error_hook
  • Vider le cache dans le bon ordre, sans laisser de ressources orphelines

Un seul unit, app, qui écrit un fichier hello.txt avec le module write-file. Un unit est un dossier qui contient un terragrunt.hcl et pilote un module Terraform ou OpenTofu. Ici, aucun backend distant n'est configuré, ce qui compte pour la suite : le state sera local.

  • Répertoirelab-debug/
    • Répertoiremodules/
      • Répertoirewrite-file/
        • main.tf
    • Répertoirelive/
      • Répertoiredev/
        • Répertoireapp/
          • terragrunt.hcl

Fichier modules/write-file/main.tf :

terraform {
required_version = ">= 1.6.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
variable "filename" {
type = string
}
variable "content" {
type = string
}
resource "local_file" "this" {
filename = var.filename
content = var.content
}

Fichier live/dev/app/terragrunt.hcl :

terraform {
source = "../../../modules/write-file"
}
inputs = {
filename = "${get_terragrunt_dir()}/hello.txt"
content = "hello from lab a"
}

Placez-vous dans live/dev/app et lancez un apply. Sur un unit seul, --non-interactive supprime les questions de Terragrunt, mais pas la confirmation d'OpenTofu : il faut y ajouter -auto-approve.

Fenêtre de terminal
terragrunt --non-interactive apply -auto-approve

Le résultat est double : hello.txt apparaît dans le dossier du unit et un dossier .terragrunt-cache apparaît à côté de terragrunt.hcl. Terragrunt n'exécute pas le moteur depuis votre dossier source : il prépare un répertoire de travail intermédiaire dans ce cache.

terragrunt info print affiche, sans rien exécuter, le contexte réel de l'exécution : c'est le premier diagnostic à lancer. La sortie est un objet JSON à six clés.

CléContenu
config_pathLe terragrunt.hcl chargé
download_dirLe chemin de .terragrunt-cache
working_dirLe dossier réel depuis lequel le module s'exécute
iam_roleLe rôle IAM configuré, s'il y en a un
terraform_binaryLe moteur utilisé (tofu ou terraform)
terraform_commandLa commande en cours (print ici)

Retenez surtout working_dir : il répond à la question « où mon module s'exécute-t-il vraiment ? », que le dossier visible dans le dépôt ne permet pas de deviner.

Le cache n'est pas du bruit : c'est le lieu concret de l'exécution. Listez-le sur trois niveaux :

Fenêtre de terminal
find .terragrunt-cache -maxdepth 3 | sort

Vous y retrouvez la copie du module (main.tf), le terragrunt.hcl, les dossiers .terraform et .terraform.lock.hcl, les manifestes Terragrunt (.terragrunt-module-manifest, .terragrunt-source-manifest, .terragrunt-source-version) et, sans backend distant, le state local terraform.tfstate.

Cette présence du state a une conséquence directe : vider le cache supprime le state. Sans remote_state, un unit dont on a effacé le cache ne sait plus qu'il a créé ses ressources.

Le listing peut contenir aussi hello.txt, alors que le fichier est créé dans le dossier du unit (get_terragrunt_dir()). C'est une recopie : rejoué, un find .terragrunt-cache -name hello.txt ne trouve rien juste après le premier apply, puis trouve le fichier après la commande suivante (plan). Terragrunt recopie à chaque exécution le contenu du dossier du unit dans le cache ; la copie est identique à l'original (cmp ne signale aucune différence) mais c'est un autre fichier. Le vrai fichier reste celui du dossier du unit.

Le niveau et le format des logs se règlent sans toucher au code. Pour enrichir le diagnostic, lancez :

Fenêtre de terminal
terragrunt --log-level debug info print

La sortie de debug montre la version de Terragrunt, la détection du moteur (tofu version: 1.13.1), la ligne Reading Terragrunt config file at ./terragrunt.hcl et le moment où Setting working directory to ./.terragrunt-cache/<h1>/<h2>. Commencer par info print en debug permet de voir le contexte sans lancer un apply de plus.

Les valeurs acceptées ont été toutes vérifiées. Une valeur inconnue (verbose, bidule) est rejetée avec le code 1.

OptionValeurs acceptées
--log-levelstderr, stdout, error, warn, info, debug, trace
--log-formatkey-value, bare, pretty, json

Le format key-value donne time=... level=debug msg=..., le format json un objet par ligne ({"time":...,"level":"debug","working-dir":...,"msg":...}) et bare des lignes de la forme DEBU[0000] .... Pour un format sur mesure, --log-custom-format '%level %msg' produit par exemple debug Terragrunt Version: 1.1.6. La variable TG_LOG_LEVEL=debug est équivalente à l'option.

Le module s'exécute depuis le répertoire de travail du cache, pas depuis le dossier visible. Un chemin relatif écrit en supposant un autre dossier courant vise donc le mauvais emplacement. C'est la raison d'être de cette ligne :

filename = "${get_terragrunt_dir()}/hello.txt"

get_terragrunt_dir() ancre le chemin sur le dossier du unit. Pour les sources de modules et les fichiers racine, partez de repères stables plutôt que de « là où la commande est lancée » : get_terragrunt_dir() pour le dossier du unit, find_in_parent_folders("root.hcl") pour retrouver une racine connue.

Un hook est une commande que Terragrunt exécute autour du moteur. Il se déclare dans le bloc terraform du unit. Trois types existent : before_hook (avant le moteur), after_hook (après) et error_hook (quand une erreur correspond à un motif).

Le before_hook s'exécute avant tofu apply. Si le moteur réussit, l'after_hook s'exécute. Si le moteur échoue, l'after_hook s'exécute d'abord si run_on_error vaut true, puis l'error_hook s'exécute quand l'erreur correspond à on_errors.before_hookavant le moteurtofu applyafter_hookaprès le moteursuccèséchec, si run_on_error = trueerror_hooksi l'erreur correspond à on_errorséchecpuis, si l'erreur correspond
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

Le schéma se lit de gauche à droite : le trait épais est le chemin de succès, les traits fins le chemin d'échec. Un after_hook ne s'exécute après un échec que si run_on_error = true. Pour voir les trois hooks agir, il faut une erreur provoquée à la demande, sinon l'error_hook ne se déclenche jamais. Ajoutez d'abord à la fin de modules/write-file/main.tf une variable fail et une precondition, un contrôle que le moteur évalue avant de créer la ressource :

variable "fail" {
type = bool
default = false
}
resource "terraform_data" "garde_fou" {
lifecycle {
precondition {
condition = !var.fail
error_message = "Expected failure: la variable fail vaut true"
}
}
}

La condition doit citer un objet de la configuration (ici var.fail). Avec condition = false, OpenTofu refuse le module dès init (Invalid precondition expression) et aucun hook ne s'exécute. Ensuite, remplacez le bloc terraform du terragrunt.hcl du unit par le suivant : il reprend le source et ajoute les trois hooks.

terraform {
source = "../../../modules/write-file"
before_hook "avant" {
commands = ["apply", "plan"]
execute = ["echo", "HOOK-AVANT dans ${get_terragrunt_dir()}"]
}
after_hook "apres" {
commands = ["apply"]
execute = ["echo", "HOOK-APRES"]
run_on_error = true
}
error_hook "erreur" {
commands = ["apply"]
execute = ["echo", "HOOK-ERREUR"]
on_errors = [".*Expected failure.*"]
}
}

Au rejeu, le before_hook affiche Executing hook: avant puis HOOK-AVANT dans <dossier du unit> avant le moteur, et l'after_hook affiche Executing hook: apres puis HOOK-APRES. Pour provoquer l'échec, lancez TF_VAR_fail=true terragrunt --non-interactive apply -auto-approve. Quand tofu apply échoue, l'ordre observé est avant, puis apres, puis erreur : l'after_hook à run_on_error = true passe avant l'error_hook, qui n'affiche HOOK-ERREUR que si le message d'erreur correspond à on_errors. Avec une autre erreur, seul HOOK-APRES s'affiche. Avec run_on_error = false, l'after_hook est sauté et l'error_hook s'exécute quand même. Dans tous les cas, le code de retour 1 est conservé : un hook ne masque pas l'échec.

Les hooks entourent la commande tofu apply, pas l'initialisation. Si tofu init échoue (erreur de syntaxe HCL dans le module, par exemple), aucun hook ne s'exécute, pas même avant, et la commande rend le code 1. Pour voir les trois messages, il faut une erreur qui survient pendant apply, comme la precondition ajoutée plus haut, dont le message contient Expected failure.

L'option --no-hooks n'est pas globale : elle s'écrit sur run (terragrunt run --no-hooks -- plan) et exige l'expérience optional-hooks (--experiment optional-hooks), sans quoi elle échoue avec le code 1.

Pour déboguer un hook, vérifiez d'abord le working_dir avec info print, activez --log-level debug, utilisez des chemins ancrés par get_terragrunt_dir() et faites afficher les erreurs clairement.

Pour repartir proprement, le cache se supprime avec une commande simple :

Fenêtre de terminal
find . -type d -name '.terragrunt-cache' -prune -exec rm -rf {} +

Mais l'ordre compte. Sans backend distant, le state vit dans le cache : si vous le videz avant d'arrêter le unit, la destruction ne trouve plus rien à détruire. Rejoué dans cet ordre, destroy répond Destroy complete! Resources: 0 destroyed, code 0, alors que hello.txt et .terraform.lock.hcl restent sur le disque ; un nouvel apply recrée alors la ressource (1 added). Dans le bon ordre (appliquer, arrêter, puis vider le cache), destroy rend Resources: 1 destroyed (2 avec le garde-fou de la section sur les hooks) et hello.txt disparaît.

  1. Appliquer le unit

    Fenêtre de terminal
    terragrunt --non-interactive apply -auto-approve

    Vérification : hello.txt et .terragrunt-cache existent.

  2. Afficher le contexte Terragrunt

    Fenêtre de terminal
    terragrunt info print

    Vérification : la sortie contient config_path, download_dir et working_dir.

  3. Activer les logs de debug

    Fenêtre de terminal
    terragrunt --log-level debug info print

    Vérification : vous voyez la lecture du terragrunt.hcl et la définition du working directory.

  4. Lister le cache

    Fenêtre de terminal
    find .terragrunt-cache -maxdepth 3 | sort

    Vérification : terraform.tfstate figure dans la liste.

  5. Ajouter le garde-fou et les hooks, puis appliquer

    Ajoutez la variable fail et la precondition à modules/write-file/main.tf, remplacez le bloc terraform du unit par celui des trois hooks, puis lancez :

    Fenêtre de terminal
    terragrunt --non-interactive apply -auto-approve

    Vérification : les lignes Executing hook: avant, HOOK-AVANT dans ..., Apply complete! Resources: 1 added, Executing hook: apres, HOOK-APRES apparaissent dans cet ordre, code 0.

  6. Provoquer l'échec pour voir erreur

    Fenêtre de terminal
    TF_VAR_fail=true terragrunt --non-interactive apply -auto-approve

    Vérification : Error: Resource precondition failed et Expected failure: la variable fail vaut true, avec Executing hook: avant, puis apres (HOOK-APRES), puis erreur (HOOK-ERREUR), et le code de retour 1.

  7. Arrêter le unit, puis seulement ensuite vider le cache

    Fenêtre de terminal
    terragrunt run --all --non-interactive -- destroy
    find . -type d -name '.terragrunt-cache' -prune -exec rm -rf {} +

    Vérification : Destroy complete! Resources: 2 destroyed (le fichier et le garde-fou), hello.txt disparaît, puis le cache est supprimé. Cette forme run --all est celle qui a été rejouée. La forme sur un unit seul avec l'approbation automatique n'a pas été rejouée telle quelle (l'environnement de test ne permettait pas de l'exécuter), et --non-interactive n'ajoute pas cette approbation sur un unit seul.

SymptômeCause probableSolution
Le module semble s'exécuter dans un dossier incompréhensibleTerragrunt travaille dans .terragrunt-cacheLancer terragrunt info print
Un chemin relatif fonctionne malLe chemin suppose un mauvais dossier courantRepartir de get_terragrunt_dir() ou d'une racine stable
destroy détruit 0 ressource alors que hello.txt existeCache vidé avant l'arrêt, donc state local perduDétruire d'abord, vider le cache ensuite
Les logs sont trop pauvresNiveau par défaut trop basRelancer avec --log-level debug
--no-hooks rend le code 1L'expérience optional-hooks n'est pas activéeAjouter --experiment optional-hooks, sur run
  • .terragrunt-cache est le lieu d'exécution ; sans backend distant, il contient aussi le state.
  • terragrunt info print donne six clés, dont working_dir : c'est le premier diagnostic.
  • --log-level accepte stderr à trace, --log-format key-value, bare, pretty ou json.
  • Un hook s'écrit en before_hook, after_hook (avec run_on_error) ou error_hook, et ne masque pas le code de retour.
  • Détruisez le unit avant de vider le cache quand le state est local.

Six questions tirées sur huit : le rôle du cache, info print, les valeurs de --log-level, les hooks et l'ordre destroy puis nettoyage.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn