Aller au contenu
English
English
Infrastructure as Code medium

OpenTofu : refactor, import, moved et removed

10 min de lecture

logo opentofu

Le vrai sujet d'une infrastructure IaC n'est pas seulement "créer des ressources", mais les faire evoluer sans casser leur historique. Vous renommez un module, vous passez une ressource vers for_each, vous reprenez une ressource existante créée hors du state, ou vous voulez retirer un objet de la configuration sans le detruire. Sans aide explicite, OpenTofu voit souvent ces changements comme un vieux bloc a detruire et un nouveau bloc a créer.

OpenTofu propose plusieurs outils pour rendre ces transitions declaratives : import, moved et removed. Le plus important est de leur donner le bon role. import sert a raccrocher un objet existant a votre state. moved sert a dire qu'un objet a change d'adresse logique. removed sert a dire qu'un objet doit sortir de la configuration, avec ou sans destruction selon votre intention. Cette page vous montre comment les combiner proprement sur des dépôts qui vivent longtemps.

  • choisir entre commande d'import et import block ;
  • utiliser moved pour renommer ou redistribuer des ressources ;
  • utiliser removed pour oublier un objet sans le detruire ;
  • faire evoluer des ressources ou modules avec count et for_each ;
  • garder un historique de refactor clair pour les mainteneurs suivants.

OpenTofu raisonne principalement avec les adresses des objets dans le state. Si vous changez une adresse sans explication, il ne peut pas deviner s'il s'agit :

  • du même objet deplace ;
  • d'un objet a importer ;
  • d'un objet a oublier ;
  • ou d'un objet a recréer.

Les blocs de refactor existent donc pour transformer une intention implicite en intention déclarative et lisible.

OpenTofu dispose de deux façons principales d'importer :

  • la commande tofu import ;
  • le import block dans la configuration.

L'approche la plus interessante pour les équipes et la CI est souvent le import block, car elle est visible dans le code et passe par le cycle normal plan -> apply.

import {
to = aws_instance.example
id = "i-abcd1234"
}
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t3.micro"
}

Le point important est le suivant : il faut déjà une configuration de ressource. OpenTofu n'accepte pas un import sans savoir dans quel bloc la ressource devra vivre.

SituationBon choix
operation ponctuelle en localtofu import
revue en équipeimport block
pipeline CI/CDimport block
imports multiples et historisation du changementimport block

OpenTofu permet aussi :

import {
to = module.instances.aws_instance.example
id = "i-abcd1234"
}

ou encore :

import {
to = aws_instance.example["blue"]
id = "i-abcd1234"
}

Le bloc moved sert a expliquer qu'un objet déjà connu du state doit être considere comme le même objet, mais a une nouvelle adresse logique.

Syntaxe minimale :

moved {
from = aws_instance.old_name
to = aws_instance.new_name
}
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t3.micro"
}
moved {
from = aws_instance.app
to = aws_instance.web
}

OpenTofu comprend alors que aws_instance.app n'est pas a detruire, mais a re-interpreter comme aws_instance.web.

locals {
instances = {
blue = { instance_type = "t3.micro" }
}
}
resource "aws_instance" "web" {
for_each = local.instances
ami = "ami-12345678"
instance_type = each.value.instance_type
}
moved {
from = aws_instance.web
to = aws_instance.web["blue"]
}

Le cas d'usage est très fréquent : vous partez d'une ressource unique, puis vous generalisez avec for_each.

module "network_v2" {
source = "../modules/network"
}
moved {
from = module.network
to = module.network_v2
}

Ici encore, l'objectif n'est pas de créer un nouveau module, mais de conserver le lien historique entre les adresses.

Le bloc moved devient encore plus utile quand vous :

  • transformez un count en for_each ;
  • decoupez un gros module en plusieurs petits modules ;
  • enchaînez plusieurs renommages dans le temps.
moved {
from = aws_instance.a
to = aws_instance.b
}
moved {
from = aws_instance.b
to = aws_instance.c
}

Cette écriture garde un historique d'upgrade plus robuste qu'un seul move ecrasant les étapes intermédiaires.

Pourquoi il ne faut pas supprimer trop vite les moved

Section intitulée « Pourquoi il ne faut pas supprimer trop vite les moved »

Retirer un moved trop tot est souvent une breaking change. Un utilisateur qui saute une version intermediaire n'aura plus l'information nécessaire pour relier l'ancienne adresse a la nouvelle.

Le bon réflexe est donc de conserver les moved tant que vous n'avez pas la certitude que tous les consommateurs ont applique la migration voulue.

4 - removed : sortir un objet de la configuration sans toujours le detruire

Section intitulée « 4 - removed : sortir un objet de la configuration sans toujours le detruire »

Le bloc removed sert a dire qu'un objet doit quitter la configuration. C'est utile si vous voulez oublier une ressource ou un module dans le state sans la destruction correspondante.

removed {
from = aws_instance.web
lifecycle {
destroy = false
}
}

Avec destroy = false, OpenTofu retirera l'objet du state sans demander sa destruction dans le système distant.

removed {
from = module.legacy_network
lifecycle {
destroy = false
}
}

Pour un module, l'idée est la même. Vous oubliez le module dans la configuration et dans le state, sans toucher aux objets gérés a distance.

  • lifecycle n'est pas strictement obligatoire, mais il est fortement recommande ;
  • destroy = false sert a oublier sans detruire ;
  • destroy = true documente explicitement une suppression volontaire ;
  • les removed pointant vers des modules n'acceptent pas de provisioners ;
  • pour une ressource, un removed peut inclure un provisioner si la destruction est voulue.

Voici un enchaînement sain sur une configuration existante :

  1. Importer les objets qui existent hors state avec import ou tofu import.

  2. Stabiliser la configuration avec un plan propre.

  3. Refactorer ensuite les adresses avec moved.

  4. Sortir enfin certains objets de la configuration avec removed si l'objectif est de les oublier sans les detruire.

  5. Conserver les moved utiles aussi longtemps que le chemin d'upgrade doit rester compatible.

Ce sequence évite le piège classique qui consiste a faire un gros refactor structurel avant même d'avoir raccroche correctement les objets au state.

6 - Ne pas oublier la deprecation des variables et outputs

Section intitulée « 6 - Ne pas oublier la deprecation des variables et outputs »

Les refactors ne concernent pas seulement les ressources. OpenTofu supporte aussi des messages de deprecation sur les variables et outputs d'un module, ce qui aide a accompagner les consommateurs vers une nouvelle interface sans tout casser d'un coup.

Cette approche ne remplace pas moved, mais elle complète une stratégie de migration progressive pour les modules très utilisés.

SymptômeCause probableSolution
un renommage provoque une recréationabsence de moved ou mauvais adressageajouter un moved correct puis relire le plan
import block refuse de planifierresource block absent ou insuffisantdéfinir la ressource cible avant l'import
plusieurs adresses gèrent le même objetimport fait deux fois vers des adresses différenteschoisir une seule adresse canonique et nettoyer le state
un objet sort du state alors qu'il devait être détruitremoved avec destroy = false utilise par erreurcorriger l'intention de destruction et relire le plan
un vieux consommateur casse a la mise a jourmoved retire trop totrestaurer le move ou documenter une migration intermediaire
  • import sert a reprendre un objet existant dans le state.
  • moved sert a conserver un objet tout en changeant son adresse logique.
  • removed sert a sortir un objet de la configuration, avec ou sans destruction selon lifecycle.destroy.
  • Les refactors propres se lisent d'abord dans le plan, pas au moment du apply surprise.
  • Garder l'historique des migrations dans le code aide les prochains mainteneurs autant que l'outillage lui-même.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. 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