I am a long time Terraform user. The number of providers that are available for Terraform, and having a resource for pretty much every cloud service makes it super appealing. But even with several years of production usage, I still find myself scratching my head at times when I’m writing my interpolations. Terraform provides a really nice shell to assist with this, and it can be accessed with the terraform “console” option:
$ terraform console
Once you are in the shell, typing an expression will produce immediate feedback:
> list("a","b","c")[0]
> a
The expression above creates a list, and then displays the first element in it. A more realistic example would be grabbing a given subnet from a list:
> aws_subnet.vpc-foo-public-subnets-proxies.*.id[0]
subnet-0a211c324068d847e
In this example I use the splat operator to get all subnets in a list, and then display the subnet in index 0. The console is also super useful for playing with data sources. To see what a data source contains, you can type it into the console:
> data.aws_availability_zones.available
{
"group_names" = [
"us-east-1",
]
"id" = "2020-04-26 14:08:51.531061491 +0000 UTC"
"names" = [
"us-east-1a",
"us-east-1b",
"us-east-1c",
"us-east-1d",
"us-east-1e",
"us-east-1f",
]
"state" = "available"
"zone_ids" = [
"use1-az2",
"use1-az4",
"use1-az6",
"use1-az1",
"use1-az3",
"use1-az5",
]
}
Once you see the structure (maps, lists, strings etc.), you can use the built-in functions to massauge the data to your liking:
> slice(data.aws_availability_zones.available.names,2,4)
[
"us-east-1c",
"us-east-1d",
]
One other super useful feature is the ability to play with maps. You can retrieve map values:
> lookup(map("a","avalue","b","bvalue"), "a")
avalue
Or the keys that comprise a map:
> keys(map("a","avalue","b","bvalue"))
[
"a",
"b",
]
Or both the keys and their values:
> { for k, v in map("a", "one", "b", "two"): v => k }
> {
> "one" = "a"
> "two" = "b"
> }
As of Terraform 0.12, you now have the ability to use for, for_each and logic operators ( x ? y : z existed previously) in your HCL. Testing logic operations in the console is as easy as:
> keys(map("a","avalue","b","bvalue"))[0] == "a" ? "true" : "false"
true
> keys(map("a","avalue","b","bvalue"))[0] == "ab" ? "true" : "false"
false
The same goes for testing looping logic:
> [for string in ["one", "two", "three"] : upper(string)]
[
"ONE",
"TWO",
"THREE",
]
> [ for key in keys(map("a", "one", "b", "two")) : key ]
[
"a",
"b",
]
> [ for value in map("a", "one", "b", "two") : value ]
[
"one",
"two",
]
The console has become my best friend when writing Terraform code. I can test my code in the shell, then commit it once I know it will produce the result I want. This also reduces the number of times I need to come back to my code after reviewing my terraform plans. Viva la Terraform!