25
votes

I have a Terraform 0.11 project with 30-40 different resources. I would like to delete all of them except a few - and those few are logically related to each other.

I was looking for something close to terraform destroy --except=resource-id but that of course doesn't exist.

Is there a way to achieve that without too much scripting (Terraform admins have various OSs)? Would using modules make that process easier perhaps?

3
The answer is to not structure your code base this way. Things in the same directory should all be creatable or destroyable at the same time. Part applying changes is an escape hatch, not something to rely on.ydaetskcoR
@ydaetskcoR This makes sense. I would accept this answer, if you can write it uprath
It feels like it might be a duplicate, let me have a dig around, otherwise I'll write it up as an answer here.ydaetskcoR
what about eips? say for example you had these whitelisted and don't want to destroy them because you need a change control elsewhere, you set Terraform to create and mark wit prevent_destroy, all prevent_destroy does here is to fail your terraform destroy command. You could create the eip outside terraform and just manage the association, but both feel like this could be handled betterkrystan honour

3 Answers

52
votes

There is no exist feature in terraform destroy command currently. If you really want to do that, and you know what you do, here is the workaround.

# list all resources
terraform state list

# remove that resource you don't want to destroy
# you can add more to be excluded if required
terraform state rm <resource_to_be_deleted> 

# destroy the whole stack except above excluded resource(s)
terraform destroy 

So why do these commands work for your idea?

The state (*.tfstate) is used by Terraform to map real world resources to your configuration, keep track of metadata.

terraform state rm cleans a record (resource) from the state file (*.tfstate) only. It doesn't destroy the real resource.

Since you don't run terraform apply or terraform refresh, after terraform state rm, terraform doesn't know the excluded resource was created at all.

When you run terraform destroy, it has no detail about that excluded resource’s state and will not destroy it. It will destroy the rest.

By the way, later you still have chance to import the resource back with terraform import command if you want.

6
votes

Targetting each resource (while skipping over the data resources) except the one you want is probably the only way atm:

#! /bin/bash

while read -r resource; do
    terraform destroy -target="$resource"
done < <(terraform state list | grep -vE "^data\." | grep -vE "dont_remove|also_important")
0
votes

I have a bit of a different work around. The resources I do not want to delete with "terraform destroy" I create as "null_resource" using a provisioner with CLI. You can still use your variables in terraform as well.

for example (Create a resource group, but it is persistent due to null_resource)

resource "null_resource" "backend-config" {
        provisioner "local-exec" {
        command     = <<EOT
    az group create --location ${var.Location} --name ${var.Resource_group_name} --tags 'LineOfBusiness=${var.Lob}' 'Region=${var.Region}' 'Purpose="Terraform-Primary-Resource-Group-${var.Lob}'
    EOT
        interpreter = ["Powershell", "-Command"]
      }
    }

Now if you destroy the resources using terraform destroy. Any null_resource will remain intact.