[SOLVED] Unclear syntax in TF 0.12 for lists from count based resources

I have the following aws_subnet definition:

resource "aws_subnet" "private-db" {
  count             = 2
  vpc_id            = aws_vpc.app.id
  cidr_block        = cidrsubnet(aws_vpc.app.cidr_block, 3, count.index)
}

And the following aws_db_subnet_group definition:

resource "aws_db_subnet_group" "main" {
  name       = local.prefix
  subnet_ids = ["${aws_subnet.private-db.*.id}"]
}

I am not clear on what is the proper syntax to use to provide the list of subnet_ids here. I always get this or a similar error during planning:

Error: Incorrect attribute value type

  on database.tf line 24, in resource "aws_db_subnet_group" "main":
  24:   subnet_ids = ["${aws_subnet.private-db.*.id}"]
    |----------------
    | aws_subnet.private-db is tuple with 2 elements

Inappropriate value for attribute "subnet_ids": element 0: string required.

I’ve tried the following syntax’s:

  • aws_subnet.private-db
  • aws_subnet.private-db.*.id
  • [aws_subnet.private-db]
  • [aws_subnet.private-db.*.id]
  • list(aws_subnet.private-db.*.id)
  • "${aws_subnet.private-db.*.id}" - This works in 0.11
  • "${list(aws_subnet.private-db.*.id)}"

What is the proper syntax to use in this scenario?
What don’t I understand about how Terraform 0.12 processes this situation different from 0.11?

Please advise.

1 Like

I don’t really know what happened, but this syntax worked eventually:

resource "aws_db_subnet_group" "main" {
  name       = local.prefix
  subnet_ids = aws_subnet.private-db.*.id
  tags = {
    Name = local.prefix
  }
}
1 Like

Hi @madpipeline,

Thanks for following up! I’m glad you found the solution, and I thought you might appreciate some explanation as to why that was the solution…

  • aws_subnet.private-db.*.id returns a list of ids
  • [ ... ] constructs a list from the values inside the brackets.
  • Therefore [aws_subnet.private-db.*.id] returns a list of lists.

Since what you needed here is just a flat a set of ids, rather than a list of lists of ids, aws_subnet.private-db.*.id is the appropriate syntax. (Terraform will automatically convert the list of ids into a set of ids as required for the subnet_ids argument.)

The form ["${aws_subnet.private-db.*.id}"] was working in Terraform 0.11 because Terraform 0.11 was preserving compatibility with a legacy syntax from Terraform 0.6, from before the Terraform language had real support for lists and it was just modelling lists as special delimited strings. Terraform 0.12 finally removed that backward-compatibility mechanism that was causing the list of lists to be flattened into a single list, and so it’s no longer valid to use a list of lists where a list is expected.

As you noted, "${aws_subnet.private-db.*.id}" was also valid (and preferred) in Terraform 0.11, and should work in Terraform 0.12 as well. Terraform 0.12 removed the requirement that all expressions appear as interpolations into strings, but it’s still supported as a deprecated form for backward compatibility.

3 Likes

Thanks for the explanation.