Using for_each with provider setting
Asked Answered
Z

2

9

I try to create VPCs in different regions for doing this I have multiple providers set up that I have given the alias equal to its region. The VPCs is set up with a for_each where the each.key is the region I want to spin up the VPC in. The issue I have is that i can't find a way to use the each.key with the "aws." prefix needed for the provider setting for the resource.

This is what I try to do:

provider "aws" {
  alias = "eu-west-1"
  profile = "Terraform"
  region = "eu-west-1"
}
provider "aws" {
  alias = "eu-west-2"
  profile = "Terraform"
  region = "eu-west-2"
}

locals {
  pools = {
    "eu-west-1" = "${data.aws_vpc_ipam_pool.pooleu-west-1.id}"
    "eu-west-2" = "${data.aws_vpc_ipam_pool.pooleu-west-2.id}"
  }
}

resource "aws_vpc" "default" {
  for_each = local.pools
  provider = aws.${each.key}
  ipv4_ipam_pool_id = each.value
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "main-vpc-${each.key}"
  }
}

Can this be done or should I try to find another solution? I cant find any answers to this and I am to under experienced with terraform to know this.

Zielsdorf answered 8/6, 2022 at 7:23 Comment(0)
Z
12

After a lot of resource I have found this thread on the topic and it's not possible (yet and maybe never) to assign the provider dynamically...

You can read more here: https://github.com/hashicorp/terraform/issues/24476

Zielsdorf answered 8/6, 2022 at 9:28 Comment(0)
R
0

If you throw out the requirement of immediate convergence and allow eventual consistency (i.e. keep running terraform apply until it becomes a no-op), a lot of the places where Terraform is annoying become much more manageable.

For example to solve this case you should be able to use local_file to have your Terraform config generate itself.

NOTE: this has the issue that if the local version of generated files are out of date, this could try to delete some resource on the first invocation. Making sure that the first invocation always only --targets the generation would be advisable.

locals {
  regions = toset([
    "us-east-1",
    "us-east-2",
    "us-west-1",
    "us-west-2",
  ])
}

resource "local_file" "per_region_mod" {
  for_each = local.regions
  filename = "./region.${each.key}.tf"
  file_permission = "0600"
  content  = <<EOT
provider "aws" {
  alias = "${each.key}"
  region = "${each.key}"
}

module "region-${each.key}" {
  providers = { aws = aws.${each.key} }
  // ...
}
EOF
}

NOT tested... yet.

Ripe answered 12/3 at 21:37 Comment(2)
Creative but also complicated and not as clean as being able to assign provider dynamically. But that do not work so...Zielsdorf
@ErikAsplund Having to work around this sort of thing is par for the course. The Go language (IIRC TF is written in Go) seems to attract people who expect user requirements to adapt to their solution's ideology so this lack of support doesn't surprise me. I know of at least two more cases of that in TF and an epic FUBAR re Go's intentional non-implementation of oneof in proto-buffs. If TF wasn't so handy for the other 99% I'd just abandon it rather than hack around it in that 1%.Ripe

© 2022 - 2024 — McMap. All rights reserved.