Aller au contenu
Infrastructure as Code medium

Conditions personnalisées Terraform : validation, precondition, postcondition et check

8 min de lecture

logo terraform

Comment refuser une taille d'instance trop petite avant le plan ? Comment vérifier qu'une instance a bien reçu une IP après sa création ? Comment surveiller la santé d'un service sans faire échouer l'apply ? Ces trois questions appellent trois dispositifs différents, et Terraform en a un quatrième par-dessus.

Terraform offre quatre niveaux de validation : la validation de variable, la precondition, la postcondition et le bloc check. Ils se ressemblent à l'écrit, mais un seul n'arrête pas l'opération. Savoir lequel mettre où, et lequel bloque, est le sous-objectif d'examen 2a, et c'est le trou le plus fréquent en préparation.

Tous les exemples de ce guide ont été exécutés sur Terraform v1.15.4 avant publication, résultats compris.

  • validation : refuser une entrée avant le plan, y compris en croisant deux variables
  • precondition : refuser une hypothèse avant la création (et le piège de count = 0)
  • postcondition : refuser un résultat après la création, avec self
  • check : surveiller sans bloquer, et pourquoi il fait sortir plan -detailed-exitcode en 2
  • Le tableau checks de show -json : le verdict des quatre en un appel machine

Dans un bloc variable, un bloc validation refuse une valeur d'entrée avant tout plan. Sa condition est un booléen, son error_message s'affiche quand elle est fausse. Depuis Terraform 1.9, la condition peut référencer une autre variable, ce qu'on appelle une validation croisée :

variable "replicas" {
type = number
validation {
condition = var.replicas <= var.replicas_max
error_message = "replicas ne peut pas dépasser replicas_max."
}
}

precondition : refuser une hypothèse avant la création

Section intitulée « precondition : refuser une hypothèse avant la création »

Dans un bloc lifecycle, une precondition vérifie une hypothèse au moment du plan, avant que la ressource soit créée :

resource "aws_instance" "web" {
# ...
lifecycle {
precondition {
condition = var.instance_type != "t2.nano"
error_message = "t2.nano est trop petit pour ce rôle."
}
}
}

postcondition : refuser un résultat après la création

Section intitulée « postcondition : refuser un résultat après la création »

Toujours dans lifecycle, une postcondition vérifie le résultat après la création. Elle est la seule à disposer de self, l'objet créé :

postcondition {
condition = self.private_ip != ""
error_message = "L'instance n'a pas reçu d'IP privée."
}

C'est la différence de fond avec la précondition : la précondition garde une entrée (connue au plan), la postcondition garde une sortie (connue après l'apply). Les deux bloquent l'opération quand leur condition est fausse.

Un bloc check de niveau racine surveille un invariant. Contrairement aux trois précédents, un assert en échec n'arrête pas l'apply : il produit un avertissement, pas une erreur. C'est fait pour des vérifications de continuité de service qu'on ne veut pas bloquantes.

check "sante_http" {
data "http" "home" {
url = "https://${aws_instance.web.public_ip}/"
}
assert {
condition = data.http.home.status_code == 200
error_message = "La home ne répond pas 200."
}
}

Un check peut contenir un data source scopé, comme ici. Point à connaître : ce data source est relu à chaque plan, donc il apparaît toujours en action read dans le plan.

terraform show -json expose un tableau checks de premier niveau. Chaque entrée porte un address.kind et un status :

address.kindDispositifBloque ?
varvalidation de variableoui
resourceprecondition / postconditionoui
output_valueprecondition d'un outputoui
checkbloc checknon, avertit

Un check en échec porte son message dans instances[].problems[].message. C'est la preuve machine des quatre niveaux, sans jamais lire une sortie humaine :

Fenêtre de terminal
terraform show -json | jq '.checks[] | {kind: .address.kind, status}'

Le dernier piège : validate ne joue pas ces conditions

Section intitulée « Le dernier piège : validate ne joue pas ces conditions »

terraform validate contrôle la forme de la configuration, pas les valeurs. Il ne connaît pas les valeurs des variables, donc il rend valid: true sur une entrée que le plan refusera :

Fenêtre de terminal
terraform validate -json # valid: true, error_count: 0
terraform plan -var replicas=99 # Error: Invalid value for variable

validate est un contrôle de syntaxe et de références, utile en pré-commit ; il ne remplace jamais un plan pour valider les valeurs.

  • validation (variable) refuse une entrée avant le plan ; depuis 1.9 elle peut croiser deux variables.
  • precondition garde une hypothèse avant création, mais n'est pas évaluée si count = 0.
  • postcondition garde un résultat après création ; seule elle a self.
  • Ces trois-là bloquent ; le bloc check avertit seulement.
  • Un check avec data source scopé fait sortir plan -detailed-exitcode en 2 sur une config pourtant convergée.
  • Le tableau checks de show -json donne le verdict des quatre ; validate ne joue aucune de ces conditions.

Les questions ci-dessous portent sur ce qui bloque le plus souvent : quel niveau choisir, pourquoi une précondition ne se déclenche pas, et pourquoi un plan annonce des changements sur une configuration stable. Chaque réponse donne la commande de vérification correspondante.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn