Home > OS >  Acquiring subnet availability zone ids in bulk, in a module
Acquiring subnet availability zone ids in bulk, in a module

Time:07-26

The module I'm working on represents one app which is deployed to a VPC. The VPC is declared elsewhere.

The relevant data path includes these resources:

variable "vpc_id" { }

data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.vpc.id]
  }

  filter {
    name = "tag:Visibility"
    values = ["private"]
  }
}

data "aws_subnet" "private" {
  for_each = toset(data.aws_subnets.private.ids)

  vpc_id = data.aws_vpc.vpc.id
  id = each.value
}

resource "aws_rds_cluster" "database" {
  availability_zones = data.aws_subnet.private.*.availability_zones
}

That feels like the correct syntax, though it is a verbose chain of data retrieval. However, when I terraform plan it:

│ Error: Unsupported attribute
│ 
│   on ../../../../../appmodule/rds_postgres.tf line 23, in resource "aws_rds_cluster" "webapp":
│   23:   availability_zones = data.aws_subnet.private.*.availability_zone_id
│ 
│ This object does not have an attribute named "availability_zone_id".

I'm using aws-provider 4.18.0 and Terraform v1.1.2. The documentation for the subnet data source shows that availability_zone_id

Am I missing something obvious here?

CodePudding user response:

As mentioned in the comments, you can get the list of AZs by using the values built-in function [1]. This is necessary as the data source you are relying on to provide the AZs is in a key value format due to for_each meta-argument use:

data "aws_subnet" "private" {
  for_each = toset(data.aws_subnets.private.ids)

  vpc_id = data.aws_vpc.vpc.id
  id = each.value
}

The change you need to make is:

resource "aws_rds_cluster" "database" {
  availability_zones = values(data.aws_subnet.private)[*].availability_zone
}

A test with an output and a default VPC shows the following result:

    subnet_azs = [
        "us-east-1b",
        "us-east-1c",
        "us-east-1d",
        "us-east-1a",
        "us-east-1f",
        "us-east-1e",
    ]

As you can see, it is already a list so you can use it as is.

Note that there is an explanation why you should use the availability_zone attribute:

availability_zone_id - (Optional) ID of the Availability Zone for the subnet. This argument is not supported in all regions or partitions. If necessary, use availability_zone instead


[1] https://www.terraform.io/language/functions/values

  • Related