AWS Advent: Where are They Now?

Last November, I wrote an article for the 2016 AWS Advent, which you can find here and here.

As luck would have it, a mere week after it went live in the advent, HashiCorp went and released version 0.8.0 of Terraform, rendering a few important parts of the article obsolete via way of first-class support for things like ternary logic. And since then, Terraform 0.9.0 has been released (around mid-March to be specific), bringing even more goodies, such as the long awaited ability to use a computed count value in data sources, making data sources much more useful.

Let’s touch on these and some other of the more useful core updates:

The Ternary Operator

The Ternary operator adds first-class support for basic conditional logic to Terraform. Interpolation operations can now render output based on a conditional if-then-else expression in an EXPR ? THEN : ELSE form.

This can still be used to do things like toggle resources in the graph. Let’s take an example from the advent article where we toggle an AWS ALB target group in the autoscaling module. This used to be written as:

// autoscaling_alb_target_group creates the ALB target group.
resource "aws_alb_target_group" "autoscaling_alb_target_group" {
  count    = "${lookup(map("true", "1"), var.enable_alb, "0")}"

This can now be written as:

// autoscaling_alb_target_group creates the ALB target group.
resource "aws_alb_target_group" "autoscaling_alb_target_group" {
  count    = "${var.enable_alb == "true" ? "1" : "0" }"

Much simpler. 🙂

Count In Data Sources

Terraform 0.9.0 brought partial support for the ability for a computed count to be available within data sources. As long as all computed counts can be evaluated during the planning phase, Terraform will not kick back an error to you.

This means that a computed count is still not permitted when the computed variable comes from the result of a resource – basically if there’s absolutely no way for Terraform to know what your count is going to be before it starts its run, you’re out of luck.

Support for this will more than likely be coming at some point in time though through a in-development feature currently referred to as a partial apply. You can follow the effort here.

Remote State Configuration Files

terraform remote config was dropped as a command in 0.9.0 as well. You now use backends in a terraform configuration stanza to define remote state configuration, and then terraform init to write the .terraform/terraform.tfstate stub state file with the correct remote state configuration in it.

It should also be noted that via this stub state is now the only thing that gets saved to the .terraform/terraform.tfstate file. State is not cached anymore, preventing the leaking of sensitive data via artifacts from a Terraform run, or edge cases that can happen with existing state (as an example, enabling KMS on an existing S3-stored Terraform state was problematic because the initial pull of the non-KMS encrypted state blew away the new remote state configuration).

State Environments

Related to this change is the concept of state environments. These are namespaces that can be used to store state for different sets of resources that share a common configuration, such as development and production. This is normally something that you would have needed to accomplish yourself via a specific namespace in your remote state, but now can be accomplished via the terraform env command.

One Gotcha – No Interpolations

Unfortunately, the current remote state configuration scheme does not support interpolations. This may be a blocker for you if you need a bit more advanced parameterization of your environments, such as purpose and region (such as if you need to differentiate between development in ca-central-1, and development in us-west-2, for example).

One way around this is to move your conditional logic to your environment name purely. You can then use the terraform env commands to switch to this state when needed, such as in scripts in your CI pipeline.

Emulating Pre-0.9.0 Behaviour

If you’re not quite ready to switch your state management yet, but want 0.9.x for the other amazing features, you can kind of emulate the previous terraform remote config behaviour by scripting the process of dropping in an automatically-generated file and running terraform init. Check out this gist which will give you the building blocks you need to update your scripts accordingly.