Aller au contenu
Infrastructure as Code medium

Les fonctions définies par les providers : la syntaxe provider::

9 min de lecture

logo terraform

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.

  • La syntaxe provider:: : namespace, nom local, désambiguïsation
  • Le provider intégré terraform : encode_tfvars, decode_tfvars, encode_expr
  • Une fonction tierce : direxists de hashicorp/local, et le piège de version
  • Prouver l'origine d'une fonction : providers schema -json et metadata functions -json
  • Fonctions pures : évaluées au plan, absentes du state

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.

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 that
provider name "terraform" is declared in this module's required_providers
block, 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 })
<<EOT
region = "eu-west-3"
replicas = 3
EOT
> 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 .tfvars depuis des données calculées.
  • decode_tfvars(chaîne) fait l'inverse et restitue les types : le replicas ci-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.

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)
true

Le 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.

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 :

Fenêtre de terminal
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.

CommandeCe qu'elle prouve
providers schema -jsonLes fonctions d'un provider (.functions)
metadata functions -jsonLes fonctions du langage uniquement
version -jsonLa version de provider retenue

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.

  • Une fonction définie par un provider s'appelle provider::<nom_local>::<fonction>, où <nom_local> est le nom du provider dans required_providers, pas son type.
  • Le provider doit être déclaré, y compris le provider intégré terraform, sinon Unknown provider function.
  • Le provider intégré expose encode_tfvars, decode_tfvars (qui restitue les types) et encode_expr, hors ligne.
  • Une fonction n'existe qu'à partir de la version de provider qui l'a introduite : une contrainte trop basse passe l'init mais échoue à l'appel.
  • providers schema -json et metadata functions -json prouvent, sans ambiguïté, si une fonction vient d'un plugin ou du langage.

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.

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