Search code examples
amazon-web-servicesterraformterraform-provider-awsaws-security-group

Terraform Splat Expression Giving "Invalid template interpolation value"


I am using data sources in Terraform to fetch a list of ids of my security groups as such:

data "aws_security_groups" "test" {
  filter {
    name   = "group-name"
    values = ["the-name"]
  }
}

output "security_group_id" {
  value = "The id is ${data.aws_security_groups.test.ids[*]}"
}

However, this is giving me the following error:

Error: Invalid template interpolation value

on main.tf line 11, in output "security_group_id":
  11:   value = "The id is ${data.aws_security_groups.test.ids[*]}"
    |----------------
    | data.aws_security_groups.test.ids is list of string with 1 element

Cannot include the given value in a string template: string required.

But if I use data.aws_security_groups.test.ids[0] instead it displays the ID.

Can someone help me to display the list of IDs?


Solution

  • First, I want to note that you don't necessarily need to combine this list with a string message at all if you don't want to, because Terraform will accept output values of any type:

    output "security_group_ids" {
      value = data.aws_security_groups.test.ids
    }
    

    If having them included as part of a bigger string is important for your underlying problem then you'll need to make a decision about how you want to present these multiple ids in your single string. There are various different ways you could do that, depending on what you intend to do with this information.

    One relatively-straightforward answer would be to make the string include a JSON representation of the list using jsonencode, like this:

    output "security_group_id_message" {
      value = "The ids are ${jsonencode(data.aws_security_groups.test.ids)}"
    }
    

    If you want a more human-friendly presentation then you might prefer to use a multi-line string instead, in which case you can customize the output using string templates.

    output "security_group_id_message" {
      value = <<-EOT
      The ids are:
      %{ for id in data.aws_security_groups.test.ids ~}
      - ${id}
      %{ endfor ~}
      EOT
    }
    

    Or, for an answer somewhere in between, you could use join to just concatenate the values together with a simple delimiter, like this:

    output "security_group_id_message" {
      value = "The ids are ${join(",", data.aws_security_groups.test.ids)}"
    }
    

    Note that I removed the [*] from your reference in all of these examples, since it isn't really doing anything here: data.aws_security_groups.test.ids is already an iterable collection, and so is compatible with all of the language features I used in the examples above.

    IIRC the provider considers this ids attribute to be a set of strings rather than a list of strings, and so that [*] suffix could potentially be useful in other situations to force converting the set into a list if you need it to be typed that way, although if that is your intent then I'd suggest using one of the following instead so that it's clearer to a future reader what it does:

    • sort(data.aws_security_groups.test.ids) (if it being in lexical order is important to the behavior; Terraform uses lexical sorting by default anyway, but calling sort is a good prompt to a reader unfamiliar with Terraform to look up that function to see what the actual sort order is.)
    • tolist(data.aws_security_groups.test.ids) (functionally equivalent to sort above when it's a set of strings, but avoids the implication that the specific ordering is important, if all that matters is that it's a list regardless of the ordering)