top of page
  • Paul Zietsman

terraform | a better way to loop

Resource looping has come a long way since I started using terraform, and with 0.13 around the corner it is time for us to say goodbye to count.


If you are new to terraform or have not really built dynamic environments, let’s quickly recap what count is. Imagine you have to manage security groups in AWS. To achieve this you create a aws_security_group resource and copy-pasta it a few times, changing the relevant arguments.

Quickly you realize this is not fun, so you create a variable to hold all the security group arguments. An oversimplified variable might look something like this:


Next, you make a few changes to your security group and implement count. The resource might look something like this:


Running an apply returns a summary that 3 security groups were created:



Your team starts using these security groups. A few months later the security group allowing the 10.0.0.0/16 range needs to be removed. Easy, you just remove the second entry on the list. But you now see something weird in the plan:


You expected to see one resource being destroyed, what is terraform trying to change? This is where the problem with count shows itself.


The problem

When using count, terraform only has the index of the variable to reference the resource by. In this scenario, sg-038b will be removed and sg-08f8 will have its CIDR updated from 10.0.0.0/16 to 11.0.0.0/16. This is bad since resources depending on sg-038b will have their security group removed.


To solve this we need to have a more “stable” pointer to the items in a list to avoid this behavior. This is wherfor_each comes to the rescue.

for_each


For each allows you to loop over a map or set of strings. A set of strings only contain unique values and maps cannot have duplicate keys, this means you have some unique pointer to each resource.


If you have a list of strings that has duplicates and you need that, then for_each will not work for you.


So let’s have a look at how we can modify our code to use for_each instead of count.


The easiest would be to change our input variable to a map where the name of the security group becomes the key in the map:


You’ll need to make a few changes to the resource, instead of referencing each object by the index in the list, you will now have an object with a key and value property.


Your apply will now look something like this:


Now notice that terraform has a unique and stable reference to each provisioned resource. If we now remove the sg-b entry we will only see one resource being destroyed.


And you are done, but what happens if you do not have control over what this variable looks like, it could be that you read if from another team’s terraform backend or that it's the output from another resource.


Let’s convert the list to a map.


Using thfor expression you are able to construct new lists or maps for a variety of input. The expression returns the index/key and the value of each item. You can nest multiple for expressions if you have more complex data structures.


This local variable can be used in place of the simple_map variable.


When constructing a map and you are using nested for expressions, the key of the map needs to be created in the “root” for expression. Sometimes you need to create intermediary local variables to get to your final structure when using complex data structures.


tldr;

Terraform has given us all the tools we need to not have to use count anymore. Count can lead to unexpected side effects, especially when building complex dynamic environments, having a stable pointer to a resource created with terraform will save future you a ton of headaches.

2 views0 comments

Comments


Commenting has been turned off.
bottom of page