Terraform refactoring - Renaming resources
When you start working with Terraform, you often don’t see a need for renaming resources, but as time moves on and your infrastructure project grows, you will definitely encounter situations where you will need to change the Terraform name of a resource (for example, as part of an “Extract module” refactoring).
Creating our instance and IP address
Let’s say you have a Compute Engine instance and a static IP configured in your Google Cloud environment.
resource "google_compute_address" "ip_address" {
name = "main-application"
}
resource "google_compute_instance" "default" {
name = "main-application"
machine_type = "f1-micro"
zone = "europe-west1-b"
boot_disk {
initialize_params {
image = "opensuse-cloud/opensuse-leap-15-5-v20230607-x86-64"
}
}
network_interface {
network = "default"
access_config {
nat_ip = google_compute_address.ip_address.address
}
}
}
I recommend that you run terraform init && terraform apply
to deploy the above code in your environment so that you can follow along with the next steps in the post.
The need for a rename
At some point, you need to set up a second Compute Engine instance for a new service that you are developing. You open up the Terraform code and realize that you named the resource for the IP address of the original instance ip_address
and the resource for the instance default
(a copy-paste error from the Terraform documentation).
Before adding the new instance, we need to do some clean-up.
Let’s give our resources some better names.
variable "project" {}
resource "google_compute_address" "main_application" {
project = var.project
name = "main-application"
region = "europe-west1"
}
resource "google_compute_instance" "main_application" {
project = var.project
name = "main-application"
machine_type = "f1-micro"
zone = "europe-west1-b"
boot_disk {
initialize_params {
image = "opensuse-cloud/opensuse-leap-15-5-v20230607-x86-64"
}
}
network_interface {
network = "default"
access_config {
nat_ip = google_compute_address.main_application.address
}
}
}
After renaming our resources, we can run terraform plan
to ensure Terraform applies our changes correctly.
...
Plan: 2 to add, 0 to change, 2 to destroy.
...
According to the plan, Terraform wants to destroy our resources rather than update the names. If this happens, we will be in big trouble, as recreating the resources will result in production downtime. We can’t have our production server down because of an internal name change. In addition, deleting the IP address would mean we would get a new IP address. Often this is not what we want.
The reason for Terraform’s proposal comes from the fact that Terraform doesn’t know that the google_compute_instance.main_application
and google_compute_instance.default
resource names refer to the same Compute Engine instance.
Informing Terraform of the new resource names
In the past, you would have had to resort to a state migration to resolve this issue, but in later versions of Terraform, a moved
block was added to the language that you can use to notify Terraform that a resource has moved to a new location.
moved {
from = google_compute_address.ip_address
to = google_compute_address.main_application
}
moved {
from = google_compute_instance.default
to = google_compute_instance.main_application
}
In the moved
blocks, we specify the old and new names of the resources we want to move. Let’s run terraform plan
one more time.
...
Plan: 0 to add, 0 to change, 0 to destroy.
...
We can see that Terraform now identifies the rename correctly and no longer plans to destroy any infrastructure. We can commit our code to version control, and on a future deployment, these changes will be applied to our production environment and our production Terraform state.