
Vous déployez une VM sur un hyperviseur KVM qui a 64 Go de RAM. Vous voulez que votre configuration alloue automatiquement 25 % de la mémoire disponible — mais cette valeur dépend de la machine hôte, pas de votre code. Comment lire cette information depuis Terraform sans la coder en dur ?
Les data sources sont la réponse. Un bloc data {} ne crée, ne modifie
et ne détruit rien — il lit uniquement. Il interroge une API ou
l’infrastructure existante pendant le plan, et expose le résultat
comme n’importe quel attribut de ressource. La puissance des data sources
vient de leur intégration : vous pouvez référencer data.libvirt_node_info.host.memory
dans vos ressources exactement comme var.nom ou libvirt_volume.disk.path.
C’est le mécanisme standard pour connecter Terraform à de l’infrastructure
existante non gérée par votre state.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Différence entre
resourceetdata: créer vs lire - Syntaxe d’un bloc
data {}et référencedata.type.nom.attribut - Quand Terraform lit les data sources : dans le plan, pas l’apply
- Utiliser une data source pour calculer des valeurs : sizing automatique d’une VM
- Les data sources dans le state :
data.dansterraform state list
Prérequis
Section intitulée « Prérequis »- Terraform ≥ 1.11 installé (installer Terraform)
- Ressources maîtrisées (déclarer des ressources)
L’idée derrière les data sources
Section intitulée « L’idée derrière les data sources »Pensez à lire une API pour récupérer une valeur :
# Données en durmemory = 64 # Codé manuellement
# Mieux : lire depuis l'APIapi_response = requests.get("/api/host/memory")memory = api_response["total_gb"] # 64vm_memory = memory * 0.25 # 16 GB pour la VM
# Puis créer la VMcreate_vm(name="my-vm", memory=vm_memory)Les data sources de Terraform font exactement cela : au lieu de coder des valeurs manuellement, vous les lisez depuis une API ou de l’infra existante, puis les utilisez pour créer des ressources.
Ressource vs data source
Section intitulée « Ressource vs data source »| Caractéristique | resource | data |
|---|---|---|
| Crée un objet | Oui | Non |
| Modifie un objet | Oui | Non |
| Détruit un objet | Oui | Non |
| Lit des informations | En retour | Uniquement |
| Lu au moment du… | Apply | Plan par défaut, apply si dépendances inconnues |
| Présent dans le state | Oui | Oui |
La ligne clé : Terraform essaie de lire les data sources pendant le plan, mais peut reporter cette lecture à l’apply si un argument dépend d’une valeur inconnue au moment du plan. Quand elles sont lues au plan, leurs valeurs sont disponibles pour calculer des attributs de ressources.
Syntaxe d’un bloc data
Section intitulée « Syntaxe d’un bloc data »data "libvirt_node_info" "host" {}La structure est identique aux ressources :
| Élément | Valeur | Rôle |
|---|---|---|
| Mot-clé | data | Toujours data |
| Type de data source | "libvirt_node_info" | Défini par le provider |
| Nom local | "host" | Alias HCL libre |
Pour référencer un attribut dans votre code :
data.type.nom_local.attributExemple :
data.libvirt_node_info.host.memory_total_kbExemple : adapter sa VM au host KVM
Section intitulée « Exemple : adapter sa VM au host KVM »Cet exemple illustre un cas concret : calculer automatiquement la mémoire à allouer à une VM en fonction des ressources réelles de l’hyperviseur.
Structure du projet
Section intitulée « Structure du projet »mon-projet/├── versions.tf ← provider libvirt├── variables.tf ← vm_name, pool, image_path├── main.tf ← data source + locals + ressources└── outputs.tf ← infos host + mémoire calculée# 1. Lire les infos du nœud KVMdata "libvirt_node_info" "host" {}
# 2. Calculer la mémoire VM depuis les infos lueslocals { host_memory_mib = floor(data.libvirt_node_info.host.memory_total_kb / 1024) vm_memory_mib = max(512, min(floor(local.host_memory_mib / 2), 4096))}
# 3. Créer le disqueresource "libvirt_volume" "disk" { name = "${var.vm_name}.qcow2" pool = var.pool
target = { format = { type = "qcow2" } } create = { content = { url = var.image_path } }}
# 4. Créer la VM avec la mémoire calculéeresource "libvirt_domain" "vm" { name = var.vm_name memory = local.vm_memory_mib # ← vient de la data source memory_unit = "MiB" vcpu = 1 # ... reste de la config}Le flux est : data → locals (calcul) → resource (utilisation).
terraform plan — la data source est lue immédiatement
Section intitulée « terraform plan — la data source est lue immédiatement »data.libvirt_node_info.host: Reading...data.libvirt_node_info.host: Read complete after 0s [id=7280450332732970530]
Terraform will perform the following actions: # libvirt_domain.vm will be created + memory = 4096 ...
Changes to Outputs: + host_cpu_cores_total = 16 + host_cpu_model = "x86_64" + host_memory_total_mib = 47953 + vm_memory_allocated_mib = 4096Le plan affiche déjà les valeurs réelles lues (host_cpu_cores_total = 16,
host_memory_total_mib = 47953). La VM reçoit 4096 MiB — moitié de la RAM
disponible (47953 MiB), plafonnée à 4096.
terraform apply — résultat
Section intitulée « terraform apply — résultat »Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
disk_path = "/var/lib/libvirt/images/lab05-vm.qcow2"host_cpu_cores_total = 16host_cpu_model = "x86_64"host_memory_total_mib = 47953vm_memory_allocated_mib = 4096Les data sources dans le state
Section intitulée « Les data sources dans le state »terraform state listdata.libvirt_node_info.host ← data source, préfixe data.libvirt_domain.vmlibvirt_volume.diskLes data sources apparaissent dans le state, mais avec le préfixe data.
Les inspecter avec terraform state show :
terraform state show data.libvirt_node_info.host# data.libvirt_node_info.host:data "libvirt_node_info" "host" { cpu_cores_per_socket = 16 cpu_cores_total = 16 cpu_model = "x86_64" cpu_sockets = 1 cpu_threads_per_core = 1 id = "7280450332732970530" memory_total_kb = 49104084 numa_nodes = 1}Terraform stocke le résultat lu pour détecter les changements lors des prochains plans. Si les données externes changent (nouvelle RAM dans le host), Terraform recalcule les valeurs dépendantes.
Quand utiliser une data source ?
Section intitulée « Quand utiliser une data source ? »Les data sources couvrent principalement trois situations :
1. Lire de l’infrastructure gérée par une autre configuration Terraform
# Config équipe réseau (state A)output "vpc_id" { value = aws_vpc.main.id }
# Votre config (state B)data "terraform_remote_state" "network" { backend = "s3" config = { bucket = "...", key = "network/terraform.tfstate" }}resource "aws_subnet" "app" { vpc_id = data.terraform_remote_state.network.outputs.vpc_id}2. Lire de l’infrastructure créée hors Terraform
# Pool libvirt créé manuellement (pas dans ce state)data "libvirt_node_info" "host" {}
# Utiliser les infos dans une ressourceresource "libvirt_domain" "vm" { memory = min(floor(data.libvirt_node_info.host.memory_total_kb / 1024 / 4), 2048)}3. Lire des informations dynamiques (IPs, états courants)
# Lire les interfaces d'une VM déjà crééedata "libvirt_domain_interface_addresses" "vm_ip" { domain = libvirt_domain.vm.id source = "lease"}Filtrer les données avec des arguments
Section intitulée « Filtrer les données avec des arguments »Certaines data sources acceptent des arguments pour cibler précisément
quoi lire. libvirt_node_info n’en a pas besoin (il n’y a qu’un seul
hôte), mais libvirt_node_devices accepte un filtre :
data "libvirt_node_devices" "usb" { capability = "usb_device"}Sur AWS, la data source aws_ami utilise des filtres pour trouver la
bonne image :
# Note : exemple AWS théorique, non testé dans les labs du sitedata "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical
filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-*-24.04-amd64-server-*"] }}
resource "aws_instance" "web" { ami = data.aws_ami.ubuntu.id # ← ID récupéré dynamiquement instance_type = "t3.micro"}Ordre d’exécution avec des data sources
Section intitulée « Ordre d’exécution avec des data sources »Terraform détermine l’ordre d’évaluation des data sources automatiquement :
- Pas de dépendance sur une ressource → lue pendant le plan (avant apply)
- Dépendance sur une ressource (
known after apply) → lue après la creation de la ressource
# Cas 1 : lue pendant le plan (pas de dépendance)data "libvirt_node_info" "host" {}
# Cas 2 : lue après création de la VM (dépendance sur libvirt_domain.vm)data "libvirt_domain_interface_addresses" "ip" { domain = libvirt_domain.vm.id # ← dépend d'une ressource}Dans le deuxième cas, Terraform affiche (known after apply) dans le plan
pour les attributs qui dépendent de cette data source — et les lit lors de
l’apply, une fois la VM créée.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
Error reading data source: connection refused | Provider non configuré ou service absent | Vérifier la config provider |
Valeurs en (known after apply) dans le plan | Data source dépend d’une ressource non créée | Normal — Terraform gère l’ordre |
Error: data source not found in provider | Faute de frappe sur le type | Vérifier avec terraform providers schema -json |
Data source non reconnue après init | Provider pas à jour | terraform init -upgrade |
À retenir
Section intitulée « À retenir »data "type" "nom" {}lit sans jamais modifier l’infrastructure- Les data sources sont lues pendant le plan (sauf si elles dépendent d’une ressource)
- La référence s’écrit
data.type.nom.attribut— notez le préfixedata. - Les data sources apparaissent dans
terraform state listavec le préfixedata. - Cas d’usage clés : infrastructure externe, autre state Terraform, infos dynamiques
terraform state show data.type.nomaffiche les valeurs lues