Aller au contenu
Infrastructure as Code medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

OpenTofu : refactor, import, moved et removed

10 min de lecture

logo opentofu

Le vrai sujet d’une infrastructure IaC n’est pas seulement “creer 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 creee 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 creer.

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 depots 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 meme objet deplace ;
  • d’un objet a importer ;
  • d’un objet a oublier ;
  • ou d’un objet a recreer.

Les blocs de refactor existent donc pour transformer une intention implicite en intention declarative et lisible.

OpenTofu dispose de deux facons principales d’importer :

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

L’approche la plus interessante pour les equipes 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 deja 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 equipeimport 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"
}

2 - moved : dire qu’un objet a change d’adresse

Section intitulée « 2 - moved : dire qu’un objet a change d’adresse »

Le bloc moved sert a expliquer qu’un objet deja connu du state doit etre considere comme le meme 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 tres frequent : 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 creer 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 ;
  • enchainez plusieurs renommages dans le temps.
moved {
from = aws_instance.a
to = aws_instance.b
}
moved {
from = aws_instance.b
to = aws_instance.c
}

Cette ecriture garde un historique d’upgrade plus robuste qu’un seul move ecrasant les etapes intermediaires.

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 necessaire pour relier l’ancienne adresse a la nouvelle.

Le bon reflexe 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 systeme distant.

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

Pour un module, l’idee est la meme. Vous oubliez le module dans la configuration et dans le state, sans toucher aux objets geres 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 enchainement 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 evite le piege classique qui consiste a faire un gros refactor structurel avant meme 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 complete une strategie de migration progressive pour les modules tres utilises.

SymptomeCause probableSolution
un renommage provoque une recreationabsence de moved ou mauvais adressageajouter un moved correct puis relire le plan
import block refuse de planifierresource block absent ou insuffisantdefinir la ressource cible avant l’import
plusieurs adresses gerent le meme objetimport fait deux fois vers des adresses differenteschoisir une seule adresse canonique et nettoyer le state
un objet sort du state alors qu’il devait etre detruitremoved 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-meme.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn