Terraform - prevent accidental resource re-creation

This tutorial shows you how to use Terraform lifecycle option to prevent undesirable resource re-creation.

Terraform is an infrastructure as a code software that can be used to manage Catalyst Cloud.

Problem

In Catalyst Cloud we provide OS images that users can use to start their virtual machines. We update our images regularly so the image name stays the same but the image contents change. Users who manage Catalyst Cloud using Terraform, will notice that when they use certain images to start compute instances Terraform will periodically offer to re-create an entire instance in response to image id change.

resource "openstack_compute_instance_v2" "instance-name" {
  ...
  # re-created every time image "ubuntu-18.04-x86_64" is updated.
  image_name      = "ubuntu-18.04-x86_64"
}
vm1:~/idempotency-test-terraform$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

openstack_compute_instance_v2.basic: Refreshing state... (ID: dca5cf20-70bd-474c-a05b-xxxxxxxxxxxx)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

-/+ openstack_compute_instance_v2.basic (new resource required)
      id:                  "dca5cf20-70bd-474c-a05b-xxxxxxxxxxxx" => <computed> (forces new resource)
      ...
      image_id:            "ad091b52-742f-469e-8f3c-xxxxxxxxxxxx"  => "ed6468b1-0ebf-4b67-97cf-xxxxxxxxxxxx" (forces new resource)
      image_name:          "ubuntu-18.04-x86_64"
      ...


Plan: 1 to add, 0 to change, 1 to destroy.

------------------------------------------------------------------------

Lifecycle or image ID

One possible solution is to use image_id in the Terraform manifest, this will pin image_id to specific value so that change in image_name won’t affect the resource.

resource "openstack_compute_instance_v2" "instance-name" {
  ...
  image_id        = "ad091b52-742f-469e-8f3c-xxxxxxxxxxxx"
}

while this solution works some people - others prefer to use image_name field for descriptive purposes, in this case another possible solution is to tell Terraform to ignore changes in image_name

resource "openstack_compute_instance_v2" "instance-name" {
  ...
  image_name      = "ubuntu-18.04-x86_64"
  lifecycle {
    ignore_changes = ["image_name"]
  }
}

This will prevent Terraform from re-creating the instance when image_id changes.