Comprendre les fonctions, expressions et méta-arguments de Terraform - AWS Conseils prescriptifs

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Comprendre les fonctions, expressions et méta-arguments de Terraform

L'une des critiques à l'encontre des outils IaC qui utilisent des fichiers de configuration déclaratifs plutôt que des langages de programmation courants est qu'ils compliquent la mise en œuvre d'une logique de programmation personnalisée. Dans les configurations Terraform, ce problème est résolu à l'aide de fonctions, d'expressions et de méta-arguments.

Fonctions

L'un des grands avantages de l'utilisation du code pour provisionner votre infrastructure est la possibilité de stocker des flux de travail courants et de les réutiliser encore et encore, en utilisant souvent des arguments différents à chaque fois. Les fonctions Terraform sont similaires aux fonctions AWS CloudFormation intrinsèques, bien que leur syntaxe soit plus proche de la façon dont les fonctions sont appelées dans les langages de programmation. Vous avez peut-être déjà remarqué certaines fonctions Terraform, telles que substr, concat, length et base64decode, dans les exemples de ce guide. Comme CloudFormation pour les fonctions intrinsèques, Terraform possède une série de fonctions intégrées qui peuvent être utilisées dans vos configurations. Par exemple, si un attribut de ressource particulier prend un objet JSON très volumineux qu'il serait inefficace de coller directement dans le fichier, vous pouvez placer l'objet dans un fichier .json et utiliser les fonctions Terraform pour y accéder. Dans l'exemple suivant, la file fonction renvoie le contenu du fichier sous forme de chaîne, puis le jsondecode convertit en un type d'objet.

resource "example_resource" "example_resource_name" { json_object = jsondecode(file("/path/to/file.json")) }

Expressions

Terraform autorise également les expressions conditionnelles, qui sont similaires aux CloudFormation condition fonctions, sauf qu'elles utilisent la syntaxe plus traditionnelle des opérateurs ternaires. Dans l'exemple suivant, les deux expressions renvoient exactement le même résultat. Le deuxième exemple est ce que Terraform appelle une expression splat. L'astérisque permet à Terraform de parcourir la liste en boucle et de créer une nouvelle liste en utilisant uniquement la id propriété de chaque élément.

resource "example_resource" "example_resource_name" { boolean_value = var.value ? true : false numeric_value = var.value > 0 ? 1 : 0 string_value = var.value == "change_me" ? "New value" : var.value string_value_2 = var.value != "change_me" ? var.value : "New value" } There are two ways to express for loops in a Terraform configuration: resource "example_resource" "example_resource_name" { list_value = [for object in var.ids : object.id] list_value_2 = var.ids[*].id }

Méta-arguments

Dans l'exemple de code précédent, list_value et list_value_2 sont appelés arguments. Vous connaissez peut-être déjà certains de ces méta-arguments. Terraform possède également quelques méta-arguments, qui agissent comme des arguments mais avec quelques fonctionnalités supplémentaires :

  • Le méta-argument depends_on est très similaire à l'attribut. CloudFormation DependsOn

  • Le méta-argument du fournisseur vous permet d'utiliser plusieurs configurations de fournisseur à la fois.

  • Le méta-argument du cycle de vie vous permet de personnaliser les paramètres des ressources, de la même manière que les politiques de suppression et de suppression dans. CloudFormation

D'autres méta-arguments permettent d'ajouter des fonctionnalités de fonction et d'expression directement à une ressource. Par exemple, le méta-argument count est un mécanisme utile pour créer plusieurs ressources similaires en même temps. L'exemple suivant montre comment créer deux clusters Amazon Elastic Container Service (Amazon EKS) sans utiliser le count méta-argument.

resource "aws_eks_cluster" "example_0" { name = "example_0" role_arn = aws_iam_role.cluster_role.arn vpc_config { endpoint_private_access = true endpoint_public_access = true subnet_ids = var.subnet_ids[0] } } resource "aws_eks_cluster" "example_1" { name = "example_1" role_arn = aws_iam_role.cluster_role.arn vpc_config { endpoint_private_access = true endpoint_public_access = true subnet_ids = var.subnet_ids[1] } }

L'exemple suivant montre comment utiliser le count méta-argument pour créer deux clusters Amazon EKS.

resource "aws_eks_cluster" "clusters" { count = 2 name = "cluster_${count.index}" role_arn = aws_iam_role.cluster_role.arn vpc_config { endpoint_private_access = true endpoint_public_access = true subnet_ids = var.subnet_ids[count.index] } }

Pour attribuer un nom d'unité à chacune, vous pouvez accéder à l'index de la liste dans le bloc de ressources à l'adressecount.index. Mais que faire si vous souhaitez créer plusieurs ressources similaires un peu plus complexes ? C'est là qu'intervient le méta-argument for_each. Le for_each méta-argument est très similaire àcount, sauf que vous transmettez une liste ou un objet au lieu d'un nombre. Terraform crée une nouvelle ressource pour chaque membre de la liste ou de l'objet. C'est la même chose que si vous définissezcount = length(list), sauf que vous pouvez accéder au contenu de la liste plutôt qu'à l'index de la boucle.

Cela fonctionne à la fois pour une liste d'éléments ou pour un seul objet. L'exemple suivant créerait deux ressources dotées d'un id-0 identifiant et id-1 d'un identifiant.

variable "ids" { default = [ { id = "id-0" }, { id = "id-1" }, ] } resource "example_resource" "example_resource_name" { # If your list fails, you might have to call "toset" on it to convert it to a set for_each = toset(var.ids) id = each.value }

L'exemple suivant créerait également deux ressources, l'une pour Sparky, le caniche, et l'autre pour Fluffy, le chihuahua.

variable "dogs" { default = { poodle = "Sparky" chihuahua = "Fluffy" } } resource "example_resource" "example_resource_name" { for_each = var.dogs breed = each.key name = each.value }

Tout comme vous pouvez accéder à l'index de boucle dans count en utilisant count.index, vous pouvez accéder à la clé et à la valeur de chaque élément d'une boucle for_each en utilisant l'objet each. Comme for_each itère à la fois sur les listes et sur les objets, le suivi de chaque clé et de chaque valeur peut être un peu confus. Le tableau suivant montre les différentes manières d'utiliser le méta-argument for_each et la manière dont vous pouvez référencer les valeurs à chaque itération.

Exemple for_each type Première itération Deuxième itération
A
[“poodle”, “chihuahua”]
each.key = "poodle" each.value = null
each.key = "chihuahua" each.value = null
B
[ { type = "poodle", name = "Sparky" }, { type = "chihuahua", name = "Fluffy" } ]
each.key = { type = “poodle”, name = “Sparky” } each.value = null
each.key = { type = “chihuahua”, name = “Fluffy” } each.value = null
C
{ poodle = “Sparky”, chihuahua = “Fluffy” }
each.key = “poodle” each.value = “Sparky”
each.key = “chihuahua” each.value = “Fluffy”
D
{ dogs = { poodle = “Sparky”, chihuahua = “Fluffy” }, cats = { persian = “Felix”, burmese = “Morris” } }
each.key = “dogs” each.value = { poodle = “Sparky”, chihuahua = “Fluffy” }
each.key = “cats” each.value = { persian = “Felix”, burmese = “Morris” }
E
{ dogs = [ { type = “poodle”, name = “Sparky” }, { type = “chihuahua”, name = “Fluffy” } ], cats = [ { type = “persian”, name = “Felix” }, { type = “burmese”, name = “Morris” } ] }
each.key = “dogs” each.value = [ { type = “poodle”, name = “Sparky” }, { type = “chihuahua”, name = “Fluffy” } ]
each.key = “cats” each.value = [ { type = “persian”, name = “Felix” }, { type = “burmese”, name = “Morris” } ]

 

Donc, si var.animals c'est égal à la ligne E, vous pouvez créer une ressource par animal en utilisant le code suivant.

resource "example_resource" "example_resource_name" { for_each = var.animals type = each.key breeds = each.value[*].type names = each.value[*].name }

Vous pouvez également créer deux ressources par animal en utilisant le code suivant.

resource "example_resource" "example_resource_name" { for_each = var.animals.dogs type = "dogs" breeds = each.value.type names = each.value.name } resource "example_resource" "example_resource_name" { for_each = var.animals.cats type = "cats" breeds = each.value.type names = each.value.name }