Blog

Replace Terraform resources based on other changes with replace_triggered_by

09 Apr, 2023
Xebia Background Header Wave

Terraform added the replace_triggered_by lifecycle argument in version 1.2. This argument allows you to replace a resource when another resource changes.

You probably wonder why you need this – and you’re right in doing so. Typically, Terraforms default dependency management works flawlessly. Sometimes, however, you might want to replace your VM, because even though you can update the start up script without replacement, you want a new instance for your own sanity. This blog shows how to get that done using the replace_triggered_by lifecycle argument.

Understanding the replace_triggered_by lifecycle argument

The replace_triggered_by lifecycle argument references managed resources and/or attributes. When the referenced resource or attribute changes, the resource is replaced. In the example below, any change to the foo_value.foo resource replaces the foo_value.bar resource.

resource "foo_value" "foo" {
  value = "foo"
}

resource "foo_value" "bar" {
  value = "bar"

  lifecycle {
    replace_triggered_by = [
      foo_value.foo,
    ]
  }
}

Please note that variables, data sources and modules are not supported, because the feature relies on planned actions for resource addresses. If needed, you could use the terraform_data resource to add resource-like behavior. In the example below, the terraform_data.bar resource is replaced when the local_file.foo content changes by leveraging the terraform_data.local_file_foo resource.

terraform {
  required_version = "~> 1.4.0"
}

data "local_file" "foo" {
  filename = "./foo.txt"
}

resource "terraform_data" "local_file_foo" {
  input = data.local_file.foo.content_sha256
}

resource "terraform_data" "bar" {
  input = "bar"

  lifecycle {
    replace_triggered_by = [
      terraform_data.local_file_foo,
    ]
  }
}

Find additional examples and contribute your use case to our GitHub repository.

Replacing a VM when the startup script changes

The Google Compute Instance resource has a special argument: metadata_startup_script. When changing this value, the VM is replaced. Sadly, this feature is only implemented for the startup script, whereas Windows VMs also have a sysprep script. The next example uses replace_triggered_by to replace a VM when the sysprep or startup script changes.

terraform {
  required_version = "~> 1.2.0"
}

resource "google_compute_instance" "my_vm" {
  name         = "my-vm"

  boot_disk {
    initialize_params {
      image = "projects/windows-cloud/global/images/family/windows-2022"
    }
  }

  metadata = {
    "sysprep-specialize-script-ps1" = file("${path.module}/assets/task_runner_sysprep.ps1")
    "windows-startup-script-ps1"    = file("${path.module}/assets/task_runner_startup.ps1")
  }

  lifecycle {
    replace_triggered_by = [
      null_resource.my_vm_replacement_trigger,
    ]
  }
}

resource "null_resource" "my_vm_replacement_trigger" {
  triggers = {
    "startup_script" = filesha256("${path.module}/assets/task_runner_startup.ps1")
    "sysprep_script" = filesha256("${path.module}/assets/task_runner_sysprep.ps1")
  }
}

Conclusion

Terraforms builtin dependency management typically works flawlessly. Sometimes, however, you want to force resource replacement based on other changes. If so, the replace_triggered_by lifecycle argument is there to help you.

Image by Marta from Pixabay.

Laurens Knoll
As a cloud consultant I enjoy taking software engineering practices to the cloud. Continuously improving the customers systems, tools and processes by focusing on integration and quality.
Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts