All checks were successful
Build and Deploy Hugo Site / deploy (push) Successful in 2m24s
82 lines
2.2 KiB
Markdown
82 lines
2.2 KiB
Markdown
---
|
|
title: "Index out of range in terrafrom"
|
|
date: "2026-03-26"
|
|
tags:
|
|
- terraform
|
|
- oops
|
|
categories:
|
|
- iac
|
|
---
|
|
|
|
Accidently nuked half of some resources and broke DNS (yes, it is in fact always DNS). One of the first things I learned and is on a lot of guides for terraform is how `count` works. It's one of the meta-arguments you can use with most resources, others are
|
|
|
|
```
|
|
depends_on
|
|
count
|
|
for_each
|
|
provider / providers
|
|
lifecycle
|
|
```
|
|
|
|
Here's an example for count before I show my oops.
|
|
|
|
```hcl
|
|
variable "names" {
|
|
default = ["alice", "bob", "carol"]
|
|
}
|
|
|
|
resource "aws_instance" "web" {
|
|
count = length(var.names)
|
|
ami = "ami-0c55b159cbfafe1f0"
|
|
instance_type = "t3.micro"
|
|
|
|
tags = {
|
|
Name = var.names[count.index]
|
|
}
|
|
}
|
|
```
|
|
|
|
Remove `"bob"` → `default = ["alice", "carol"]`. You'll see this in your terraform run of web[1] transitioning.
|
|
|
|
```
|
|
~ Name = "bob" -> "carol"
|
|
```
|
|
|
|
|
|
carol shifts from index 2 → 1, so Terraform modifies the bob instance to become carol, and destroys the old carol. Two changes instead of one.
|
|
|
|
`count` is very quick and easy to use but honestly I avoided it. If I read of a feature that has to be used with extra considerations, I'd rather use the pattern that doesn't let me screw up if my coffee has fully kicked in.
|
|
|
|
---
|
|
|
|
In my case, I added to middle of an array in a variable but the implementation logic was a count instead of a `for_each`.
|
|
|
|
Here's an implementation that guarentess uniqness in the array to avoid collisions and doesn't care about order.
|
|
|
|
|
|
```hcl
|
|
# Before (vulnerable — index shuffle on any list change)
|
|
resource "aws_instance" "web" {
|
|
count = length(var.names)
|
|
ami = "ami-0c55b159cbfafe1f0"
|
|
instance_type = "t3.micro"
|
|
|
|
tags = {
|
|
Name = var.names[count.index]
|
|
}
|
|
}
|
|
|
|
# After (safe — each instance is an independent resource)
|
|
resource "aws_instance" "web" {
|
|
for_each = toset(var.instances)
|
|
ami = "ami-0c55b159cbfafe1f0"
|
|
instance_type = "t3.micro"
|
|
|
|
tags = {
|
|
Name = each.key
|
|
}
|
|
}
|
|
```
|
|
|
|
Even better is that with the first method you access the resource like `aws_instance.web[0]` but with the 2nd you get a much more descriptive and assuring `aws_instance.web["bob"]`
|
|
|