HashiCorp Terraform 0.12 Preview: Generalized Splat Operator

HashiCorp Terraform 0.12 Preview: Generalized Splat Operator

Jul 19 2018 Martin Atkins

This is the fourth post of the series highlighting new features in Terraform 0.12.

As part of the lead up to the release of Terraform 0.12, we are publishing a series of feature preview blog posts. The post this week is on the new generalized splat operator.

Terraform has always supported a special syntax to obtain a list of attribute values from a set of resources created using the count argument, known as a "splat expression." In Terraform 0.12, we've generalized this to work with any list values and call it the "splat operator."

» Splat Operator

In Terraform 0.11 and earlier, the value of an attribute for a set of resources created with count could be obtained using something called a "splat expression." The example below shows this in use:

# Configuration for Terraform 0.11 and earlier

output "instance_names" {
  value = google_compute_instance.main.*.name
}

The splat expression was previously a special-case operation only for attributes on resources with count and didn't work for any other list values. For Terraform 0.12, we've generalized the operation to work for any list value and are calling the syntax the "splat operator."

The example below shows the splat operator in use for an arbitrary list value on a single resource that doesn't have count set.

# Configuration for Terraform 0.12

output "instance_ip_addrs" {
  value = google_compute_instance.example.network_interface.*.address
}

In the above example, the specific single-count resource google_compute_instance.example is specified, and the splat operator is used to flatten the list of network interface addresses into a single list.

» Full Splat Operator

The splat syntax in Terraform 0.11 and earlier has a limitation that it only allows accessing named attributes of the items in the given list. This led to common and confusing expressions like google_compute_instance.main.*.name[count.index] as a way to access the name of an instance identified by a specific index. Terraform 0.12 now allows that to be expressed more intuitively as google_compute_instance.main[count.index].name, with the old form retained for backward compatibility.

A new variant of the splat operator known as the "full splat operator", is supported in 0.12 as a way to conveniently access both attributes and indexes within a given list:

# Configuration for Terraform 0.12

output "instance_net_ip_addrs" {
  value = google_compute_instance.example.network_interface[*].access_config[0].assigned_nat_ip
}

Placing the asterisk symbol inside indexing brackets rather than using it as an attribute name activates the full splat behavior, causing access_config[0] to be interpreted as part of the access into each of the network interfaces. Replicating this behavior in Terraform 0.11 and earlier required function calls and unintuitive syntax.

We recommend using the full splat syntax for all new configurations since its behavior is generally more intuitive. The older syntax is retained for backwards compatibility but is not recommended.

» Upgrade Guide

Terraform 0.12 continues to support the previous splat operator usage in most cases, but does introduce two important breaking changes.

First, the handling of resources with count set has been slightly changed in Terraform 0.12. Referencing the resource without an index now results in a list of all of the instances, rather than behaving as an alias for the first instance. For any resource where count is set — even if it is set to 1 — the first instance must be accessed by indexing with [0], such as aws_instance.example[0].id.

The example below will behave differently in Terraform 0.12:

# Configuration for Terraform 0.11 and prior

resource "aws_instance" "web" {
  count = 1
    ...
}

output "id" {
  value = "${aws_instance.web.id}" // Value is the ID of index 0
}

The example converted to Terraform 0.12:

# Configuration for Terraform 0.12

resource "aws_instance" "web" {
  count = 1
    ...
}

output "id" {
  value = "${aws_instance.web[0].id}"
}

In most cases, Terraform 0.12 will error due to this change. If the expected value is not a list, then an error will be shown. As always, please review plan output to verify Terraform is behaving as expected and to catch any configuration changes necessary.

The second breaking change is the removal of some legacy backward-compatibility behavior for splat expressions. Early versions of Terraform required splat expressions to appear interpolated into a list constructor, like ["${aws_instance.example.*.id}"], but this requirement was lifted in Terraform 0.9.6 and this form was deprecated. In Terraform 0.12, that expression now produces a list of lists, since the splat expression produces a list itself and then the outer brackets wrap that result in another list. This is generally expected behavior but may be surprising for long-time Terraform users.

» Next

This was part 4 of the blog post series previewing Terraform 0.12.

The generalized splat operator will be released in Terraform 0.12, coming later this summer. To learn more about how to upgrade to Terraform 0.12, read the upgrade instructions which will be continuously updated as we get closer to releasing Terraform 0.12. If you have any feedback or concerns about these changes, please communicate with the Terraform team via the public mailing list.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×