Issue with sequencing a delete/create

I am looking for a solution for the following issue.

I have an existing module A with a resource A that writes a consul policy.

  *name = "${ var.application }.${ var.component }"*

  consul_policy = <<EOT
   ..... (suppressed)

and this resource is currently applied in the environment.

Now I created a new Module B (to replace Module A), which has a new resource B (and no more of Resource A)

resource "vault_consul_secret_backend_role" "vault-backend-role" {
  name    = "${ var.application }.${ var.component }"
  backend = "consul"

  policies = [
    "${ var.application }-${ var.component }",

On execution of Module B, I am expecting the resource “vault_consul_role” “consul-policy” to be deleted, and new resource “vault_consul_secret_backend_role” "vault-backend-role get created.

Now here is the issue I run into.
Since both Resource A and Resource B writes the same policy in Consul, during the terraform execution, occasionally the deletion of Resource A happens after Resource B creation, thereby deleting the policy from Consul.

I am trying to see if there is way to force the Resource B to execute only after Resource A is deleted. I cannot put a depends condition, as the Resource A is not in Module B.

Here is an actual O/p from terraform apply for clarity of the issue

Creation of Resource B in Module B
module.k8s-istioproxy-vault-policy.vault_consul_secret_backend_role.vault-backend-role: Creation complete after 0s (ID: consul/roles/k8s.istioproxy)

Deletion of Resource A  (Since it is no longer in module B)
module.k8s-istioproxy-vault-policy.vault_consul_role.consul-policy: Destruction complete after 0s

This causes the policy to be deleted, and I have to rerun the apply step once more to get the policy create thru Resource B.

My terraform version is 11.7

Any help to solve this is much appreciated.

Hi @kadavil,

It sounds like the problem you have here is a one-time migration problem as you do some refactoring, in which case I think the most straightforward answer could be to explain this to Terraform as the same existing object now being bound to a new resource, rather than as a destroy followed by a create.

You can do that by running the following command just before you apply the change, which will modify your existing state to place the same object under the management of a new Terraform resource instance:

terraform state mv module.k8s-istioproxy-vault-policy.vault_consul_role.consul-policy module.k8s-istioproxy-vault-policy.vault_consul_secret_backend_role.vault-backend-role

If you do this and then run terraform apply then Terraform should see that module.k8s-istioproxy-vault-policy.vault_consul_role.consul-policy is already gone – in the sense that there is no remote object attached to it anymore – and it will understand this configuration as calling for an update or replace of the new resource, depending on whether the change you’ve made here can be handled as an update.

The disadvantage of this approach is that you’ll need to coordinate the state modification to happen just before you apply the configuration change, because if you modify the state and then don’t modify the configuration Terraform will find an object in the state that isn’t in the configuration and plan to destroy it.

Another option, if the above isn’t appropriate in your case, could be to use the -target option as a one-off exception to give Terraform an extra hint to understand that you need a particular sequence operations here:

terraform apply -target=module.k8s-istioproxy-vault-policy.vault_consul_role.consul-policy
terraform apply

The first command above should cause Terraform to do all of the operations up to and including the delete of the existing policy. Then the second normal terraform apply with no arguments will allow Terraform to apply the remaining changes, including creating the new object.