Grouping By A Value In An Object Generated In For Loop

32 views Asked by At

I figure this is probably covered by another SO post somewhere but I'm struggling to find it so here goes.

Description

I am attempting to build a local set of variables to configure ec2 instances to be VPN servers. I need one EC2 per availability zone in a region, one EIP per EC2 instance, and 2 nic per subnet in the availability zone attached to the corresponding EC2 instance.

I'm currently struggling to build a local list that contains one element per AZ with a list of subnets based on the way I'm grouping by subnets

Code

subnets_outputs.tf

output "subnets_by_az" {
  value = { for subnet in data.aws_subnet.env_defaults : subnet.availability_zone => subnet... }
}

Example Outputs

module.defaults.subnets_by_az["us-east-2b"][0]
{
  "arn" = "arn:aws:ec2:us-east-2:{some_account}:subnet/subnet-{some_id}"
  # Leaving most of this out for brevity
  "id" = "subnet-{some_id}"
  "vpc_id" = "vpc-{some_vpc_id}"
}
module.defaults.subnets_by_az
{
  "us-east-2a" = [
    {
      "arn" = "arn:aws:ec2:us-east-2:{some_account}:subnet/subnet-{some_id}"
      # Leaving most of this out for brevity
      "id" = "subnet-{some_id}"
      "vpc_id" = "vpc-{some_vpc_id}"
    },
    {
      "arn" = "arn:aws:ec2:us-east-2:{some_account}:subnet/subnet-{some_id}"
      # Leaving most of this out for brevity
      "id" = "subnet-{some_id}"
      "vpc_id" = "vpc-{some_vpc_id}"
    }
  ]
  "us-east-2b" = [
    {
      "arn" = "arn:aws:ec2:us-east-2:{some_account}:subnet/subnet-{some_id}"
      # Leaving most of this out for brevity
      "id" = "subnet-{some_id}"
      "vpc_id" = "vpc-{some_vpc_id}"
    },
    # ...
  ]

]

Desired Result

[
  {
    "vpc_id" = "{vpc_id}"
    "subnets" = ["{subnet_id}", "{subnet_id}"]
    "availability_zone" = "us-east-2b"
  }
  # ...

The part I don't understand how to do is how do I get a flattened list

Further Example

I kind of want to be able to group by az in the following example which I know can be done with the ... operator in the first example but I'm not sure how to apply the operator when building an object in a way that flattens each value into sublists.

flatten([for az in module.defaults.subnets_by_az: [for subnet in az: { subnet_id = subnet.id, vpc_id = subnet.vpc_id, az = subnet.availability_zone}]])
[
  {
    "az" = "us-east-2a"
    "subnet_id" = "subnet-{id}"
    "vpc_id" = "vpc-{id}"
  },
  {
    "az" = "us-east-2a"
    "subnet_id" = "subnet-{id}"
    "vpc_id" = "vpc-{id}"
  },
  {
    "az" = "us-east-2b"
    "subnet_id" = "subnet-{id}"
    "vpc_id" = "vpc-{id}"
  },
  {
    "az" = "us-east-2b"
    "subnet_id" = "subnet-{id}"
    "vpc_id" = "vpc-{id}"
  },
]
1

There are 1 answers

0
AlexLordThorsen On

After toying around in the console some more I remembered the * operator and ended up building

{for key, az in module.defaults.subnets_by_az: key => {"az" = key, subnets = az[*].id, "vpc_id" = distinct(az[*].vpc_id)}}
{
  "us-east-2a" = {
    "az" = "us-east-2a"
    "subnets" = [
      "subnet-{id}",
      "subnet-{id}",
    ]
    "vpc_id" = tolist([
      "vpc-{id}",
    ])
  }
  "us-east-2b" = {
    "az" = "us-east-2b"
    "subnets" = [
      "subnet-{id}",
      "subnet-{id}",
    ]
    "vpc_id" = tolist([
      "vpc-{id}",
    ])
  }
}