
Comment sérialiser un objet en syntaxe tfvars sans assembler la chaîne à la
main ? Comment savoir, dans un terraform console, si direxists est une
fonction du langage ou une fonction apportée par un plugin ? Depuis Terraform
1.8, un provider ne fournit plus seulement des ressources et des data
sources : il expose aussi ses propres fonctions.
Ces fonctions définies par les providers s'appellent par un namespace dédié,
provider::<nom_local>::<fonction>, qui les distingue sans ambiguïté des
238 fonctions intégrées du langage. Le préfixe n'est pas décoratif : il dit
de quel plugin vient la fonction, et une fonction n'existe qu'une fois ce
plugin déclaré et installé dans une version qui la contient.
Tous les exemples de ce guide ont été exécutés sur Terraform v1.15.4 avant publication, résultats compris.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- La syntaxe
provider::: namespace, nom local, désambiguïsation - Le provider intégré
terraform:encode_tfvars,decode_tfvars,encode_expr - Une fonction tierce :
direxistsdehashicorp/local, et le piège de version - Prouver l'origine d'une fonction :
providers schema -jsonetmetadata functions -json - Fonctions pures : évaluées au plan, absentes du state
Prérequis
Section intitulée « Prérequis »- Terraform 1.8 ou plus récent (installer Terraform) :
la syntaxe
provider::n'existe pas avant. - Les fonctions intégrées et
terraform console(fonctions Terraform). - Les contraintes de version de provider (contraintes de version).
Qu'est-ce qu'une fonction définie par un provider ?
Section intitulée « Qu'est-ce qu'une fonction définie par un provider ? »Une fonction définie par un provider est une fonction livrée par un plugin, et non par le cœur de Terraform. On l'appelle par un nom qualifié en trois segments :
provider::<nom_local>::<fonction>(arguments...)Le premier segment est toujours le mot-clé provider. Le deuxième est le nom
local du provider, celui de son entrée dans required_providers, pas son
type ni son adresse source. Le troisième est le nom de la fonction. Cette forme
qualifiée lève toute ambiguïté : deux providers peuvent exposer une fonction du
même nom sans collision, puisque le nom local les sépare.
Déclarer le provider, même intégré
Section intitulée « Déclarer le provider, même intégré »Une fonction de provider n'est disponible que si le provider est déclaré dans
required_providers. C'est vrai y compris pour le provider intégré
terraform, qui expose trois fonctions utiles sans rien télécharger :
terraform { required_providers { tfcore = { source = "terraform.io/builtin/terraform" } }}Ici le nom local choisi est tfcore : les appels s'écriront donc
provider::tfcore::.... Sans cette déclaration, l'appel échoue à l'init avec un
message qui pointe précisément la cause :
Error: Unknown provider function
There is no function named "provider::terraform::encode_tfvars". Ensure thatprovider name "terraform" is declared in this module's required_providersblock, and that this provider offers a function named "encode_tfvars".Le message nomme le provider attendu : c'est le nom local, celui du namespace
d'appel, qui doit exister dans required_providers.
Les trois fonctions du provider intégré terraform
Section intitulée « Les trois fonctions du provider intégré terraform »Le provider intégré expose encode_tfvars, decode_tfvars et
encode_expr, toutes hors ligne. Testées dans terraform console :
> provider::tfcore::encode_tfvars({ region = "eu-west-3", replicas = 3 })<<EOTregion = "eu-west-3"replicas = 3EOT
> provider::tfcore::decode_tfvars("region = \"eu-west-3\"\nreplicas = 3\n"){ "region" = "eu-west-3" "replicas" = 3}
> provider::tfcore::encode_expr([1, "deux", true, null])"[1, \"deux\", true, null]"encode_tfvars(objet)sérialise un objet en syntaxe tfvars : une paire par ligne, clés triées, signes=alignés. Utile pour générer un fichier.tfvarsdepuis des données calculées.decode_tfvars(chaîne)fait l'inverse et restitue les types : lereplicasci-dessus ressort en nombre, pas en chaîne. C'est ce qui distingue un décodage tfvars d'une simple lecture de texte.encode_expr(valeur)rend la syntaxe d'expression Terraform d'une valeur, pratique pour composer du code Terraform sans concaténer à la main.
Ces fonctions sont pures : elles s'évaluent au plan, ne créent aucune ressource et n'apparaissent pas dans le state.
Une fonction tierce, et le piège de version
Section intitulée « Une fonction tierce, et le piège de version »Les providers du registre en exposent aussi. hashicorp/local fournit
direxists, qui teste l'existence d'un répertoire :
terraform { required_providers { local = { source = "hashicorp/local" version = ">= 2.5.0" } }}> provider::local::direxists(path.module)trueLe piège est là : direxists a été ajoutée en hashicorp/local 2.5.0. Une
contrainte trop basse, comme ~> 2.4.0, laisse l'init réussir puis fait
échouer l'appel : la fonction n'est tout simplement pas dans le plugin
installé. Contraindre la bonne version fait donc partie du travail, au même titre
que l'appel.
Prouver d'où vient une fonction
Section intitulée « Prouver d'où vient une fonction »Deux commandes tranchent, sans ambiguïté, entre fonction du langage et fonction de provider.
terraform providers schema -json décrit les fonctions de chaque provider,
au même titre que ses ressources :
terraform providers schema -json | jq '.provider_schemas | to_entries[] | select(.value.functions) | { provider: .key, functions: (.value.functions | keys) }'{ "provider": "terraform.io/builtin/terraform", "functions": ["decode_tfvars", "encode_expr", "encode_tfvars"] }{ "provider": "registry.terraform.io/hashicorp/local", "functions": ["direxists"] }terraform metadata functions -json est la preuve par l'absence : ce
document ne liste que les ~238 fonctions du langage. Aucune fonction de
provider n'y figure. Une fonction absente d'ici mais présente dans un schéma de
provider vient donc du plugin, sans discussion possible.
| Commande | Ce qu'elle prouve |
|---|---|
providers schema -json | Les fonctions d'un provider (.functions) |
metadata functions -json | Les fonctions du langage uniquement |
version -json | La version de provider retenue |
Mettre en pratique
Section intitulée « Mettre en pratique »Le lab provider-defined-functions fait construire une configuration qui lit
un fichier tfvars, le décode, le ré-encode enrichi, produit une syntaxe
d'expression et teste des répertoires avec direxists, puis prouve chaque fait
sur les sorties JSON. Le provider intégré y est imposé sous le nom local
tfcore, et la contrainte sur hashicorp/local doit admettre direxists.
À retenir
Section intitulée « À retenir »- Une fonction définie par un provider s'appelle
provider::<nom_local>::<fonction>, où<nom_local>est le nom du provider dansrequired_providers, pas son type. - Le provider doit être déclaré, y compris le provider intégré
terraform, sinonUnknown provider function. - Le provider intégré expose
encode_tfvars,decode_tfvars(qui restitue les types) etencode_expr, hors ligne. - Une fonction n'existe qu'à partir de la version de provider qui l'a
introduite : une contrainte trop basse passe l'
initmais échoue à l'appel. providers schema -jsonetmetadata functions -jsonprouvent, sans ambiguïté, si une fonction vient d'un plugin ou du langage.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »Les questions ci-dessous portent sur les points qui bloquent le plus souvent :
le nom à mettre dans le namespace, l'erreur Unknown provider function, et la
différence entre une fonction du langage et une fonction de provider. Chaque
réponse donne la commande de vérification correspondante.
Réponse courte
Le nom local du provider, celui de son entrée dansrequired_providers. Ce n'est ni le type ni l'adresse source.Détail
Si vous écriveztfcore = { source = "terraform.io/builtin/terraform" }, alors les fonctions s'appellent provider::tfcore::encode_tfvars, pas provider::terraform::encode_tfvars. Changez le nom local, et le namespace change avec lui.Réponse courte
Le provider nommé dans le namespace n'est pas déclaré dansrequired_providers.Détail
Le message le dit explicitement : il attend queprovider name "..." soit déclaré et offre la fonction. Deux causes : le provider manque de required_providers, ou le nom local ne correspond pas à celui du namespace. Corrigez, puis terraform init.Réponse courte
Oui. Le provider intégré ne se télécharge pas, mais il se déclare comme les autres.Détail
terraform {
required_providers {
tfcore = {
source = "terraform.io/builtin/terraform"
}
}
}
Sans cette déclaration, provider::tfcore::encode_tfvars(...) lève Unknown provider function.Réponse courte
terraform metadata functions -json liste les fonctions du langage ; terraform providers schema -json liste celles des providers.Détail
Une fonction absente demetadata functions -json mais présente dans providers schema -json (.provider_schemas[<addr>].functions) vient du plugin. C'est la preuve par l'absence : le langage compte ~238 fonctions, aucune fonction de provider n'y figure.Réponse courte
Oui. Un nombre reste un nombre, un booléen reste un booléen.Détail
> provider::tfcore::decode_tfvars("replicas = 3\n").replicas
3
La valeur ressort en nombre (type number), pas en chaîne "3". Une lecture de texte via file() seule aurait rendu tout le contenu en chaîne.Réponse courte
La version installée du provider n'expose pas encore la fonction.Détail
Une fonction n'existe qu'à partir de la version qui l'a introduite.direxists date de hashicorp/local 2.5.0 : une contrainte ~> 2.4.0 passe l'init mais fait échouer l'appel. Vérifiez avec terraform version -json (provider_selections) et relevez la borne.Réponse courte
Non. Une fonction de provider est pure : elle transforme une valeur, sans effet de bord.Détail
Elle s'évalue au plan, ne crée aucune ressource et n'apparaît pas dans le state. Appelerprovider::tfcore::encode_expr(...) ne contacte aucune API : seul le plugin est chargé localement pour exécuter la fonction.Pour aller plus loin
Section intitulée « Pour aller plus loin »- Les boucles for de Terraform : composer ces fonctions sur une collection.
- Les locals Terraform : nommer un resultat de fonction plutot que le recalculer.
- Le style guide Terraform : le lock file, qui fige la version du provider qui fournit ces fonctions.
- Provider requirements : la reference officielle : la syntaxe
provider::<nom>::<fonction>vient de la. - Built-in functions : les fonctions integrees, a ne pas confondre avec celles d'un provider.