Terraform Pitfalls and Gotchas
I’ve been playing with terraform for a bit now and wanted to relay my experiences with the tool. Here are some interesting gotchas you may run into.
Plans are green until they’re not
Let’s say your plan goes smoothly, you’re about to stand up your awesome new architecture. Everything is nice and green. You run terraform apply
and see something like this:
Error: Error launching source instance: VPCIdNotSpecified: No default VPC for this user
status code: 400, request id: 67c7c54b-5e89-4b78-9a8a-69f56329dbf1
on main.tf line 14, in resource "aws_instance" "web":
14: resource "aws_instance" "web" {
Okay, this makes sense. My “web” instance(s) are don’t know the VPC. So maybe we can set a vpc_id = module.vpc.vpc_id
for ec2 instances? wrong
Sometimes even though your plan looks fine the deploy will not work. Luckily terraform knows what has been deployed and can simply update the stuff it was missing if you can get your recipe just right.
Terraform relationship and ID puzzle
This time testing module.vpc.vpc_id
plan fails :
Error: Unsupported argument
on main.tf line 21, in resource "aws_instance" "web":
21: vpc_id = module.vpc.vpc_id
Being the studious developer we are we google to find that you can’t specify a vpc_id with an ec2 instance and it doesn’t get that from vpc_security_group_ids
for some reason, however it does get the vpc from the subnet! Okay awesome.
Our plan said that module.vpc.aws_subnet.public[0] and module.vpc.aws_subnet.public[1] will be created because the plan shows us!
# module.vpc.aws_subnet.public[0] will be created
+ resource "aws_subnet" "public" {
...(omitted)
+ id = (known after apply)
...(omitted)
+ vpc_id = (known after apply)
}
Knowing that we can use the new terraform 0.12 built in count.index
and armed with this new information we immediately set subnet_id = module.vpc.aws_subnet.public[count.index].id
and are confident we have solved the problem.
Our confidence is quickly destroyed as we run our next plan.
Error: Reference to undeclared output value
on main.tf line 22, in resource "aws_instance" "web":
22: subnet_id = module.vpc.aws_subnet.public[count.index].id
An output value with the name "aws_subnet" has not been declared in
module.vpc.
So terraform can definitely plan a set of subnets but secretly hides where they are from us so that we don’t know. Through some more google foo we find the vpc module actually references them at module.vpc.public_subnets
and since we have no idea what the underlying id is we can assume to use .id
or possibly .subnet_id
since the vpc itsels is referenced by .vpc_id
.
Plan doesn’t like us again:
Error: Unsupported attribute
on main.tf line 22, in resource "aws_instance" "web":
22: subnet_id = module.vpc.public_subnets[count.index].id
|----------------
| count.index is 1
| module.vpc.public_subnets is tuple with 2 elements
This value does not have any attributes.
Since this feels close we try .subnet_id
blindly and get nothing. Only to hope beyond hope that terraform actually tells us when we take off the last dot element and use subnet_id = module.vpc.public_subnets[count.index]
but that makes plan go green and we now expect the deploy to fail with some error… except it works!???
Conclusion
I had even more gotchas for this post but I feel like this is a great overview of some issues you may face. Terraform is a very cool tool with a growing community but has a lot of what I like to call “intrinsic knowledge points” where once you’ve faced something 42 times you just know it and move on assuming everyone will figure it out. A good example of this is how everyone just knows that when your SNES cartridge doesn’t boot you blow on it.
Maybe you want a fun challenge, a new way of managing cloud architecture, or your current solution isn’t cutting it AND you don’t mind some pain. If so feel free to check Terraform out. It is “platform agnostic” that being said, plans do not work across platforms and you’ll have to have specific platform files and variables for each platform.
Hopefully 2.0 gets us closer to agnostic easy platform management tool it could be.