How to remove the resource from specific index of count

Hello all,

I have Terraform SQL module, which was created with COUNT parameter for DB parameters in Azure. I have passed 3 DB’s, DB1, DB2 and DB3 to it and 3 DB’s created.

DB1is Index 0, DB2 is Index 1 and DB3 is at Index 2.

When i was removing the DB2, terraform is trying to shift the DB3 to Index 1 and deleting the DB3 of Index 2

however, i don’t want to delete the DB3. Is there a way to delete the DB2 only at Index 1 location without disturbing the DB1 and DB3

Regards,
Venkat.

Hi @venkatchkala88,

When you use count Terraform understands that to mean that all of your resource instances are equivalent and so it shouldn’t matter which one gets destroyed when the count decreases.

For situations like yours where each database is unique and special, it’s more appropriate to use the for_each argument and specify a meaningful name for each of the instances, which then means you can remove a particular key without affecting any others.

For example:

resource "example" "example" {
  for_each = toset(["db1", "db2", "db3"])

  # ...
}

If you had created the instances like above then you could remove db2 from the set of strings and Terraform will know exactly which instance you intend to remove, and will preserve the one you named “db3” because that name is still present in the set.

If you are using Terraform v1.1 or later then you can migrate to using for_each at the same time as you remove “db2” by using the refactoring features:

# I'm using example.example here because you didn't
# mention exactly which resource type you are working
# with. You should replace this with the real resource type
# and resource name you are using, both here and in the
# "moved" blocks that follow.
resource "example" "example" {
  for_each = toset(["db1", "db3"])

  # ...
}

moved {
  from = example.example[0]
  to   = example.example["db1"]
}

moved {
  from = example.example[1]
  to   = example.example["db2"]
}

moved {
  from = example.example[3]
  to   = example.example["db3"]
}

The configuration above will tell Terraform how to map your existing count-based indexes to the new instance keys chosen by for_each, so Terraform will first translate your existing instances from numeric keys to string-based keys. After it’s done so, it will notice that example.example["db2"] is no longer declared in the configuration and propose to destroy it. Therefore you should be able to apply the plan and have it keep both “db1” and “db3”, and only destroy “db2”.

If you try this, make sure to inspect the plan to make sure Terraform reports only that db1 and db3 have moved, without proposing to modify them in any way. The only real action you should see in the plan is the one proposing to delete example.example["db2"].

(You can choose whichever instance key strings you like when you do this, as long as you’re consistent. If there’s something more meaningful than just “db1” – for example, the name of the application or customer that the database belongs to – then I would suggest using that instead so that it’s easier for future maintainers to clearly see what is special about each of these instances.)

1 Like

Hello,

Currently the code is in production and databases are running with COUNT parameter. I need the solution for removing the DB index-1 with existing code before changing the code to FOR_EACH.

Regards,
Venkat.

Hi @venkatchkala88,

What you want to achieve isn’t possible, because count is for situations where all of the instances are equivalent and so deleting the instance with index 2 would be the same as deleting index 3.

If these instances are each unique and you need to be able to treat them differently then you will need to switch to using for_each so that there will be a way for you to describe to Terraform exactly which of the instances should be deleted, using its key.

The code I provided should allow you to switch to for_each and remove the instance you want to remove. If you instead want to achieve this in two separate steps then you will need to complete the step to move to for_each first, and then you can separately destroy the instance.

Here is a slightly different version of the code I previously shared which will move to for_each without destroying any of the instances:

resource "example" "example" {
  for_each = toset(["db1", "db2", "db3"])

  # ...
}

moved {
  from = example.example[0]
  to   = example.example["db1"]
}

moved {
  from = example.example[1]
  to   = example.example["db2"]
}

moved {
  from = example.example[3]
  to   = example.example["db3"]
}

The difference here is that "db2" is still in the for_each of the resource, so Terraform will see that it shouldn’t be deleted yet. Therefore if you apply this change Terraform should report only that these three instances have moved to new addresses, and should not propose to delete anything.

Once you apply that change to update the resource instance keys in the state, you can then separately remove "db2" from the for_each argument and run terraform apply again, and then Terraform will propose to delete only that instance.

1 Like