Upgrading Terraform Destroy-Time Provisioners
Tags: systemadministration, terraform, devops, go
Published: 2020-12-25 11:13:35

---
title: Upgrading Terraform Destroy-Time Provisioners
published: true
date: 2020-12-18 19:58:57 UTC
tags: systemadministration,terraform,devops,golang
canonical_url: https://medium.com/@jmarhee/upgrading-terraform-destroy-time-provisioners-31c57b62ff1e
---

With Terraform, you can specify when you’d like a resource applied. For example, using when = destroy , the following resource will only be run when that plan is targeted for a destroy:

```
data "external" "create_cluster" {
  program = ["python3", "${path.module}/scripts/create_cluster.py"]
  query = {
    du_fqdn = var.cluster_fqdn
    user = var.cluster_user
    pw = var.cluster_password
    tenant = var.cluster_tenant
    region = var.cluster_region
    cluster_name = var.cluster_name
    k8s_api_fqdn = metal_reserved_ip_block.cluster_ip.address
    allow_workloads_on_master = var.allow_workloads_on_master
  }
}

resource "null_resource" "delete_cluster" {

provisioner "local-exec" {
    when = destroy
    command = "printf '{\"du_fqdn\": \"${var..cluster_fqdn}\", \"user\": \"${var..cluster_user}\", \"pw\": \"${var..cluster_password}\", \"tenant\": \"${var..cluster_tenant}\", \"region\": \"${var..cluster_region}\", \"cluster_uuid\": \"${lookup(data.external.create_cluster.result, "cluster_id")}\"}' | python3 ${path.module}/scripts/delete_cluster.py"
    environment = {
      du_fqdn = var.cluster_fqdn
      user = var.cluster_user
      pw = var.cluster_password
      tenant = var.cluster_tenant
      region = var.cluster_region
      cluster_uuid = lookup(data.external.create_cluster.result, "cluster_id")
    }
  }
}
```

In this case, we want the result from our `create_cluster` datasource. However, in Terraform 0.13+, you can no longer reference data in this way, and when you try, you get a fatal error:

```
Error: Invalid reference from destroy provisioner

Destroy-time provisioners and their connection configurations may only
reference attributes of the related resource, via 'self', 'count.index',
or 'each.key'.

References to other resources during the destroy phase can cause dependency
cycles and interact poorly with create_before_destroy.
```

This means that, if you want to continue to reference this external data inside of a destroy-time provisioner, in order to ensure these values are available, you just need to modify the above null\_resource slightly:

First, we need to, before the provisioner block, define a map of triggers so when Terraform can reference these objects as part of its class when this destroy event occurs, so in order to, for example, reference your variables, your map should look like:

```
resource "null_resource" "delete_cluster" {

triggers = {
    cluster_uuid = lookup(data.external.create_cluster.result, "cluster_id")
    cluster_fqdn = var.cluster_fqdn
    cluster_user = var.cluster_user
    cluster_password = var.cluster_password
    cluster_tenant = var.cluster_tenant
    cluster_region = var.cluster_region
  }
```

and then to reference them in the plan, you simply use self.triggers.[key] :

```
provisioner "local-exec" {
    when = destroy
    command = "printf '{\"du_fqdn\": \"${self.triggers.cluster_fqdn}\", \"user\": \"${self.triggers.cluster_user}\", \"pw\": \"${self.triggers.cluster_password}\", \"tenant\": \"${self.triggers.cluster_tenant}\", \"region\": \"${self.triggers.cluster_region}\", \"cluster_uuid\": \"${self.triggers.cluster_uuid}\"}' | python3 ${path.module}/scripts/delete_cluster.py"
    environment = {
      du_fqdn = self.triggers.cluster_fqdn
      user = self.triggers.cluster_user
      pw = self.triggers.cluster_password
      tenant = self.triggers.cluster_tenant
      region = self.triggers.cluster_region
      cluster_uuid = self.triggers.cluster_uuid
    }
  }
}
```

More about other Terraform upgrade (to 0.13 and beyond) concerns can be found [here](https://www.terraform.io/upgrade-guides/0-13.html).