Cours - Boucles et expressions conditionnelles dans un langage déclaratif comme Terraform
Les boucles
Section titled “Les boucles”Le fait que HCL soit un langage destiné à une interprétation permet d’intégrer des appels à des boucles afin de générer par exemple plusieurs instances d’un même objet.
Ce n’est pas courant parmi les langages de configuation qui sont le plus souvent statiques, cf. XML, JSON ou YAML .
Terraform propose plusieurs constructions de bouclage, chacune destinée à être utilisée dans un scénario légèrement différent.
- Le meta paramètre
count: boucler sur les ressources et les modules - L’expression
for_each: boucler sur les ressources, les blocs en ligne dans une ressource et les modules - L’expression
for: boucler sur des listes et des maps - La directive de chaînes de caractère
for: boucler sur les listes et les maps dans une chaîne
Le meta argument count
Section titled “Le meta argument count”Ce méta-argument count peut provisionner dynamiquement plusieurs instances d’un Ressource.
Il prend pour paramètre un nombre entier qui détermine le nombre d’objets désirés.
variable "user_names" { description = "Create IAM users with these names" type = list(string) default = ["neo", "trinity", "morpheus"]}
resource "aws_iam_user" "example" { count = length(var.user_names) name = var.user_names[count.index]}La syntaxe count.index permet d’accéder à l’entier correspondant à l’itération courante, de {0...N}.
Pour accéder à une instance d’une ressource créée avec count, utilisez la notation crochet [], car il produit logiquement une liste de ressources.
aws_iam_user.example[0]Il existe plusieurs limitations qui limitent l’usage de count.
-
Il n’est utilisable que sur des blocks de ressources, et non sur des blocs intérieurs.
-
Il peut introduire des erreurs en raison de l’index d’itération.
Q: Que se passe-t-il si j’enlève l’utilisateur ayant l’index 1 de la liste ?
R: La valeur de aws_iam_user.example[1] n’est plus la même et Terraform va replanifier en fonction.
L’expression for_each
Section titled “L’expression for_each”Cette expression comparable à count itére sur des listes et des maps pour créer plusieurs copies d’une ressource.
On peut l’utiliser comme count en tant que paramètre de la ressource, en lui fournissant une structure complexe à parcourir.
variable "user_names" { description = "Create IAM users with these names" type = list(string) default = ["neo", "trinity", "morpheus"]}
resource "aws_iam_user" "example" { for_each = toset(var.user_names) name = each.value}Quelques remarques importantes
- On utilise la fonction
tosetpour convertir le typelisten typeset - On utilise la syntaxe
each.valuepour accéder à la valeur courante du pointeur dans la structure. - On peut aussi utiliser
each.keypour utiliser la clef d’unemap - Terraform utilise la chaîne
valued’un set ou lakeyd’une map comme index du conteneur des ressources produites
aws_iam_user.example["neo"]aws_iam_user.example["trinity"]aws_iam_user.example["morpheus"]L’intérêt de for_each est qu’il s’agit d’une expression qui peut être utilisée plus généralement.
Au contraire de count on peut l’utiliser dans toutes sortes de blocs à condition d’utiliser la directive dynamic.
Ici on l’utilise pour générer plusieurs tags définis dans une variable.
variable "
resource "aws_autoscaling_group" "example" { launch_configuration = aws_launch_configuration.example.name vpc_zone_identifier = data.aws_subnets.default.ids target_group_arns = [aws_lb_target_group.asg.arn] health_check_type = "ELB"
min_size = var.min_size max_size = var.max_size
tag { key = "Name" value = var.cluster_name propagate_at_launch = true }
dynamic "tag" { for_each = var.custom_tags
content { key = tag.key value = tag.value propagate_at_launch = true } }}La structure complexe parcourue par une expression for_each doit être connue à l’avance.
On ne peut donc pas utiliser une structure construire sur la base d’informations d’une ressource connues après son obtention.
L’expression for
Section titled “L’expression for”L’expression for est utilisée pour parcourir et traiter une structure complexe.
Son usage est assez proche de celui des compréhensions de liste en python.
Elle produit des listes et des maps
> [for k,v in [1,3,5] : "${k}:${v}"][ "0:1", "1:3", "2:5",]
> {for k,v in ["apple","kiwi","bananas"] : v => k}{ "apple" = 0 "bananas" = 2 "kiwi" = 1}On peut également filtrer les résultats avec un if et utilliser des fonctions.
> [for k,v in ["aba","aca","ada","afa","aga"] : upper("${k}:${v}") if k % 2 == 0][ "0:ABA", "2:ADA", "4:AGA",]La directive de chaînes de caractère for
Section titled “La directive de chaînes de caractère for”Elle est utile pour créer des contenus de chaînes à partir de structures complexes.
> "%{ for k,v in ["apple","kiwi","bananas"] }${k}:${v}, %{ endfor }""0:apple, 1:kiwi, 2:bananas, "Utilisation des conditions
Section titled “Utilisation des conditions”Avec count
Section titled “Avec count”En combinant les conditionals et count on peut désactiver certaines ressources.
resource "aws_autoscaling_schedule" "scale_out_during_business_hours" { count = var.enable_autoscaling ? 1 : 0
scheduled_action_name = "${var.cluster_name}-scale-out-during-business-hours" min_size = 2 max_size = 10 desired_capacity = 10 recurrence = "0 9 * * *" autoscaling_group_name = aws_autoscaling_group.example.name}On peut aussi faire des conditions inverses
resource "aws_iam_user_policy_attachment" "neo_cloudwatch_full_access" { count = var.give_user_cloudwatch_full_access ? 1 : 0
user = aws_iam_user.the_user.name policy_arn = aws_iam_policy.cloudwatch_full_access.arn}
resource "aws_iam_user_policy_attachment" "neo_cloudwatch_read_only" { count = var.give_user_cloudwatch_full_access ? 0 : 1
user = aws_iam_user.the_user.name policy_arn = aws_iam_policy.cloudwatch_read_only.arn}Utiliser des conditions pour for_each
Section titled “Utiliser des conditions pour for_each”On peut transformer la structure complexe à parcourir avant de la passer à for_each.
dynamic "tag" { for_each = { for key, value in var.custom_tags: key => upper(value) if key != "Name" }
content { key = tag.key value = tag.value propagate_at_launch = true } }Utiliser des conditions pour la directive de chaîne for
Section titled “Utiliser des conditions pour la directive de chaîne for”Dans l’exemple précédent, on avait le problème classique de la chaîne terminant par une virgule.
## console> "%{ for k,v in ["apple","kiwi","bananas"] }${k}:${v}%{ if k < length( ["apple","kiwi","bananas"]) - 1}, %{ endif}%{ endfor }""0:apple, 1:kiwi, 2:bananas"