
Une expression calcule une valeur : une interpolation, un opérateur, un
ternaire, une référence. C'est le tissu de toute configuration Terraform. Le
déclarer est simple ; les pièges se cachent dans les détails : la syntaxe de
référence d'une ressource, la conversion de types (présente pour
l'arithmétique, absente pour l'égalité), et la valeur null qu'on remplace à
tort par une chaîne vide.
Ce guide part de la base, où vivent les expressions et comment les tester, puis
traite les références, les types et leur conversion, null, la précédence des
opérateurs et les valeurs inconnues au plan. Tous les comportements ont été
vérifiés sur Terraform v1.15.4 dans terraform console.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Où vivent les expressions, et tester avec
terraform console - La référence d'une ressource gérée, sans préfixe
- La conversion automatique de types, et l'exception de
== nullcomme absence, pas comme chaîne vide- La précédence des opérateurs, et les valeurs inconnues au plan
Prérequis
Section intitulée « Prérequis »- Un projet Terraform initialisé (installer Terraform)
- Terraform 1.15.x, la série stable courante
Tester une expression avec terraform console
Section intitulée « Tester une expression avec terraform console »terraform console évalue une expression sans rien appliquer. Il est
interactif, mais s'utilise aussi en script, en lui passant des commandes sur
l'entrée standard, ce qui en fait un vrai outil de test et de CI :
echo 'max(3, 7, 2)' | terraform console7L'option -plan évalue même les expressions contre l'état planifié. C'est le
moyen le plus rapide de vérifier une expression avant de l'écrire dans une
ressource.
Référencer une ressource : sans préfixe
Section intitulée « Référencer une ressource : sans préfixe »Les valeurs nommées ont chacune leur préfixe : var.nom, local.nom,
data.<type>.<nom>.<attribut>, module.<nom>.<sortie>, auxquels s'ajoutent
each.key / each.value, count.index, path.module / path.root et
terraform.workspace. Mais une ressource gérée fait exception : elle se
référence SANS préfixe, par <type>.<nom>.<attribut> :
resource "random_string" "jeton" { length = 8}
output "valeur" { value = random_string.jeton.result}Écrire resource.random_string.jeton.result est une erreur : le mot
resource n'apparaît jamais dans une expression. C'est le seul cas de la liste
sans préfixe, et la confusion la plus fréquente des débutants.
Types et conversion automatique
Section intitulée « Types et conversion automatique »Terraform a trois types primitifs (string, number, bool) et des types
complexes (list, set, tuple, map, object). Entre primitifs, il
convertit automatiquement quand il le peut, notamment pour l'arithmétique :
> "5" + 38La chaîne "5" devient un nombre. Mais l'égalité ne convertit pas, et c'est
la règle qui surprend le plus :
> 1 == "1"falseLe nombre 1 et la chaîne "1" ne sont pas égaux. La documentation est
nette : « Automatic type conversion does not occur when using the equality
operator. » Elle recommande de n'employer == et != qu'entre types
identiques, ou après une conversion explicite (tostring(), tonumber()).
null : l'absence, pas la chaîne vide
Section intitulée « null : l'absence, pas la chaîne vide »null représente l'absence d'une valeur. Affecter null à un argument de
ressource revient à ne pas l'écrire du tout : Terraform applique alors le
défaut du provider. La documentation le dit : « If you set an argument of a
resource to null, Terraform behaves as though you had completely omitted it. »
resource "local_file" "exemple" { filename = "exemple.txt" content = "x" file_permission = var.perm != "" ? var.perm : null}Quand var.perm est vide, l'argument vaut null et la permission retombe sur le
défaut du provider. Écrire une chaîne vide "" à la place serait une valeur
bien réelle, souvent invalide, pas une omission. C'est le mécanisme standard
pour rendre un argument optionnel, et le piège classique de la chaîne vide
employée à sa place.
Opérateurs et précédence
Section intitulée « Opérateurs et précédence »Les opérateurs suivent une précédence classique : l'unaire (!, -), puis
* / %, puis + -, puis les comparaisons, puis &&, puis ||. Le
multiplicatif passe avant l'additif :
> 1 + 2 * 371 + 2 * 3 se lit 1 + (2 * 3), soit 7, jamais 9. En cas de doute, les
parenthèses lèvent l'ambiguïté et documentent l'intention.
Une valeur peut être inconnue au plan
Section intitulée « Une valeur peut être inconnue au plan »Enfin, une expression qui dépend d'un attribut pas encore créé vaut
(known after apply). Cette inconnue se propage : une valeur connue
combinée à une valeur inconnue donne une valeur inconnue. Trois conséquences
concrètes : un count ne peut pas dépendre d'un attribut de ressource, la
lecture d'une data source peut être reportée à l'apply, et certains outputs
n'ont leur valeur qu'après l'apply. C'est le sujet le plus discriminant du
niveau Professional.
Les quatre familles d'expressions et leurs guides
Section intitulée « Les quatre familles d'expressions et leurs guides »Cette page pose le cadre. Quatre familles d'expressions ont leur guide dédié :
- les conditions et le ternaire, traités dans les conditions Terraform ;
- les expressions
foret le splat[*], dans les boucles for ; - les blocs
dynamic, dans les blocs dynamiques ; - les fonctions intégrées, dans les fonctions Terraform.
Pour produire du JSON ou du YAML, préférez d'ailleurs jsonencode() et
yamlencode() à un heredoc <<-, plus sûrs sur l'échappement.
Dépannage
Section intitulée « Dépannage »Ces symptômes viennent presque tous d'une règle de type ou de référence. Le tableau les relie à leur cause.
| Symptôme | Cause | Solution |
|---|---|---|
Reference to undeclared resource | Un préfixe resource. écrit dans l'expression | Référencer sans préfixe : type.nom.attribut |
Une égalité vraie attendue rend false | == ne convertit pas les types | Comparer entre types identiques, ou convertir (tostring, tonumber) |
| Un ternaire censé rendre un nombre rend une chaîne | Conversion silencieuse vers un type commun | Convertir explicitement, ou aligner les deux branches |
Un argument mis à "" provoque une erreur du provider | La chaîne vide est une valeur, pas une omission | Utiliser null pour omettre l'argument |
Invalid count argument (valeur inconnue) | count dépend d'un attribut known after apply | Le fonder sur une variable ou une valeur connue au plan |
À retenir
Section intitulée « À retenir »terraform consoleévalue une expression sans appliquer, et s'utilise en script (entrée standard,-plan).- Une ressource gérée se référence sans préfixe :
type.nom.attribut. - L'arithmétique convertit les types (
"5" + 3= 8),==non (1 == "1"= false). - Un ternaire convertit ses branches vers un type commun, sans erreur.
nullomet un argument ; une chaîne vide est une valeur.- Précédence :
*avant+;1 + 2 * 3= 7. - Une valeur inconnue au plan (
known after apply) se propage.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous reprennent les confusions les plus fréquentes sur les
expressions : la référence sans préfixe, la conversion de types, et null.
Sans préfixe
Une ressource gérée se référence par<type>.<nom>.<attribut> :output "valeur" {
value = random_string.jeton.result
}
L'erreur classique
Écrireresource.random_string.jeton.result échoue : le mot resource n'apparaît jamais dans une expression. C'est le seul cas sans préfixe, là où les autres valeurs nommées en ont un : var., local., data.<type>.<nom>, module.<nom>.== ne convertit pas
Vérifié sur Terraform 1.15.4 :> 1 == "1"
false
La doc : « Automatic type conversion does not occur when using the equality operator. » Le nombre 1 et la chaîne "1" ne sont pas égaux.La parade
Comparer entre types identiques, ou convertir explicitement :tostring(1) == "1" vaut true. C'est l'inverse de l'arithmétique, qui, elle, convertit ("5" + 3 vaut 8).Une conversion, pas une erreur
> type(true ? 12 : "hello")
string
Les deux branches sont converties vers un type commun. Beaucoup de guides présentent ce cas comme une erreur : c'est faux, c'est un piège de type silencieux.Comment s'en prémunir
Vérifiez le type du résultat, pas seulement sa valeur, et convertissez explicitement (tostring()) quand les branches diffèrent vraiment.null = omission
« If you set an argument of a resource tonull, Terraform behaves as though you had completely omitted it. »file_permission = var.perm != "" ? var.perm : null
Quand var.perm est vide, l'argument vaut null et la permission retombe sur le défaut du provider (0777).La chaîne vide est un piège
Écrire"" à la place n'omet rien : c'est une valeur, souvent invalide, qui fait échouer le provider.L'ordre
- unaire
!,- */%+-- comparaisons (
<,>,==, ...) &&||
Conséquence
> 1 + 2 * 3
7
1 + 2 * 3 se lit 1 + (2 * 3), soit 7, jamais 9. Les parenthèses documentent l'intention quand la lecture est ambiguë.Une valeur pas encore connue
Une expression qui dépend d'un attribut créé plus tard vaut(known after apply). L'inconnue se propage : connue + inconnue donne inconnue.Trois conséquences
- un
countne peut pas dépendre d'un attribut de ressource ; - la lecture d'une data source peut être reportée à l'apply ;
- certains outputs n'ont leur valeur qu'après l'apply.
Un outil de test, pas qu'un bac à sable
echo 'max(3, 7, 2)' | terraform console
# 7
« The terraform console command can be used in non-interactive scripts by piping newline-separated commands to it. »L'option -plan
terraform console -plan évalue les expressions contre l'état planifié, utile pour vérifier une valeur dérivée d'une ressource avant apply.Pour aller plus loin
Section intitulée « Pour aller plus loin »- Les conditions Terraform : Détaille le ternaire et le
countconditionnel, suite directe des expressions. - Conditions personnalisées : Place
validation,preconditionetcheckpour rejeter une valeur dès le plan. - Les boucles for : Transforme listes et maps, l'usage le plus courant des expressions.